diff options
author | jamie <jamie@FreeBSD.org> | 2009-07-25 14:48:57 +0000 |
---|---|---|
committer | jamie <jamie@FreeBSD.org> | 2009-07-25 14:48:57 +0000 |
commit | 274ea197bb2f446e42dd6f17d5046b348d26d82d (patch) | |
tree | e2f5557445f7151dc18cefe88f9b884b83f55993 /sys | |
parent | 0888b985acf99a673549ca79a753e47d3e98fe9a (diff) | |
download | FreeBSD-src-274ea197bb2f446e42dd6f17d5046b348d26d82d.zip FreeBSD-src-274ea197bb2f446e42dd6f17d5046b348d26d82d.tar.gz |
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
Diffstat (limited to 'sys')
-rw-r--r-- | sys/compat/linux/linux_mib.c | 78 | ||||
-rw-r--r-- | sys/kern/kern_jail.c | 120 | ||||
-rw-r--r-- | sys/sys/jail.h | 24 |
3 files changed, 145 insertions, 77 deletions
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(). |