From owner-svn-src-head@FreeBSD.ORG Fri Feb 27 16:28:57 2015 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id ABCE27A6; Fri, 27 Feb 2015 16:28:57 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 9537C14D; Fri, 27 Feb 2015 16:28:57 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t1RGSv6f067488; Fri, 27 Feb 2015 16:28:57 GMT (envelope-from ian@FreeBSD.org) Received: (from ian@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t1RGSurE067472; Fri, 27 Feb 2015 16:28:56 GMT (envelope-from ian@FreeBSD.org) Message-Id: <201502271628.t1RGSurE067472@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: ian set sender to ian@FreeBSD.org using -f From: Ian Lepore Date: Fri, 27 Feb 2015 16:28:56 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r279361 - in head: sys/kern sys/sys usr.sbin/jail X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 27 Feb 2015 16:28:57 -0000 Author: ian Date: Fri Feb 27 16:28:55 2015 New Revision: 279361 URL: https://svnweb.freebsd.org/changeset/base/279361 Log: 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. The values can only be set at jail creation time, to eliminate the need for any locking when accessing the values via sysctl. The overridden values are inherited by nested jails (unless the config for the nested jails also overrides the values). There is no sanity or range checking, other than disallowing an empty release string or a zero release date, by design. The system administrator is trusted to set sane values. Setting values that are newer than the actual running kernel will likely cause compatibility problems. Differential Revision: https://reviews.freebsd.org/D1948 Relnotes: yes Modified: head/sys/kern/imgact_elf.c head/sys/kern/init_main.c head/sys/kern/kern_jail.c head/sys/kern/kern_mib.c head/sys/sys/jail.h head/usr.sbin/jail/jail.8 Modified: head/sys/kern/imgact_elf.c ============================================================================== --- head/sys/kern/imgact_elf.c Fri Feb 27 15:47:30 2015 (r279360) +++ head/sys/kern/imgact_elf.c Fri Feb 27 16:28:55 2015 (r279361) @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -1007,7 +1008,8 @@ __elfN(freebsd_fixup)(register_t **stack 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); Modified: head/sys/kern/init_main.c ============================================================================== --- head/sys/kern/init_main.c Fri Feb 27 15:47:30 2015 (r279360) +++ head/sys/kern/init_main.c Fri Feb 27 16:28:55 2015 (r279361) @@ -494,7 +494,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; Modified: head/sys/kern/kern_jail.c ============================================================================== --- head/sys/kern/kern_jail.c Fri Feb 27 15:47:30 2015 (r279360) +++ head/sys/kern/kern_jail.c Fri Feb 27 16:28:55 2015 (r279361) @@ -239,6 +239,19 @@ static int jail_default_devfs_rsnum = JA 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) @@ -538,7 +551,7 @@ kern_jail_set(struct thread *td, struct 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; @@ -548,7 +561,7 @@ kern_jail_set(struct thread *td, struct 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; @@ -959,6 +972,46 @@ kern_jail_set(struct thread *td, struct } } + 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 @@ -1285,6 +1338,12 @@ kern_jail_set(struct thread *td, struct 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); @@ -4303,12 +4362,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, Modified: head/sys/kern/kern_mib.c ============================================================================== --- head/sys/kern/kern_mib.c Fri Feb 27 15:47:30 2015 (r279360) +++ head/sys/kern/kern_mib.c Fri Feb 27 16:28:55 2015 (r279361) @@ -90,9 +90,6 @@ SYSCTL_ROOT_NODE(OID_AUTO, regression, C 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_ 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 | CTLFLAG_NOFETCH, &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 Modified: head/sys/sys/jail.h ============================================================================== --- head/sys/sys/jail.h Fri Feb 27 15:47:30 2015 (r279360) +++ head/sys/sys/jail.h Fri Feb 27 16:28:55 2015 (r279361) @@ -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 { @@ -362,6 +365,7 @@ void getcredhostname(struct ucred *, cha 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 *); Modified: head/usr.sbin/jail/jail.8 ============================================================================== --- head/usr.sbin/jail/jail.8 Fri Feb 27 15:47:30 2015 (r279360) +++ head/usr.sbin/jail/jail.8 Fri Feb 27 16:28:55 2015 (r279361) @@ -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 ar .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.