From 274ea197bb2f446e42dd6f17d5046b348d26d82d Mon Sep 17 00:00:00 2001 From: jamie Date: Sat, 25 Jul 2009 14:48:57 +0000 Subject: Some jail parameters (in particular, "ip4" and "ip6" for IP address restrictions) were found to be inadequately described by a boolean. Define a new parameter type with three values (disable, new, inherit) to handle these and future cases. Approved by: re (kib), bz (mentor) Discussed with: rwatson --- lib/libjail/jail.c | 148 +++++++++++++++++++++++++------------------ lib/libjail/jail.h | 1 + sys/compat/linux/linux_mib.c | 78 +++++++++++++---------- sys/kern/kern_jail.c | 120 +++++++++++++++++++++++++---------- sys/sys/jail.h | 24 +++++-- usr.sbin/jail/jail.8 | 40 ++++++++---- usr.sbin/jls/jls.c | 31 ++++----- 7 files changed, 277 insertions(+), 165 deletions(-) diff --git a/lib/libjail/jail.c b/lib/libjail/jail.c index 621b5b5..9411b88 100644 --- a/lib/libjail/jail.c +++ b/lib/libjail/jail.c @@ -54,6 +54,8 @@ __FBSDID("$FreeBSD$"); #define ARRAY_SLOP 5 +static int jailparam_import_enum(const char **values, int nvalues, + const char *valstr, size_t valsize, int *value); static int jailparam_vlist(struct jailparam **jpp, va_list ap); static int jailparam_type(struct jailparam *jp); static char *noname(const char *name); @@ -61,6 +63,9 @@ static char *nononame(const char *name); char jail_errmsg[JAIL_ERRMSGLEN]; +static const char *bool_values[] = { "false", "true" }; +static const char *jailsys_values[] = { "disable", "new", "inherit" }; + /* * Import a null-terminated parameter list and set a jail with the flags @@ -140,7 +145,6 @@ int jailparam_all(struct jailparam **jpp) { struct jailparam *jp; - char *nname; size_t mlen1, mlen2, buflen; int njp, nlist; int mib1[CTL_MAXNAME], mib2[CTL_MAXNAME - 2]; @@ -182,6 +186,8 @@ jailparam_all(struct jailparam **jpp) "sysctl(0.1): %s", strerror(errno)); goto error; } + if (buf[buflen - 2] == '.') + buf[buflen - 2] = '\0'; /* Add the parameter to the list */ if (njp >= nlist) { nlist *= 2; @@ -197,17 +203,6 @@ jailparam_all(struct jailparam **jpp) njp++; goto error; } - /* Convert nobool parameters to bool. */ - if (jp[njp].jp_flags & JP_NOBOOL) { - nname = nononame(jp[njp].jp_name); - if (nname == NULL) { - njp++; - goto error; - } - free(jp[njp].jp_name); - jp[njp].jp_name = nname; - jp[njp].jp_flags ^= JP_BOOL | JP_NOBOOL; - } mib1[1] = 2; } jp = realloc(jp, njp * sizeof(*jp)); @@ -285,14 +280,31 @@ jailparam_import(struct jailparam *jp, const char *value) switch (jp->jp_ctltype & CTLTYPE) { case CTLTYPE_INT: if (jp->jp_flags & (JP_BOOL | JP_NOBOOL)) { - if (!strncasecmp(avalue, "true", 4)) - ((int *)jp->jp_value)[i] = 1; - else if (!strncasecmp(avalue, "false", 5)) - ((int *)jp->jp_value)[i] = 0; - else { + if (!jailparam_import_enum(bool_values, 2, + avalue, fw, &((int *)jp->jp_value)[i])) { snprintf(jail_errmsg, - JAIL_ERRMSGLEN, - "%s: unknown boolean value \"%.*s\"", + JAIL_ERRMSGLEN, "%s: " + "unknown boolean value \"%.*s\"", + jp->jp_name, fw, avalue); + errno = EINVAL; + goto error; + } + break; + } + if (jp->jp_flags & JP_JAILSYS) { + /* + * Allow setting a jailsys parameter to "new" + * in a booleanesque fashion. + */ + if (value[0] == '\0') + ((int *)jp->jp_value)[i] = JAIL_SYS_NEW; + else if (!jailparam_import_enum(jailsys_values, + sizeof(jailsys_values) / + sizeof(jailsys_values[0]), avalue, fw, + &((int *)jp->jp_value)[i])) { + snprintf(jail_errmsg, + JAIL_ERRMSGLEN, "%s: " + "unknown jailsys value \"%.*s\"", jp->jp_name, fw, avalue); errno = EINVAL; goto error; @@ -373,6 +385,23 @@ jailparam_import(struct jailparam *jp, const char *value) return (-1); } +static int +jailparam_import_enum(const char **values, int nvalues, const char *valstr, + size_t valsize, int *value) +{ + char *ep; + int i; + + for (i = 0; i < nvalues; i++) + if (valsize == strlen(values[i]) && + !strncasecmp(valstr, values[i], valsize)) { + *value = i; + return 1; + } + *value = strtol(valstr, &ep, 10); + return (ep == valstr + valsize); +} + /* * Put a name and value into a jail parameter element, copying the value * but not altering it. @@ -428,6 +457,15 @@ jailparam_set(struct jailparam *jp, unsigned njp, int flags) } } else { + /* + * Try to fill in missing values with an empty string. + */ + if (jp[j].jp_value == NULL && jp[j].jp_valuelen > 0 && + jailparam_import(jp + j, "") < 0) { + njp = j; + jid = -1; + goto done; + } jiov[i].iov_base = jp[j].jp_value; jiov[i].iov_len = (jp[j].jp_ctltype & CTLTYPE) == CTLTYPE_STRING @@ -632,7 +670,7 @@ jailparam_export(struct jailparam *jp) { char *value, *tvalue, **values; size_t valuelen; - int i, nval; + int i, nval, ival; char valbuf[INET6_ADDRSTRLEN]; if (!jp->jp_ctltype && jailparam_type(jp) < 0) @@ -655,14 +693,21 @@ jailparam_export(struct jailparam *jp) for (i = 0; i < nval; i++) { switch (jp->jp_ctltype & CTLTYPE) { case CTLTYPE_INT: - if (jp->jp_flags & (JP_BOOL | JP_NOBOOL)) { - strlcpy(valbuf, - ((int *)jp->jp_value)[i] ? "true" : "false", + ival = ((int *)jp->jp_value)[i]; + if ((jp->jp_flags & (JP_BOOL | JP_NOBOOL)) && + (unsigned)ival < 2) { + strlcpy(valbuf, bool_values[ival], + sizeof(valbuf)); + break; + } + if ((jp->jp_flags & JP_JAILSYS) && + (unsigned)ival < sizeof(jailsys_values) / + sizeof(jailsys_values[0])) { + strlcpy(valbuf, jailsys_values[ival], sizeof(valbuf)); break; } - snprintf(valbuf, sizeof(valbuf), "%d", - ((int *)jp->jp_value)[i]); + snprintf(valbuf, sizeof(valbuf), "%d", ival); break; case CTLTYPE_UINT: snprintf(valbuf, sizeof(valbuf), "%u", @@ -688,7 +733,7 @@ jailparam_export(struct jailparam *jp) valbuf, sizeof(valbuf)) == NULL) { strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); - + return (NULL); } break; @@ -698,7 +743,7 @@ jailparam_export(struct jailparam *jp) valbuf, sizeof(valbuf)) == NULL) { strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN); - + return (NULL); } break; @@ -846,11 +891,13 @@ jailparam_type(struct jailparam *jp) } } } + unknown_parameter: snprintf(jail_errmsg, JAIL_ERRMSGLEN, "unknown parameter: %s", jp->jp_name); errno = ENOENT; return (-1); } + mib_desc: mib[1] = 4; desclen = sizeof(desc); if (sysctl(mib, (miblen / sizeof(int)) + 2, &desc, &desclen, @@ -873,8 +920,9 @@ jailparam_type(struct jailparam *jp) switch (desc.i & CTLTYPE) { case CTLTYPE_INT: if (desc.s[0] == 'B') - jp->jp_flags |= - (desc.s[1] == 'N') ? JP_NOBOOL : JP_BOOL; + jp->jp_flags |= JP_BOOL; + else if (!strcmp(desc.s, "E,jailsys")) + jp->jp_flags |= JP_JAILSYS; case CTLTYPE_UINT: jp->jp_valuelen = sizeof(int); break; @@ -916,41 +964,21 @@ jailparam_type(struct jailparam *jp) } break; case CTLTYPE_NODE: - /* - * A node isn't normally a parameter, but may be a boolean - * if its "no" counterpart exists. - */ - nname = noname(jp->jp_name); - if (nname == NULL) - return (-1); - mib[1] = 3; - snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", nname); - free(nname); - miblen = sizeof(mib) - 2 * sizeof(int); - if (sysctl(mib, 2, mib + 2, &miblen, desc.s, - strlen(desc.s)) < 0) { - snprintf(jail_errmsg, JAIL_ERRMSGLEN, - "unknown parameter: %s", jp->jp_name); - return (-1); - } - mib[1] = 4; - desclen = sizeof(desc); - if (sysctl(mib, (miblen / sizeof(int)) + 2, &desc, &desclen, + /* A node might be described by an empty-named child. */ + mib[1] = 1; + mib[(miblen / sizeof(int)) + 2] = + mib[(miblen / sizeof(int)) + 1] - 1; + miblen += sizeof(int); + desclen = sizeof(desc.s); + if (sysctl(mib, (miblen / sizeof(int)) + 2, desc.s, &desclen, NULL, 0) < 0) { snprintf(jail_errmsg, JAIL_ERRMSGLEN, - "sysctl(0.4.%s): %s", desc.s, strerror(errno)); - return (-1); - } - if ((desc.i & CTLTYPE) != CTLTYPE_INT || desc.s[0] != 'B') { - snprintf(jail_errmsg, JAIL_ERRMSGLEN, - "unknown parameter: %s", jp->jp_name); - errno = ENOENT; + "sysctl(0.1): %s", strerror(errno)); return (-1); } - jp->jp_valuelen = sizeof(int); - jp->jp_ctltype = desc.i; - jp->jp_flags |= JP_BOOL; - break; + if (desc.s[desclen - 2] != '.') + goto unknown_parameter; + goto mib_desc; default: snprintf(jail_errmsg, JAIL_ERRMSGLEN, "unknown type for %s", jp->jp_name); diff --git a/lib/libjail/jail.h b/lib/libjail/jail.h index 4b38001..2801dbc 100644 --- a/lib/libjail/jail.h +++ b/lib/libjail/jail.h @@ -32,6 +32,7 @@ #define JP_RAWVALUE 0x01 #define JP_BOOL 0x02 #define JP_NOBOOL 0x04 +#define JP_JAILSYS 0x08 #define JAIL_ERRMSGLEN 1024 diff --git a/sys/compat/linux/linux_mib.c b/sys/compat/linux/linux_mib.c index 58af9c5..5e770f6 100644 --- a/sys/compat/linux/linux_mib.c +++ b/sys/compat/linux/linux_mib.c @@ -237,12 +237,14 @@ linux_prison_create(void *obj, void *data) { struct prison *pr = obj; struct vfsoptlist *opts = data; + int jsys; - if (vfs_flagopt(opts, "nolinux", NULL, 0)) + if (vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)) == 0 && + jsys == JAIL_SYS_INHERIT) return (0); /* * Inherit a prison's initial values from its parent - * (different from NULL which also inherits changes). + * (different from JAIL_SYS_INHERIT which also inherits changes). */ return linux_alloc_prison(pr, NULL); } @@ -252,11 +254,16 @@ linux_prison_check(void *obj __unused, void *data) { struct vfsoptlist *opts = data; char *osname, *osrelease; - int error, len, osrel, oss_version; + int error, jsys, len, osrel, oss_version; /* Check that the parameters are correct. */ - (void)vfs_flagopt(opts, "linux", NULL, 0); - (void)vfs_flagopt(opts, "nolinux", NULL, 0); + error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)); + if (error != ENOENT) { + if (error != 0) + return (error); + if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT) + return (EINVAL); + } error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len); if (error != ENOENT) { if (error != 0) @@ -296,33 +303,40 @@ linux_prison_set(void *obj, void *data) struct prison *pr = obj; struct vfsoptlist *opts = data; char *osname, *osrelease; - int error, gotversion, len, nolinux, oss_version, yeslinux; + int error, gotversion, jsys, len, oss_version; /* Set the parameters, which should be correct. */ - yeslinux = vfs_flagopt(opts, "linux", NULL, 0); - nolinux = vfs_flagopt(opts, "nolinux", NULL, 0); + error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)); + if (error == ENOENT) + jsys = -1; error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len); if (error == ENOENT) osname = NULL; else - yeslinux = 1; + jsys = JAIL_SYS_NEW; error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len); if (error == ENOENT) osrelease = NULL; else - yeslinux = 1; + jsys = JAIL_SYS_NEW; error = vfs_copyopt(opts, "linux.oss_version", &oss_version, sizeof(oss_version)); - gotversion = (error == 0); - yeslinux |= gotversion; - if (nolinux) { - /* "nolinux": inherit the parent's Linux info. */ + if (error == ENOENT) + gotversion = 0; + else { + gotversion = 1; + jsys = JAIL_SYS_NEW; + } + switch (jsys) { + case JAIL_SYS_INHERIT: + /* "linux=inherit": inherit the parent's Linux info. */ mtx_lock(&pr->pr_mtx); osd_jail_del(pr, linux_osd_jail_slot); mtx_unlock(&pr->pr_mtx); - } else if (yeslinux) { + break; + case JAIL_SYS_NEW: /* - * "linux" or "linux.*": + * "linux=new" or "linux.*": * the prison gets its own Linux info. */ error = linux_alloc_prison(pr, &lpr); @@ -348,9 +362,7 @@ linux_prison_set(void *obj, void *data) return (0); } -SYSCTL_JAIL_PARAM_NODE(linux, "Jail Linux parameters"); -SYSCTL_JAIL_PARAM(, nolinux, CTLTYPE_INT | CTLFLAG_RW, - "BN", "Jail w/ no Linux parameters"); +SYSCTL_JAIL_PARAM_SYS_NODE(linux, CTLFLAG_RW, "Jail Linux parameters"); SYSCTL_JAIL_PARAM_STRING(_linux, osname, CTLFLAG_RW, LINUX_MAX_UTSNAME, "Jail Linux kernel OS name"); SYSCTL_JAIL_PARAM_STRING(_linux, osrelease, CTLFLAG_RW, LINUX_MAX_UTSNAME, @@ -371,15 +383,22 @@ linux_prison_get(void *obj, void *data) /* See if this prison is the one with the Linux info. */ lpr = linux_find_prison(pr, &ppr); - i = (ppr == pr); + i = (ppr == pr) ? JAIL_SYS_NEW : JAIL_SYS_INHERIT; error = vfs_setopt(opts, "linux", &i, sizeof(i)); if (error != 0 && error != ENOENT) goto done; - i = !i; - error = vfs_setopt(opts, "nolinux", &i, sizeof(i)); - if (error != 0 && error != ENOENT) - goto done; if (i) { + error = vfs_setopts(opts, "linux.osname", lpr->pr_osname); + if (error != 0 && error != ENOENT) + goto done; + error = vfs_setopts(opts, "linux.osrelease", lpr->pr_osrelease); + if (error != 0 && error != ENOENT) + goto done; + error = vfs_setopt(opts, "linux.oss_version", + &lpr->pr_oss_version, sizeof(lpr->pr_oss_version)); + if (error != 0 && error != ENOENT) + goto done; + } else { /* * If this prison is inheriting its Linux info, report * empty/zero parameters. @@ -394,17 +413,6 @@ linux_prison_get(void *obj, void *data) sizeof(lpr->pr_oss_version)); if (error != 0 && error != ENOENT) goto done; - } else { - error = vfs_setopts(opts, "linux.osname", lpr->pr_osname); - if (error != 0 && error != ENOENT) - goto done; - error = vfs_setopts(opts, "linux.osrelease", lpr->pr_osrelease); - if (error != 0 && error != ENOENT) - goto done; - error = vfs_setopt(opts, "linux.oss_version", - &lpr->pr_oss_version, sizeof(lpr->pr_oss_version)); - if (error != 0 && error != ENOENT) - goto done; } error = 0; diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index 5c36758..6f6ae28 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -120,29 +120,26 @@ static int prison_restrict_ip6(struct prison *pr, struct in6_addr *newip6); */ static char *pr_flag_names[] = { [0] = "persist", - "host", -#ifdef INET - "ip4", -#endif -#ifdef INET6 - [3] = "ip6", -#endif -#ifdef VIMAGE - [4] = "vnet", -#endif }; static char *pr_flag_nonames[] = { [0] = "nopersist", - "nohost", +}; + +struct jailsys_flags { + const char *name; + unsigned disable; + unsigned new; +} pr_flag_jailsys[] = { + { "host", 0, PR_HOST }, +#ifdef VIMAGE + { "vnet", 0, PR_VNET }, +#endif #ifdef INET - "noip4", + { "ip4", PR_IP4_USER | PR_IP4_DISABLE, PR_IP4_USER }, #endif #ifdef INET6 - [3] = "noip6", -#endif -#ifdef VIMAGE - [4] = "novnet", + { "ip6", PR_IP6_USER | PR_IP6_DISABLE, PR_IP6_USER }, #endif }; @@ -478,7 +475,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) unsigned long hid; size_t namelen, onamelen; int created, cuflags, descend, enforce, error, errmsg_len, errmsg_pos; - int gotchildmax, gotenforce, gothid, gotslevel, fi, jid, len, level; + int gotchildmax, gotenforce, gothid, gotslevel; + int fi, jid, jsys, len, level; int childmax, slevel, vfslocked; #if defined(INET) || defined(INET6) int ii, ij; @@ -569,6 +567,34 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) vfs_flagopt(opts, pr_flag_nonames[fi], &ch_flags, 1 << fi); } ch_flags |= pr_flags; + for (fi = 0; fi < sizeof(pr_flag_jailsys) / sizeof(pr_flag_jailsys[0]); + fi++) { + error = vfs_copyopt(opts, pr_flag_jailsys[fi].name, &jsys, + sizeof(jsys)); + if (error == ENOENT) + continue; + if (error != 0) + goto done_free; + switch (jsys) { + case JAIL_SYS_DISABLE: + if (!pr_flag_jailsys[fi].disable) { + error = EINVAL; + goto done_free; + } + pr_flags |= pr_flag_jailsys[fi].disable; + break; + case JAIL_SYS_NEW: + pr_flags |= pr_flag_jailsys[fi].new; + break; + case JAIL_SYS_INHERIT: + break; + default: + error = EINVAL; + goto done_free; + } + ch_flags |= + pr_flag_jailsys[fi].new | pr_flag_jailsys[fi].disable; + } if ((flags & (JAIL_CREATE | JAIL_UPDATE | JAIL_ATTACH)) == JAIL_CREATE && !(pr_flags & PR_PERSIST)) { error = EINVAL; @@ -684,16 +710,18 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) #ifdef INET error = vfs_getopt(opts, "ip4.addr", &op, &ip4s); if (error == ENOENT) - ip4s = -1; + ip4s = (pr_flags & PR_IP4_DISABLE) ? 0 : -1; else if (error != 0) goto done_free; else if (ip4s & (sizeof(*ip4) - 1)) { error = EINVAL; goto done_free; } else { - ch_flags |= PR_IP4_USER; - pr_flags |= PR_IP4_USER; - if (ip4s > 0) { + ch_flags |= PR_IP4_USER | PR_IP4_DISABLE; + if (ip4s == 0) + pr_flags |= PR_IP4_USER | PR_IP4_DISABLE; + else { + pr_flags = (pr_flags & ~PR_IP4_DISABLE) | PR_IP4_USER; ip4s /= sizeof(*ip4); if (ip4s > jail_max_af_ips) { error = EINVAL; @@ -745,16 +773,18 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) #ifdef INET6 error = vfs_getopt(opts, "ip6.addr", &op, &ip6s); if (error == ENOENT) - ip6s = -1; + ip6s = (pr_flags & PR_IP6_DISABLE) ? 0 : -1; else if (error != 0) goto done_free; else if (ip6s & (sizeof(*ip6) - 1)) { error = EINVAL; goto done_free; } else { - ch_flags |= PR_IP6_USER; - pr_flags |= PR_IP6_USER; - if (ip6s > 0) { + ch_flags |= PR_IP6_USER | PR_IP6_DISABLE; + if (ip6s == 0) + pr_flags |= PR_IP6_USER | PR_IP6_DISABLE; + else { + pr_flags = (pr_flags & ~PR_IP6_DISABLE) | PR_IP6_USER; ip6s /= sizeof(*ip6); if (ip6s > jail_max_af_ips) { error = EINVAL; @@ -1968,6 +1998,19 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags) if (error != 0 && error != ENOENT) goto done_deref; } + for (fi = 0; fi < sizeof(pr_flag_jailsys) / sizeof(pr_flag_jailsys[0]); + fi++) { + i = pr->pr_flags & + (pr_flag_jailsys[fi].disable | pr_flag_jailsys[fi].new); + i = pr_flag_jailsys[fi].disable && + (i == pr_flag_jailsys[fi].disable) ? JAIL_SYS_DISABLE + : (i == pr_flag_jailsys[fi].new) ? JAIL_SYS_NEW + : JAIL_SYS_INHERIT; + error = + vfs_setopt(opts, pr_flag_jailsys[fi].name, &i, sizeof(i)); + if (error != 0 && error != ENOENT) + goto done_deref; + } for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]); fi++) { if (pr_allow_names[fi] == NULL) @@ -2614,6 +2657,7 @@ prison_restrict_ip4(struct prison *pr, struct in_addr *newip4) } } if (pr->pr_ip4s == 0) { + pr->pr_flags |= PR_IP4_DISABLE; free(pr->pr_ip4, M_PRISON); pr->pr_ip4 = NULL; } @@ -2918,6 +2962,7 @@ prison_restrict_ip6(struct prison *pr, struct in6_addr *newip6) } } if (pr->pr_ip6s == 0) { + pr->pr_flags |= PR_IP6_DISABLE; free(pr->pr_ip6, M_PRISON); pr->pr_ip6 = NULL; } @@ -4035,7 +4080,7 @@ SYSCTL_JAIL_PARAM(, persist, CTLTYPE_INT | CTLFLAG_RW, "B", "Jail persistence"); #ifdef VIMAGE SYSCTL_JAIL_PARAM(, vnet, CTLTYPE_INT | CTLFLAG_RDTUN, - "B", "Virtual network stack"); + "E,jailsys", "Virtual network stack"); #endif SYSCTL_JAIL_PARAM(, dying, CTLTYPE_INT | CTLFLAG_RD, "B", "Jail is in the process of shutting down"); @@ -4046,9 +4091,7 @@ SYSCTL_JAIL_PARAM(_children, cur, CTLTYPE_INT | CTLFLAG_RD, SYSCTL_JAIL_PARAM(_children, max, CTLTYPE_INT | CTLFLAG_RW, "I", "Maximum number of child jails"); -SYSCTL_JAIL_PARAM_NODE(host, "Jail host info"); -SYSCTL_JAIL_PARAM(, nohost, CTLTYPE_INT | CTLFLAG_RW, - "BN", "Jail w/ no host info"); +SYSCTL_JAIL_PARAM_SYS_NODE(host, CTLFLAG_RW, "Jail host info"); SYSCTL_JAIL_PARAM_STRING(_host, hostname, CTLFLAG_RW, MAXHOSTNAMELEN, "Jail hostname"); SYSCTL_JAIL_PARAM_STRING(_host, domainname, CTLFLAG_RW, MAXHOSTNAMELEN, @@ -4062,16 +4105,12 @@ SYSCTL_JAIL_PARAM_NODE(cpuset, "Jail cpuset"); SYSCTL_JAIL_PARAM(_cpuset, id, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail cpuset ID"); #ifdef INET -SYSCTL_JAIL_PARAM_NODE(ip4, "Jail IPv4 address virtualization"); -SYSCTL_JAIL_PARAM(, noip4, CTLTYPE_INT | CTLFLAG_RW, - "BN", "Jail w/ no IP address virtualization"); +SYSCTL_JAIL_PARAM_SYS_NODE(ip4, CTLFLAG_RW, "Jail IPv4 address virtualization"); SYSCTL_JAIL_PARAM_STRUCT(_ip4, addr, CTLFLAG_RW, sizeof(struct in_addr), "S,in_addr,a", "Jail IPv4 addresses"); #endif #ifdef INET6 -SYSCTL_JAIL_PARAM_NODE(ip6, "Jail IPv6 address virtualization"); -SYSCTL_JAIL_PARAM(, noip6, CTLTYPE_INT | CTLFLAG_RW, - "BN", "Jail w/ no IP address virtualization"); +SYSCTL_JAIL_PARAM_SYS_NODE(ip6, CTLFLAG_RW, "Jail IPv6 address virtualization"); SYSCTL_JAIL_PARAM_STRUCT(_ip6, addr, CTLFLAG_RW, sizeof(struct in6_addr), "S,in6_addr,a", "Jail IPv6 addresses"); #endif @@ -4102,6 +4141,7 @@ db_show_prison(struct prison *pr) #if defined(INET) || defined(INET6) int ii; #endif + unsigned jsf; #ifdef INET6 char ip6buf[INET6_ADDRSTRLEN]; #endif @@ -4128,6 +4168,16 @@ db_show_prison(struct prison *pr) fi++) if (pr_flag_names[fi] != NULL && (pr->pr_flags & (1 << fi))) db_printf(" %s", pr_flag_names[fi]); + for (fi = 0; fi < sizeof(pr_flag_jailsys) / sizeof(pr_flag_jailsys[0]); + fi++) { + jsf = pr->pr_flags & + (pr_flag_jailsys[fi].disable | pr_flag_jailsys[fi].new); + db_printf(" %-16s= %s\n", pr_flag_jailsys[fi].name, + pr_flag_jailsys[fi].disable && + (jsf == pr_flag_jailsys[fi].disable) ? "disable" + : (jsf == pr_flag_jailsys[fi].new) ? "new" + : "inherit"); + } db_printf(" allow = %x", pr->pr_allow); for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]); fi++) diff --git a/sys/sys/jail.h b/sys/sys/jail.h index 117e134..d7457bf 100644 --- a/sys/sys/jail.h +++ b/sys/sys/jail.h @@ -100,6 +100,10 @@ struct xprison { #define JAIL_SET_MASK 0x0f #define JAIL_GET_MASK 0x08 +#define JAIL_SYS_DISABLE 0 +#define JAIL_SYS_NEW 1 +#define JAIL_SYS_INHERIT 2 + #ifndef _KERNEL struct iovec; @@ -182,16 +186,18 @@ struct prison { /* Flag bits set via options */ #define PR_PERSIST 0x00000001 /* Can exist without processes */ #define PR_HOST 0x00000002 /* Virtualize hostname et al */ -#define PR_IP4_USER 0x00000004 /* Virtualize IPv4 addresses */ -#define PR_IP6_USER 0x00000008 /* Virtualize IPv6 addresses */ +#define PR_IP4_USER 0x00000004 /* Restrict IPv4 addresses */ +#define PR_IP6_USER 0x00000008 /* Restrict IPv6 addresses */ #define PR_VNET 0x00000010 /* Virtual network stack */ +#define PR_IP4_DISABLE 0x00000020 /* Disable IPv4 */ +#define PR_IP6_DISABLE 0x00000040 /* Disable IPv6 */ /* Internal flag bits */ #define PR_REMOVE 0x01000000 /* In process of being removed */ -#define PR_IP4 0x02000000 /* IPv4 virtualized by this jail or */ - /* an ancestor */ -#define PR_IP6 0x04000000 /* IPv6 virtualized by this jail or */ - /* an ancestor */ +#define PR_IP4 0x02000000 /* IPv4 restricted or disabled */ + /* by this jail or an ancestor */ +#define PR_IP6 0x04000000 /* IPv6 restricted or disabled */ + /* by this jail or an ancestor */ /* Flags for pr_allow */ #define PR_ALLOW_SET_HOSTNAME 0x0001 @@ -315,7 +321,11 @@ SYSCTL_DECL(_security_jail_param); CTLTYPE_STRUCT | CTLFLAG_MPSAFE | (access), NULL, len, \ sysctl_jail_param, fmt, descr) #define SYSCTL_JAIL_PARAM_NODE(module, descr) \ - SYSCTL_NODE(_security_jail_param, OID_AUTO, module, CTLFLAG_RW, 0, descr) + SYSCTL_NODE(_security_jail_param, OID_AUTO, module, 0, 0, descr) +#define SYSCTL_JAIL_PARAM_SYS_NODE(module, access, descr) \ + SYSCTL_JAIL_PARAM_NODE(module, descr); \ + SYSCTL_JAIL_PARAM(_##module, , CTLTYPE_INT | (access), "E,jailsys", \ + descr) /* * Kernel support functions for jail(). diff --git a/usr.sbin/jail/jail.8 b/usr.sbin/jail/jail.8 index 7189001..f3340bd 100644 --- a/usr.sbin/jail/jail.8 +++ b/usr.sbin/jail/jail.8 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 8, 2009 +.Dd July 25, 2009 .Dt JAIL 8 .Os .Sh NAME @@ -252,14 +252,26 @@ match. It is only possible to start multiple jails with the same IP address, if none of the jails has more than this single overlapping IP address assigned to itself. -.Pp -A list of zero elements (an empty string) will stop the jail from using IPv4 -entirely; setting the boolean parameter -.Ar noip4 -will not restrict the jail at all. -.It Va ip6.addr +.It Va ip4 +Control the availablity of IPv4 addresses. +Possible values are +.Dq inherit +to allow unrestricted access to all system addresses, +.Dq new +to restrict addresses via +.Va ip4.addr +above, and +.Dq disable +to stop the jail from using IPv4 entirely. +Setting the +.Va ip4.addr +parameter implies a value of +.Dq new . +.It Va ip6.addr , Va ip6 A list of IPv6 addresses assigned to the prison, the counterpart to -.Ar ip4.addr +.Va ip4.addr +and +.Va ip4 above. .It Va host.hostname Hostname of the prison. @@ -268,9 +280,15 @@ Other similar parameters are .Va host.hostuuid and .Va host.hostid . -Setting the boolean parameter -.Va nohost -will retain the system values of these settings. +.It Va host +Set the origin of hostname and related information. +Possible values are +.Dq inherit +to use the system information and +.Dq new +for the jail to use the information from the above fields. +Setting any of the above fields implies a value of +.Dq new . .It Va securelevel The value of the jail's .Va kern.securelevel diff --git a/usr.sbin/jls/jls.c b/usr.sbin/jls/jls.c index 40019f1..8c8b981 100644 --- a/usr.sbin/jls/jls.c +++ b/usr.sbin/jls/jls.c @@ -57,7 +57,7 @@ __FBSDID("$FreeBSD$"); #define PRINT_VERBOSE 0x20 static struct jailparam *params; -static int *param_noparent; +static int *param_parent; static int nparams; static int add_param(const char *name, void *value, size_t valuelen, @@ -71,7 +71,7 @@ static void quoted_print(char *str); int main(int argc, char **argv) { - char *dot, *ep, *jname, *nname; + char *dot, *ep, *jname; int c, i, jflags, jid, lastjid, pflags, spc; jname = NULL; @@ -139,17 +139,14 @@ main(int argc, char **argv) JP_USER); if (pflags & PRINT_SKIP) { - /* Check for parameters with boolean parents. */ + /* Check for parameters with jailsys parents. */ for (i = 0; i < nparams; i++) { if ((params[i].jp_flags & JP_USER) && (dot = strchr(params[i].jp_name, '.'))) { *dot = 0; - nname = noname(params[i].jp_name); + param_parent[i] = add_param(params[i].jp_name, + NULL, (size_t)0, NULL, JP_OPT); *dot = '.'; - param_noparent[i] = - add_param(nname, NULL, (size_t)0, NULL, - JP_OPT); - free(nname); } } } @@ -237,21 +234,20 @@ add_param(const char *name, void *value, size_t valuelen, if (!nparams) { paramlistsize = 32; params = malloc(paramlistsize * sizeof(*params)); - param_noparent = - malloc(paramlistsize * sizeof(*param_noparent)); - if (params == NULL || param_noparent == NULL) + param_parent = malloc(paramlistsize * sizeof(*param_parent)); + if (params == NULL || param_parent == NULL) err(1, "malloc"); } else if (nparams >= paramlistsize) { paramlistsize *= 2; params = realloc(params, paramlistsize * sizeof(*params)); - param_noparent = realloc(param_noparent, - paramlistsize * sizeof(*param_noparent)); - if (params == NULL || param_noparent == NULL) + param_parent = realloc(param_parent, + paramlistsize * sizeof(*param_parent)); + if (params == NULL || param_parent == NULL) err(1, "realloc"); } /* Look up the parameter. */ - param_noparent[nparams] = -1; + param_parent[nparams] = -1; param = params + nparams++; if (source != NULL) { *param = *source; @@ -387,8 +383,9 @@ print_jail(int pflags, int jflags) if ((pflags & PRINT_SKIP) && ((!(params[i].jp_ctltype & (CTLFLAG_WR | CTLFLAG_TUN))) || - (param_noparent[i] >= 0 && - *(int *)params[param_noparent[i]].jp_value))) + (param_parent[i] >= 0 && + *(int *)params[param_parent[i]].jp_value != + JAIL_SYS_NEW))) continue; if (spc) putchar(' '); -- cgit v1.1