From 0b64d43702cbdfa3b7e16dc3f9bc074cbc90658d Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 25 Mar 2015 20:57:54 +0000 Subject: [PATCH] MFC r279361, r279395, r279396: Allow the kern.osrelease and kern.osreldate sysctl values to be set in a jail's creation parameters. This allows the kernel version to be reliably spoofed within the jail whether examined directly with sysctl or indirectly with the uname -r and -K options. Export the new osreldate and osrelease jail parms in jail_get(2). Fix line wrap. git-svn-id: svn://svn.freebsd.org/base/stable/10@280632 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/kern/imgact_elf.c | 4 ++- sys/kern/init_main.c | 2 +- sys/kern/kern_jail.c | 78 +++++++++++++++++++++++++++++++++++++++++-- sys/kern/kern_mib.c | 52 +++++++++++++++++++++++------ sys/sys/jail.h | 6 +++- usr.sbin/jail/jail.8 | 12 +++++-- 6 files changed, 137 insertions(+), 17 deletions(-) diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index 940b38f9d..e41ad7668 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -996,7 +997,8 @@ __elfN(freebsd_fixup)(register_t **stack_base, struct image_params *imgp) AUXARGS_ENTRY(pos, AT_BASE, args->base); if (imgp->execpathp != 0) AUXARGS_ENTRY(pos, AT_EXECPATH, imgp->execpathp); - AUXARGS_ENTRY(pos, AT_OSRELDATE, osreldate); + AUXARGS_ENTRY(pos, AT_OSRELDATE, + imgp->proc->p_ucred->cr_prison->pr_osreldate); if (imgp->canary != 0) { AUXARGS_ENTRY(pos, AT_CANARY, imgp->canary); AUXARGS_ENTRY(pos, AT_CANARYLEN, imgp->canarylen); diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 16235bc5c..1c5f77cbb 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -493,7 +493,7 @@ proc0_init(void *dummy __unused) td->td_flags = TDF_INMEM; td->td_pflags = TDP_KTHREAD; td->td_cpuset = cpuset_thread0(); - prison0.pr_cpuset = cpuset_ref(td->td_cpuset); + prison0_init(); p->p_peers = 0; p->p_leader = p; p->p_reaper = p; diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index 54ca3ff5b..e9c71caad 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -238,6 +238,19 @@ static int jail_default_devfs_rsnum = JAIL_DEFAULT_DEVFS_RSNUM; static unsigned jail_max_af_ips = 255; #endif +/* + * Initialize the parts of prison0 that can't be static-initialized with + * constants. This is called from proc0_init() after creating thread0 cpuset. + */ +void +prison0_init(void) +{ + + prison0.pr_cpuset = cpuset_ref(thread0.td_cpuset); + prison0.pr_osreldate = osreldate; + strlcpy(prison0.pr_osrelease, osrelease, sizeof(prison0.pr_osrelease)); +} + #ifdef INET static int qcmp_v4(const void *ip1, const void *ip2) @@ -537,7 +550,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) struct prison *pr, *deadpr, *mypr, *ppr, *tpr; struct vnode *root; char *domain, *errmsg, *host, *name, *namelc, *p, *path, *uuid; - char *g_path; + char *g_path, *osrelstr; #if defined(INET) || defined(INET6) struct prison *tppr; void *op; @@ -547,7 +560,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) int created, cuflags, descend, enforce, error, errmsg_len, errmsg_pos; int gotchildmax, gotenforce, gothid, gotrsnum, gotslevel; int fi, jid, jsys, len, level; - int childmax, rsnum, slevel; + int childmax, osreldt, rsnum, slevel; int fullpath_disabled; #if defined(INET) || defined(INET6) int ii, ij; @@ -962,6 +975,46 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) } } + error = vfs_getopt(opts, "osrelease", (void **)&osrelstr, &len); + if (error == ENOENT) + osrelstr = NULL; + else if (error != 0) + goto done_free; + else { + if (flags & JAIL_UPDATE) { + error = EINVAL; + vfs_opterror(opts, + "osrelease cannot be changed after creation"); + goto done_errmsg; + } + if (len == 0 || len >= OSRELEASELEN) { + error = EINVAL; + vfs_opterror(opts, + "osrelease string must be 1-%d bytes long", + OSRELEASELEN - 1); + goto done_errmsg; + } + } + + error = vfs_copyopt(opts, "osreldate", &osreldt, sizeof(osreldt)); + if (error == ENOENT) + osreldt = 0; + else if (error != 0) + goto done_free; + else { + if (flags & JAIL_UPDATE) { + error = EINVAL; + vfs_opterror(opts, + "osreldate cannot be changed after creation"); + goto done_errmsg; + } + if (osreldt == 0) { + error = EINVAL; + vfs_opterror(opts, "osreldate cannot be 0"); + goto done_errmsg; + } + } + /* * Grab the allprison lock before letting modules check their * parameters. Once we have it, do not let go so we'll have a @@ -1290,6 +1343,12 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) pr->pr_enforce_statfs = JAIL_DEFAULT_ENFORCE_STATFS; pr->pr_devfs_rsnum = ppr->pr_devfs_rsnum; + pr->pr_osreldate = osreldt ? osreldt : ppr->pr_osreldate; + if (osrelstr == NULL) + strcpy(pr->pr_osrelease, ppr->pr_osrelease); + else + strcpy(pr->pr_osrelease, osrelstr); + LIST_INIT(&pr->pr_children); mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF | MTX_DUPOK); @@ -2124,6 +2183,13 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags) goto done_deref; i = !i; error = vfs_setopt(opts, "nodying", &i, sizeof(i)); + if (error != 0 && error != ENOENT) + goto done_deref; + error = vfs_setopt(opts, "osreldate", &pr->pr_osreldate, + sizeof(pr->pr_osreldate)); + if (error != 0 && error != ENOENT) + goto done_deref; + error = vfs_setopts(opts, "osrelease", pr->pr_osrelease); if (error != 0 && error != ENOENT) goto done_deref; @@ -4321,12 +4387,20 @@ sysctl_jail_param(SYSCTL_HANDLER_ARGS) return (0); } +/* + * CTLFLAG_RDTUN in the following indicates jail parameters that can be set at + * jail creation time but cannot be changed in an existing jail. + */ SYSCTL_JAIL_PARAM(, jid, CTLTYPE_INT | CTLFLAG_RDTUN, "I", "Jail ID"); SYSCTL_JAIL_PARAM(, parent, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail parent ID"); SYSCTL_JAIL_PARAM_STRING(, name, CTLFLAG_RW, MAXHOSTNAMELEN, "Jail name"); SYSCTL_JAIL_PARAM_STRING(, path, CTLFLAG_RDTUN, MAXPATHLEN, "Jail root path"); SYSCTL_JAIL_PARAM(, securelevel, CTLTYPE_INT | CTLFLAG_RW, "I", "Jail secure level"); +SYSCTL_JAIL_PARAM(, osreldate, CTLTYPE_INT | CTLFLAG_RDTUN, "I", + "Jail value for kern.osreldate and uname -K"); +SYSCTL_JAIL_PARAM_STRING(, osrelease, CTLFLAG_RDTUN, OSRELEASELEN, + "Jail value for kern.osrelease and uname -r"); SYSCTL_JAIL_PARAM(, enforce_statfs, CTLTYPE_INT | CTLFLAG_RW, "I", "Jail cannot see all mounted file systems"); SYSCTL_JAIL_PARAM(, devfs_ruleset, CTLTYPE_INT | CTLFLAG_RW, diff --git a/sys/kern/kern_mib.c b/sys/kern/kern_mib.c index 6f7d0467d..030779138 100644 --- a/sys/kern/kern_mib.c +++ b/sys/kern/kern_mib.c @@ -90,9 +90,6 @@ SYSCTL_ROOT_NODE(OID_AUTO, regression, CTLFLAG_RW, 0, SYSCTL_STRING(_kern, OID_AUTO, ident, CTLFLAG_RD|CTLFLAG_MPSAFE, kern_ident, 0, "Kernel identifier"); -SYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease, CTLFLAG_RD|CTLFLAG_MPSAFE| - CTLFLAG_CAPRD, osrelease, 0, "Operating system release"); - SYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD|CTLFLAG_CAPRD, SYSCTL_NULL_INT_PTR, BSD, "Operating system revision"); @@ -105,13 +102,6 @@ SYSCTL_STRING(_kern, OID_AUTO, compiler_version, CTLFLAG_RD|CTLFLAG_MPSAFE, SYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD|CTLFLAG_MPSAFE| CTLFLAG_CAPRD, ostype, 0, "Operating system type"); -/* - * NOTICE: The *userland* release date is available in - * /usr/include/osreldate.h - */ -SYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD|CTLFLAG_CAPRD, - &osreldate, 0, "Kernel release date"); - SYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RDTUN, &maxproc, 0, "Maximum number of processes"); @@ -429,6 +419,48 @@ SYSCTL_PROC(_kern, KERN_HOSTID, hostid, CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE, NULL, 0, sysctl_hostid, "LU", "Host ID"); +/* + * The osrelease string is copied from the global (osrelease in vers.c) into + * prison0 by a sysinit and is inherited by child jails if not changed at jail + * creation, so we always return the copy from the current prison data. + */ +static int +sysctl_osrelease(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + + pr = req->td->td_ucred->cr_prison; + return (SYSCTL_OUT(req, pr->pr_osrelease, strlen(pr->pr_osrelease) + 1)); + +} + +SYSCTL_PROC(_kern, KERN_OSRELEASE, osrelease, + CTLTYPE_STRING | CTLFLAG_CAPRD | CTLFLAG_RD | CTLFLAG_MPSAFE, + NULL, 0, sysctl_osrelease, "A", "Operating system release"); + +/* + * The osreldate number is copied from the global (osreldate in vers.c) into + * prison0 by a sysinit and is inherited by child jails if not changed at jail + * creation, so we always return the value from the current prison data. + */ +static int +sysctl_osreldate(SYSCTL_HANDLER_ARGS) +{ + struct prison *pr; + + pr = req->td->td_ucred->cr_prison; + return (SYSCTL_OUT(req, &pr->pr_osreldate, sizeof(pr->pr_osreldate))); + +} + +/* + * NOTICE: The *userland* release date is available in + * /usr/include/osreldate.h + */ +SYSCTL_PROC(_kern, KERN_OSRELDATE, osreldate, + CTLTYPE_INT | CTLFLAG_CAPRD | CTLFLAG_RD | CTLFLAG_MPSAFE, + NULL, 0, sysctl_osreldate, "I", "Kernel release date"); + SYSCTL_NODE(_kern, OID_AUTO, features, CTLFLAG_RD, 0, "Kernel Features"); #ifdef COMPAT_FREEBSD4 diff --git a/sys/sys/jail.h b/sys/sys/jail.h index 08b5f4bdb..cfe71d8f2 100644 --- a/sys/sys/jail.h +++ b/sys/sys/jail.h @@ -134,6 +134,7 @@ MALLOC_DECLARE(M_PRISON); #include #define HOSTUUIDLEN 64 +#define OSRELEASELEN 32 struct racct; struct prison_racct; @@ -177,13 +178,15 @@ struct prison { int pr_securelevel; /* (p) securelevel */ int pr_enforce_statfs; /* (p) statfs permission */ int pr_devfs_rsnum; /* (p) devfs ruleset */ - int pr_spare[4]; + int pr_spare[3]; + int pr_osreldate; /* (c) kern.osreldate value */ unsigned long pr_hostid; /* (p) jail hostid */ char pr_name[MAXHOSTNAMELEN]; /* (p) admin jail name */ char pr_path[MAXPATHLEN]; /* (c) chroot path */ char pr_hostname[MAXHOSTNAMELEN]; /* (p) jail hostname */ char pr_domainname[MAXHOSTNAMELEN]; /* (p) jail domainname */ char pr_hostuuid[HOSTUUIDLEN]; /* (p) jail hostuuid */ + char pr_osrelease[OSRELEASELEN]; /* (c) kern.osrelease value */ }; struct prison_racct { @@ -364,6 +367,7 @@ void getcredhostname(struct ucred *, char *, size_t); void getcreddomainname(struct ucred *, char *, size_t); void getcredhostuuid(struct ucred *, char *, size_t); void getcredhostid(struct ucred *, unsigned long *); +void prison0_init(void); int prison_allow(struct ucred *, unsigned); int prison_check(struct ucred *cred1, struct ucred *cred2); int prison_owns_vnet(struct ucred *); diff --git a/usr.sbin/jail/jail.8 b/usr.sbin/jail/jail.8 index b270a1548..83666ab7d 100644 --- a/usr.sbin/jail/jail.8 +++ b/usr.sbin/jail/jail.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 6, 2015 +.Dd February 25, 2015 .Dt JAIL 8 .Os .Sh NAME @@ -276,7 +276,7 @@ Then there are pseudo-parameters that are only used by .Nm itself. .Pp -Jails have a set a core parameters, and kernel modules can add their own +Jails have a set of core parameters, and kernel modules can add their own jail parameters. The current set of available parameters can be retrieved via .Dq Nm sysctl Fl d Va security.jail.param . @@ -471,6 +471,14 @@ The .Va jid of the parent of this jail, or zero if this is a top-level jail (read-only). +.It Va osrelease +The string for the jail's +.Va kern.osrelease +sysctl and uname -r. +.It Va osreldate +The number for the jail's +.Va kern.osreldate +and uname -K. .It Va allow.* Some restrictions of the jail environment may be set on a per-jail basis. -- 2.45.0