summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorjamie <jamie@FreeBSD.org>2009-07-25 14:48:57 +0000
committerjamie <jamie@FreeBSD.org>2009-07-25 14:48:57 +0000
commit274ea197bb2f446e42dd6f17d5046b348d26d82d (patch)
treee2f5557445f7151dc18cefe88f9b884b83f55993 /sys
parent0888b985acf99a673549ca79a753e47d3e98fe9a (diff)
downloadFreeBSD-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.c78
-rw-r--r--sys/kern/kern_jail.c120
-rw-r--r--sys/sys/jail.h24
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().
OpenPOWER on IntegriCloud