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
This commit is contained in:
jamie 2009-07-25 14:48:57 +00:00
parent 0888b985ac
commit 274ea197bb
7 changed files with 277 additions and 165 deletions

View File

@ -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;
}
snprintf(valbuf, sizeof(valbuf), "%d",
((int *)jp->jp_value)[i]);
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", 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));
"sysctl(0.1): %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;
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);

View File

@ -32,6 +32,7 @@
#define JP_RAWVALUE 0x01
#define JP_BOOL 0x02
#define JP_NOBOOL 0x04
#define JP_JAILSYS 0x08
#define JAIL_ERRMSGLEN 1024

View File

@ -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;

View File

@ -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++)

View File

@ -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().

View File

@ -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

View File

@ -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(' ');