Index: sys/kern/kern_jail.c =================================================================== --- sys/kern/kern_jail.c +++ sys/kern/kern_jail.c @@ -99,22 +99,23 @@ /* prison0 describes what is "real" about the system. */ struct prison prison0 = { - .pr_id = 0, - .pr_name = "0", - .pr_ref = 1, - .pr_uref = 1, - .pr_path = "/", - .pr_securelevel = -1, - .pr_devfs_rsnum = 0, - .pr_childmax = JAIL_MAX, - .pr_hostuuid = DEFAULT_HOSTUUID, - .pr_children = LIST_HEAD_INITIALIZER(prison0.pr_children), + .pr_id = 0, + .pr_name = "0", + .pr_ref = 1, + .pr_uref = 1, + .pr_path = "/", + .pr_securelevel = -1, + .pr_suser_enabled = 1, + .pr_devfs_rsnum = 0, + .pr_childmax = JAIL_MAX, + .pr_hostuuid = DEFAULT_HOSTUUID, + .pr_children = LIST_HEAD_INITIALIZER(prison0.pr_children), #ifdef VIMAGE - .pr_flags = PR_HOST|PR_VNET|_PR_IP_SADDRSEL, + .pr_flags = PR_HOST|PR_VNET|_PR_IP_SADDRSEL, #else - .pr_flags = PR_HOST|_PR_IP_SADDRSEL, + .pr_flags = PR_HOST|_PR_IP_SADDRSEL, #endif - .pr_allow = PR_ALLOW_ALL_STATIC, + .pr_allow = PR_ALLOW_ALL_STATIC, }; MTX_SYSINIT(prison0, &prison0.pr_mtx, "jail mutex", MTX_DEF); @@ -518,8 +519,8 @@ size_t namelen, onamelen, pnamelen; int born, created, cuflags, descend, enforce; int error, errmsg_len, errmsg_pos; - int gotchildmax, gotenforce, gothid, gotrsnum, gotslevel; - int jid, jsys, len, level; + int gotchildmax, gotenforce, gothid, gotrsnum, gotslevel, gotsuser; + int jid, jsys, len, level, suser; int childmax, osreldt, rsnum, slevel; #if defined(INET) || defined(INET6) int ii, ij; @@ -588,6 +589,14 @@ else gotslevel = 1; + error = vfs_copyopt(opts, "suser_enabled", &suser, sizeof(suser)); + if (error == ENOENT) + gotsuser = 0; + else if (error != 0) + goto done_free; + else + gotsuser = 1; + error = vfs_copyopt(opts, "children.max", &childmax, sizeof(childmax)); if (error == ENOENT) @@ -1270,6 +1279,7 @@ pr->pr_flags |= _PR_IP_SADDRSEL; pr->pr_securelevel = ppr->pr_securelevel; + pr->pr_suser_enabled = ppr->pr_suser_enabled; pr->pr_allow = JAIL_DEFAULT_ALLOW & ppr->pr_allow; pr->pr_enforce_statfs = jail_default_enforce_statfs; pr->pr_devfs_rsnum = ppr->pr_devfs_rsnum; @@ -1348,6 +1358,12 @@ goto done_deref_locked; } } + if (gotsuser) { + if (suser > ppr->pr_suser_enabled) { + error = EPERM; + goto done_deref_locked; + } + } if (gotchildmax) { if (childmax >= ppr->pr_childmax) { error = EPERM; @@ -1637,6 +1653,13 @@ if (tpr->pr_securelevel < slevel) tpr->pr_securelevel = slevel; } + if (gotsuser) { + pr->pr_suser_enabled = suser; + /* Pass this restriction on to the children. */ + FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) + if (tpr->pr_suser_enabled != suser) + tpr->pr_suser_enabled = suser; + } if (gotchildmax) { pr->pr_childmax = childmax; /* Set all child jails to under this limit. */ @@ -2070,6 +2093,10 @@ sizeof(pr->pr_securelevel)); if (error != 0 && error != ENOENT) goto done_deref; + error = vfs_setopt(opts, "suser_enabled", &pr->pr_suser_enabled, + sizeof(pr->pr_suser_enabled)); + if (error != 0 && error != ENOENT) + goto done_deref; error = vfs_setopt(opts, "children.cur", &pr->pr_childcount, sizeof(pr->pr_childcount)); if (error != 0 && error != ENOENT) @@ -3739,6 +3766,8 @@ 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(, suser_enabled, CTLTYPE_INT | CTLFLAG_RW, + "I", "Process in jail with uid 0 have privilege"); 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, @@ -4171,6 +4200,7 @@ #endif db_printf(" root = %p\n", pr->pr_root); db_printf(" securelevel = %d\n", pr->pr_securelevel); + db_printf(" suser_enabled = %d\n", pr->pr_suser_enabled); db_printf(" devfs_rsnum = %d\n", pr->pr_devfs_rsnum); db_printf(" children.max = %d\n", pr->pr_childmax); db_printf(" children.cur = %d\n", pr->pr_childcount); Index: sys/kern/kern_priv.c =================================================================== --- sys/kern/kern_priv.c +++ sys/kern/kern_priv.c @@ -71,6 +71,16 @@ SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__ok, "int"); SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__err, "int"); +static bool +priv_jail_suser_enabled(struct ucred *cred) +{ + + if (!jailed(cred)) + return (true); + + return (cred->cr_prison->pr_suser_enabled == 1); +} + static __always_inline int priv_check_cred_pre(struct ucred *cred, int priv) { @@ -186,7 +196,7 @@ * superuser policy to be globally disabled, although this is * currenty of limited utility. */ - if (suser_enabled) { + if (suser_enabled && priv_jail_suser_enabled(cred)) { switch (priv) { case PRIV_MAXFILES: case PRIV_MAXPROC: Index: sys/sys/jail.h =================================================================== --- sys/sys/jail.h +++ sys/sys/jail.h @@ -179,6 +179,7 @@ int pr_childmax; /* (p) maximum child jails */ unsigned pr_allow; /* (p) PR_ALLOW_* flags */ int pr_securelevel; /* (p) securelevel */ + int pr_suser_enabled; /* (c) suser enabled */ int pr_enforce_statfs; /* (p) statfs permission */ int pr_devfs_rsnum; /* (p) devfs ruleset */ int pr_spare[3]; Index: usr.sbin/jail/config.c =================================================================== --- usr.sbin/jail/config.c +++ usr.sbin/jail/config.c @@ -120,6 +120,7 @@ [KP_PATH] = {"path", 0}, [KP_PERSIST] = {"persist", 0}, [KP_SECURELEVEL] = {"securelevel", 0}, + [KP_SUSER_ENABLED] = {"suser_enabled", 0}, [KP_VNET] = {"vnet", 0}, }; Index: usr.sbin/jail/jail.8 =================================================================== --- usr.sbin/jail/jail.8 +++ usr.sbin/jail/jail.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 14, 2020 +.Dd November 6, 2020 .Dt JAIL 8 .Os .Sh NAME @@ -413,6 +413,12 @@ setting this parameter it may have a higher one. If the system securelevel is changed, any jail securelevels will be at least as secure. +.It Va suser_enable +The value of the jail's +.Va security.bsd.suser_enabled +sysctl. +The suser_enabled will be disabled automatically if its parent system has it +disabled. .It Va devfs_ruleset The number of the devfs ruleset that is enforced for mounting devfs in this jail. Index: usr.sbin/jail/jailp.h =================================================================== --- usr.sbin/jail/jailp.h +++ usr.sbin/jail/jailp.h @@ -135,6 +135,7 @@ KP_PATH, KP_PERSIST, KP_SECURELEVEL, + KP_SUSER_ENABLED, KP_VNET, IP_NPARAM };