Created
February 9, 2025 09:04
-
-
Save paigeadelethompson/0fc590bb4ad1b682d6e227dca7097cbf to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c | |
index 6ffeab59112b..fca83c74671b 100644 | |
--- a/sys/kern/kern_jail.c | |
+++ b/sys/kern/kern_jail.c | |
@@ -325,8 +325,11 @@ sys_jail(struct thread *td, struct jail_args *uap) | |
struct jail j; | |
error = copyin(uap->jail, &version, sizeof(uint32_t)); | |
- if (error) | |
+ if (error) { | |
+ if (bootverbose) | |
+ printf("jail: failed to copy version from userspace (error=%d)\n", error); | |
return (error); | |
+ } | |
switch (version) { | |
case 0: | |
@@ -336,8 +339,11 @@ sys_jail(struct thread *td, struct jail_args *uap) | |
/* FreeBSD single IPv4 jails. */ | |
bzero(&j, sizeof(struct jail)); | |
error = copyin(uap->jail, &j0, sizeof(struct jail_v0)); | |
- if (error) | |
+ if (error) { | |
+ if (bootverbose) | |
+ printf("jail: failed to copy jail_v0 structure from userspace (error=%d)\n", error); | |
return (error); | |
+ } | |
j.version = j0.version; | |
j.path = j0.path; | |
j.hostname = j0.hostname; | |
@@ -350,17 +356,24 @@ sys_jail(struct thread *td, struct jail_args *uap) | |
* Version 1 was used by multi-IPv4 jail implementations | |
* that never made it into the official kernel. | |
*/ | |
+ if (bootverbose) | |
+ printf("jail: unsupported jail API version 1\n"); | |
return (EINVAL); | |
case 2: /* JAIL_API_VERSION */ | |
/* FreeBSD multi-IPv4/IPv6,noIP jails. */ | |
error = copyin(uap->jail, &j, sizeof(struct jail)); | |
- if (error) | |
+ if (error) { | |
+ if (bootverbose) | |
+ printf("jail: failed to copy jail structure from userspace (error=%d)\n", error); | |
return (error); | |
+ } | |
break; | |
default: | |
/* Sci-Fi jails are not supported, sorry. */ | |
+ if (bootverbose) | |
+ printf("jail: unsupported jail API version %d\n", version); | |
return (EINVAL); | |
} | |
return (kern_jail(td, &j)); | |
@@ -424,20 +437,32 @@ kern_jail(struct thread *td, struct jail *j) | |
tmplen = MAXPATHLEN + MAXHOSTNAMELEN + MAXHOSTNAMELEN; | |
#ifdef INET | |
ip4s = (j->version == 0) ? 1 : j->ip4s; | |
- if (ip4s > jail_max_af_ips) | |
+ if (ip4s > jail_max_af_ips) { | |
+ if (bootverbose) | |
+ printf("jail: too many IPv4 addresses specified (max=%u)\n", jail_max_af_ips); | |
return (EINVAL); | |
+ } | |
tmplen += ip4s * sizeof(struct in_addr); | |
#else | |
- if (j->ip4s > 0) | |
+ if (j->ip4s > 0) { | |
+ if (bootverbose) | |
+ printf("jail: IPv4 addresses specified but INET not compiled in kernel\n"); | |
return (EINVAL); | |
+ } | |
#endif | |
#ifdef INET6 | |
- if (j->ip6s > jail_max_af_ips) | |
+ if (j->ip6s > jail_max_af_ips) { | |
+ if (bootverbose) | |
+ printf("jail: too many IPv6 addresses specified (max=%u)\n", jail_max_af_ips); | |
return (EINVAL); | |
+ } | |
tmplen += j->ip6s * sizeof(struct in6_addr); | |
#else | |
- if (j->ip6s > 0) | |
+ if (j->ip6s > 0) { | |
+ if (bootverbose) | |
+ printf("jail: IPv6 addresses specified but INET6 not compiled in kernel\n"); | |
return (EINVAL); | |
+ } | |
#endif | |
u_path = malloc(tmplen, M_TEMP, M_WAITOK); | |
u_hostname = u_path + MAXPATHLEN; | |
@@ -459,6 +484,8 @@ kern_jail(struct thread *td, struct jail *j) | |
error = copyinstr(j->path, u_path, MAXPATHLEN, | |
&optiov[opt.uio_iovcnt].iov_len); | |
if (error) { | |
+ if (bootverbose) | |
+ printf("jail: failed to copy path from userspace (error=%d)\n", error); | |
free(u_path, M_TEMP); | |
return (error); | |
} | |
@@ -470,6 +497,8 @@ kern_jail(struct thread *td, struct jail *j) | |
error = copyinstr(j->hostname, u_hostname, MAXHOSTNAMELEN, | |
&optiov[opt.uio_iovcnt].iov_len); | |
if (error) { | |
+ if (bootverbose) | |
+ printf("jail: failed to copy hostname from userspace (error=%d)\n", error); | |
free(u_path, M_TEMP); | |
return (error); | |
} | |
@@ -482,6 +511,8 @@ kern_jail(struct thread *td, struct jail *j) | |
error = copyinstr(j->jailname, u_name, MAXHOSTNAMELEN, | |
&optiov[opt.uio_iovcnt].iov_len); | |
if (error) { | |
+ if (bootverbose) | |
+ printf("jail: failed to copy jail name from userspace (error=%d)\n", error); | |
free(u_path, M_TEMP); | |
return (error); | |
} | |
@@ -498,6 +529,8 @@ kern_jail(struct thread *td, struct jail *j) | |
else { | |
error = copyin(j->ip4, u_ip4, optiov[opt.uio_iovcnt].iov_len); | |
if (error) { | |
+ if (bootverbose) | |
+ printf("jail: failed to copy IPv4 addresses from userspace (error=%d)\n", error); | |
free(u_path, M_TEMP); | |
return (error); | |
} | |
@@ -512,6 +545,8 @@ kern_jail(struct thread *td, struct jail *j) | |
optiov[opt.uio_iovcnt].iov_len = j->ip6s * sizeof(struct in6_addr); | |
error = copyin(j->ip6, u_ip6, optiov[opt.uio_iovcnt].iov_len); | |
if (error) { | |
+ if (bootverbose) | |
+ printf("jail: failed to copy IPv6 addresses from userspace (error=%d)\n", error); | |
free(u_path, M_TEMP); | |
return (error); | |
} | |
@@ -538,12 +573,18 @@ sys_jail_set(struct thread *td, struct jail_set_args *uap) | |
int error; | |
/* Check that we have an even number of iovecs. */ | |
- if (uap->iovcnt & 1) | |
+ if (uap->iovcnt & 1) { | |
+ if (bootverbose) | |
+ printf("jail: odd number of iovecs specified (error=EINVAL)\n"); | |
return (EINVAL); | |
+ } | |
error = copyinuio(uap->iovp, uap->iovcnt, &auio); | |
- if (error) | |
+ if (error) { | |
+ if (bootverbose) | |
+ printf("jail: failed to copy in iovecs (error=%d)\n", error); | |
return (error); | |
+ } | |
error = kern_jail_set(td, auio, uap->flags); | |
freeuio(auio); | |
return (error); | |
@@ -651,12 +692,16 @@ prison_ip_copyin(const pr_family_t af, void *op, uint32_t cnt) | |
*/ | |
for (int i = 0; i < cnt; i++) { | |
if (!pr_families[af].valid(PR_IP(pip, af, i))) { | |
+ if (bootverbose) | |
+ printf("jail: invalid IP address at index %d\n", i); | |
free(pip, M_PRISON); | |
return (NULL); | |
} | |
if (i + 1 < cnt && | |
(cmp(PR_IP(pip, af, 0), PR_IP(pip, af, i + 1)) == 0 || | |
cmp(PR_IP(pip, af, i), PR_IP(pip, af, i + 1)) == 0)) { | |
+ if (bootverbose) | |
+ printf("jail: duplicate IP address at index %d\n", i + 1); | |
free(pip, M_PRISON); | |
return (NULL); | |
} | |
@@ -833,8 +878,11 @@ prison_ip_restrict(struct prison *pr, const pr_family_t af, | |
if (!(pr->pr_flags & pr_families[af].ip_flag)) { | |
if (new == NULL) { | |
new = prison_ip_alloc(af, ppip->ips, M_NOWAIT); | |
- if (new == NULL) | |
+ if (new == NULL) { | |
+ if (bootverbose) | |
+ printf("jail: failed to allocate memory for IP addresses\n"); | |
return (false); /* Redo */ | |
+ } | |
} | |
/* This has no user settings, so just copy the parent's list. */ | |
MPASS(new->ips == ppip->ips); | |
@@ -851,8 +899,11 @@ prison_ip_restrict(struct prison *pr, const pr_family_t af, | |
if (new == NULL) { | |
new = prison_ip_alloc(af, pip->ips, M_NOWAIT); | |
- if (new == NULL) | |
+ if (new == NULL) { | |
+ if (bootverbose) | |
+ printf("jail: failed to allocate memory for IP addresses\n"); | |
return (false); /* Redo */ | |
+ } | |
} | |
for (int pi = 0; pi < ppip->ips; pi++) | |
@@ -893,6 +944,8 @@ prison_ip_restrict(struct prison *pr, const pr_family_t af, | |
} | |
} | |
if (ips == 0) { | |
+ if (bootverbose) | |
+ printf("jail: no valid IP addresses remain after restriction\n"); | |
if (newp == NULL || *newp == NULL) | |
prison_ip_free(new); | |
new = NULL; | |
@@ -925,8 +978,11 @@ prison_ip_check(const struct prison *pr, const pr_family_t af, | |
sx_xlocked(&allprison_lock)); | |
pip = atomic_load_ptr(&pr->pr_addrs[af]); | |
- if (__predict_false(pip == NULL)) | |
+ if (__predict_false(pip == NULL)) { | |
+ if (bootverbose) | |
+ printf("jail: no IP addresses configured for family %d (error=EAFNOSUPPORT)\n", af); | |
return (EAFNOSUPPORT); | |
+ } | |
/* Check the primary IP. */ | |
if (cmp(PR_IP(pip, af, 0), addr) == 0) | |
@@ -948,6 +1004,8 @@ prison_ip_check(const struct prison *pr, const pr_family_t af, | |
return (0); | |
} | |
+ if (bootverbose) | |
+ printf("jail: IP address not found in jail (family=%d)\n", af); | |
return (EADDRNOTAVAIL); | |
} | |
@@ -1019,13 +1077,22 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
error = priv_check(td, PRIV_JAIL_SET); | |
if (!error && (flags & JAIL_ATTACH)) | |
error = priv_check(td, PRIV_JAIL_ATTACH); | |
- if (error) | |
+ if (error) { | |
+ if (bootverbose) | |
+ printf("jail: insufficient privileges for jail_set (error=%d)\n", error); | |
return (error); | |
+ } | |
mypr = td->td_ucred->cr_prison; | |
- if ((flags & JAIL_CREATE) && mypr->pr_childmax == 0) | |
+ if ((flags & JAIL_CREATE) && mypr->pr_childmax == 0) { | |
+ if (bootverbose) | |
+ printf("jail: cannot create jail when childmax is 0 (error=EPERM)\n"); | |
return (EPERM); | |
- if (flags & ~JAIL_SET_MASK) | |
+ } | |
+ if (flags & ~JAIL_SET_MASK) { | |
+ if (bootverbose) | |
+ printf("jail: invalid flags specified (flags=0x%x)\n", flags); | |
return (EINVAL); | |
+ } | |
/* | |
* Check all the parameters before committing to anything. Not all | |
@@ -1038,8 +1105,11 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
* than duplicate it under a different name. | |
*/ | |
error = vfs_buildopts(optuio, &opts); | |
- if (error) | |
+ if (error) { | |
+ if (bootverbose) | |
+ printf("jail: failed to build options list (error=%d)\n", error); | |
return (error); | |
+ } | |
#ifdef INET | |
ip4 = NULL; | |
#endif | |
@@ -1084,6 +1154,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
else if (error != 0) | |
goto done_free; | |
else if (enforce < 0 || enforce > 2) { | |
+ if (bootverbose) | |
+ printf("jail: invalid enforce_statfs value %d\n", enforce); | |
error = EINVAL; | |
goto done_free; | |
} else | |
@@ -1116,6 +1188,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
switch (jsys) { | |
case JAIL_SYS_DISABLE: | |
if (!jsf->disable) { | |
+ if (bootverbose) | |
+ printf("jail: system disable not allowed for %s\n", jsf->name); | |
error = EINVAL; | |
goto done_free; | |
} | |
@@ -1127,6 +1201,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
case JAIL_SYS_INHERIT: | |
break; | |
default: | |
+ if (bootverbose) | |
+ printf("jail: invalid system flag value %d for %s\n", jsys, jsf->name); | |
error = EINVAL; | |
goto done_free; | |
} | |
@@ -1134,12 +1210,16 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
} | |
if ((flags & (JAIL_CREATE | JAIL_ATTACH)) == JAIL_CREATE | |
&& !(pr_flags & PR_PERSIST)) { | |
+ if (bootverbose) | |
+ printf("jail: new jail must persist or attach\n"); | |
error = EINVAL; | |
vfs_opterror(opts, "new jail must persist or attach"); | |
goto done_errmsg; | |
} | |
#ifdef VIMAGE | |
if ((flags & JAIL_UPDATE) && (ch_flags & PR_VNET)) { | |
+ if (bootverbose) | |
+ printf("jail: vnet cannot be changed after creation\n"); | |
error = EINVAL; | |
vfs_opterror(opts, "vnet cannot be changed after creation"); | |
goto done_errmsg; | |
@@ -1147,6 +1227,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
#endif | |
#ifdef INET | |
if ((flags & JAIL_UPDATE) && (ch_flags & PR_IP4_USER)) { | |
+ if (bootverbose) | |
+ printf("jail: ip4 cannot be changed after creation\n"); | |
error = EINVAL; | |
vfs_opterror(opts, "ip4 cannot be changed after creation"); | |
goto done_errmsg; | |
@@ -1154,6 +1236,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
#endif | |
#ifdef INET6 | |
if ((flags & JAIL_UPDATE) && (ch_flags & PR_IP6_USER)) { | |
+ if (bootverbose) | |
+ printf("jail: ip6 cannot be changed after creation\n"); | |
error = EINVAL; | |
vfs_opterror(opts, "ip6 cannot be changed after creation"); | |
goto done_errmsg; | |
@@ -1177,6 +1261,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
goto done_free; | |
else { | |
if (len == 0 || name[len - 1] != '\0') { | |
+ if (bootverbose) | |
+ printf("jail: invalid name parameter length or termination\n"); | |
error = EINVAL; | |
goto done_free; | |
} | |
@@ -1195,6 +1281,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
ch_flags |= PR_HOST; | |
pr_flags |= PR_HOST; | |
if (len == 0 || host[len - 1] != '\0') { | |
+ if (bootverbose) | |
+ printf("jail: invalid hostname parameter length or termination\n"); | |
error = EINVAL; | |
goto done_free; | |
} | |
@@ -1213,6 +1301,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
ch_flags |= PR_HOST; | |
pr_flags |= PR_HOST; | |
if (len == 0 || domain[len - 1] != '\0') { | |
+ if (bootverbose) | |
+ printf("jail: invalid domainname parameter length or termination\n"); | |
error = EINVAL; | |
goto done_free; | |
} | |
@@ -1231,6 +1321,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
ch_flags |= PR_HOST; | |
pr_flags |= PR_HOST; | |
if (len == 0 || uuid[len - 1] != '\0') { | |
+ if (bootverbose) | |
+ printf("jail: invalid hostuuid parameter length or termination\n"); | |
error = EINVAL; | |
goto done_free; | |
} | |
@@ -1266,6 +1358,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
else if (error != 0) | |
goto done_free; | |
else if (ip4s & (sizeof(struct in_addr) - 1)) { | |
+ if (bootverbose) | |
+ printf("jail: invalid IPv4 address size alignment\n"); | |
error = EINVAL; | |
goto done_free; | |
} else { | |
@@ -1274,12 +1368,16 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
if (ip4s > 0) { | |
ip4s /= sizeof(struct in_addr); | |
if (ip4s > jail_max_af_ips) { | |
+ if (bootverbose) | |
+ printf("jail: too many IPv4 addresses (max=%u)\n", jail_max_af_ips); | |
error = EINVAL; | |
vfs_opterror(opts, "too many IPv4 addresses"); | |
goto done_errmsg; | |
} | |
ip4 = prison_ip_copyin(PR_INET, op, ip4s); | |
if (ip4 == NULL) { | |
+ if (bootverbose) | |
+ printf("jail: failed to copy in IPv4 addresses\n"); | |
error = EINVAL; | |
goto done_free; | |
} | |
@@ -1294,6 +1392,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
else if (error != 0) | |
goto done_free; | |
else if (ip6s & (sizeof(struct in6_addr) - 1)) { | |
+ if (bootverbose) | |
+ printf("jail: invalid IPv6 address size alignment\n"); | |
error = EINVAL; | |
goto done_free; | |
} else { | |
@@ -1302,12 +1402,16 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
if (ip6s > 0) { | |
ip6s /= sizeof(struct in6_addr); | |
if (ip6s > jail_max_af_ips) { | |
+ if (bootverbose) | |
+ printf("jail: too many IPv6 addresses (max=%u)\n", jail_max_af_ips); | |
error = EINVAL; | |
vfs_opterror(opts, "too many IPv6 addresses"); | |
goto done_errmsg; | |
} | |
ip6 = prison_ip_copyin(PR_INET6, op, ip6s); | |
if (ip6 == NULL) { | |
+ if (bootverbose) | |
+ printf("jail: failed to copy in IPv6 addresses\n"); | |
error = EINVAL; | |
goto done_free; | |
} | |
@@ -1317,6 +1421,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
#if defined(VIMAGE) && (defined(INET) || defined(INET6)) | |
if ((ch_flags & PR_VNET) && (ch_flags & (PR_IP4_USER | PR_IP6_USER))) { | |
+ if (bootverbose) | |
+ printf("jail: vnet jails cannot have IP address restrictions\n"); | |
error = EINVAL; | |
vfs_opterror(opts, | |
"vnet jails cannot have IP address restrictions"); | |
@@ -1331,12 +1437,16 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
goto done_free; | |
else { | |
if (flags & JAIL_UPDATE) { | |
+ if (bootverbose) | |
+ printf("jail: osrelease cannot be changed after creation\n"); | |
error = EINVAL; | |
vfs_opterror(opts, | |
"osrelease cannot be changed after creation"); | |
goto done_errmsg; | |
} | |
if (len == 0 || osrelstr[len - 1] != '\0') { | |
+ if (bootverbose) | |
+ printf("jail: invalid osrelease parameter length or termination\n"); | |
error = EINVAL; | |
goto done_free; | |
} | |
@@ -1356,12 +1466,16 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
goto done_free; | |
else { | |
if (flags & JAIL_UPDATE) { | |
+ if (bootverbose) | |
+ printf("jail: osreldate cannot be changed after creation\n"); | |
error = EINVAL; | |
vfs_opterror(opts, | |
"osreldate cannot be changed after creation"); | |
goto done_errmsg; | |
} | |
if (osreldt == 0) { | |
+ if (bootverbose) | |
+ printf("jail: osreldate cannot be 0\n"); | |
error = EINVAL; | |
vfs_opterror(opts, "osreldate cannot be 0"); | |
goto done_errmsg; | |
@@ -1383,12 +1497,17 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
} | |
if (len == 0 || path[len - 1] != '\0') { | |
error = EINVAL; | |
+ if (bootverbose) | |
+ printf("jail: invalid path length or termination (error=%d)\n", error); | |
goto done_free; | |
} | |
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, path); | |
error = namei(&nd); | |
- if (error) | |
+ if (error) { | |
+ if (bootverbose) | |
+ printf("jail: namei lookup failed for path (error=%d)\n", error); | |
goto done_free; | |
+ } | |
root = nd.ni_vp; | |
NDFREE_PNBUF(&nd); | |
g_path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); | |
@@ -1398,10 +1517,14 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
path = g_path; | |
} else { | |
/* exit on other errors */ | |
+ if (bootverbose) | |
+ printf("jail: failed to get global path (error=%d)\n", error); | |
goto done_free; | |
} | |
if (root->v_type != VDIR) { | |
error = ENOTDIR; | |
+ if (bootverbose) | |
+ printf("jail: root path is not a directory (error=%d)\n", error); | |
vput(root); | |
goto done_free; | |
} | |
@@ -1427,10 +1550,14 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
if (!prison_isalive(ppr)) { | |
/* This jail is dying. This process will surely follow. */ | |
error = EAGAIN; | |
+ if (bootverbose) | |
+ printf("jail: parent jail is dying (error=%d)\n", error); | |
goto done_deref; | |
} | |
if (jid != 0) { | |
if (jid < 0) { | |
+ if (bootverbose) | |
+ printf("jail: negative jail ID specified (error=%d)\n", EINVAL); | |
error = EINVAL; | |
vfs_opterror(opts, "negative jid"); | |
goto done_deref; | |
@@ -1462,6 +1589,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
*/ | |
error = EEXIST; | |
vfs_opterror(opts, "jail %d already exists", jid); | |
+ if (bootverbose) | |
+ printf("jail: attempt to create jail with existing ID %d (error=%d)\n", jid, error); | |
goto done_deref; | |
} | |
if ((pr == NULL) | |
@@ -1475,6 +1604,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
*/ | |
error = ENOENT; | |
vfs_opterror(opts, "jail %d not found", jid); | |
+ if (bootverbose) | |
+ printf("jail: jail %d not found or not visible (error=%d)\n", jid, error); | |
goto done_deref; | |
} | |
} | |
@@ -1499,6 +1630,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
if (pr != NULL) { | |
if (strncmp(name, ppr->pr_name, namelc - name) | |
|| ppr->pr_name[namelc - name] != '\0') { | |
+ if (bootverbose) | |
+ printf("jail: cannot change jail's parent\n"); | |
error = EINVAL; | |
vfs_opterror(opts, | |
"cannot change jail's parent"); | |
@@ -1705,8 +1838,11 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
* Unlike other initial settings, this may return an error. | |
*/ | |
error = cpuset_create_root(ppr, &pr->pr_cpuset); | |
- if (error) | |
+ if (error) { | |
+ if (bootverbose) | |
+ printf("jail: failed to create root cpuset (error=%d)\n", error); | |
goto done_deref; | |
+ } | |
mtx_lock(&pr->pr_mtx); | |
drflags |= PD_LOCKED; | |
@@ -1748,18 +1884,24 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
if (gotslevel) { | |
if (slevel < ppr->pr_securelevel) { | |
error = EPERM; | |
+ if (bootverbose) | |
+ printf("jail: attempt to lower securelevel (error=%d)\n", error); | |
goto done_deref; | |
} | |
} | |
if (gotchildmax) { | |
if (childmax >= ppr->pr_childmax) { | |
error = EPERM; | |
+ if (bootverbose) | |
+ printf("jail: childmax exceeds parent's limit (error=%d)\n", error); | |
goto done_deref; | |
} | |
} | |
if (gotenforce) { | |
if (enforce < ppr->pr_enforce_statfs) { | |
error = EPERM; | |
+ if (bootverbose) | |
+ printf("jail: attempt to lower enforce_statfs (error=%d)\n", error); | |
goto done_deref; | |
} | |
} | |
@@ -1768,6 +1910,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
* devfs_rsnum is a uint16_t | |
*/ | |
if (rsnum < 0 || rsnum > 65535) { | |
+ if (bootverbose) | |
+ printf("jail: invalid devfs ruleset number (error=%d)\n", EINVAL); | |
error = EINVAL; | |
goto done_deref; | |
} | |
@@ -1777,6 +1921,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
if (jailed(td->td_ucred)) { | |
if (rsnum > 0 && rsnum != ppr->pr_devfs_rsnum) { | |
error = EPERM; | |
+ if (bootverbose) | |
+ printf("jail: nested jail cannot change devfs ruleset (error=%d)\n", error); | |
goto done_deref; | |
} else | |
rsnum = ppr->pr_devfs_rsnum; | |
@@ -1788,6 +1934,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
!prison_ip_parent_match(ppr->pr_addrs[PR_INET], ip4, | |
PR_INET)) { | |
error = EPERM; | |
+ if (bootverbose) | |
+ printf("jail: IPv4 addresses not allowed by parent jail (error=%d)\n", error); | |
goto done_deref; | |
} | |
if (!prison_ip_conflict_check(ppr, pr, ip4, PR_INET)) { | |
@@ -1803,6 +1951,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
!prison_ip_parent_match(ppr->pr_addrs[PR_INET6], ip6, | |
PR_INET6)) { | |
error = EPERM; | |
+ if (bootverbose) | |
+ printf("jail: IPv6 addresses not allowed by parent jail (error=%d)\n", error); | |
goto done_deref; | |
} | |
if (!prison_ip_conflict_check(ppr, pr, ip6, PR_INET6)) { | |
@@ -1822,6 +1972,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
snprintf(namelc = numbuf, sizeof(numbuf), "%d", jid); | |
else if ((strtoul(namelc, &p, 10) != jid || | |
namelc[0] < '1' || namelc[0] > '9') && *p == '\0') { | |
+ if (bootverbose) | |
+ printf("jail: name cannot be numeric unless it is the jid\n"); | |
error = EINVAL; | |
vfs_opterror(opts, | |
"name cannot be numeric (unless it is the jid)"); | |
@@ -1836,12 +1988,16 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
namelen = strlen(namelc); | |
if (pnamelen + namelen + 1 > sizeof(pr->pr_name)) { | |
error = ENAMETOOLONG; | |
+ if (bootverbose) | |
+ printf("jail: name too long for jail (error=%d)\n", error); | |
goto done_deref; | |
} | |
FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { | |
if (strlen(tpr->pr_name) + (namelen - onamelen) >= | |
sizeof(pr->pr_name)) { | |
error = ENAMETOOLONG; | |
+ if (bootverbose) | |
+ printf("jail: name too long for descendant jail (error=%d)\n", error); | |
goto done_deref; | |
} | |
} | |
@@ -1849,6 +2005,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
pr_allow_diff = pr_allow & ~ppr->pr_allow; | |
if (pr_allow_diff & ~PR_ALLOW_DIFFERENCES) { | |
error = EPERM; | |
+ if (bootverbose) | |
+ printf("jail: requested permissions not allowed by parent jail (error=%d)\n", error); | |
goto done_deref; | |
} | |
@@ -1860,14 +2018,19 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
mtx_unlock(&pr->pr_mtx); | |
drflags &= ~PD_LOCKED; | |
error = osd_jail_call(pr, PR_METHOD_CHECK, opts); | |
- if (error != 0) | |
+ if (error != 0) { | |
+ if (bootverbose) | |
+ printf("jail: module parameter check failed (error=%d)\n", error); | |
goto done_deref; | |
+ } | |
mtx_lock(&pr->pr_mtx); | |
drflags |= PD_LOCKED; | |
/* At this point, all valid parameters should have been noted. */ | |
TAILQ_FOREACH(opt, opts, link) { | |
if (!opt->seen && strcmp(opt->name, "errmsg")) { | |
+ if (bootverbose) | |
+ printf("jail: unknown parameter: %s\n", opt->name); | |
error = EINVAL; | |
vfs_opterror(opts, "unknown parameter: %s", opt->name); | |
goto done_deref; | |
@@ -2093,12 +2256,18 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) | |
/* Let the modules do their work. */ | |
if (created) { | |
error = osd_jail_call(pr, PR_METHOD_CREATE, opts); | |
- if (error) | |
+ if (error) { | |
+ if (bootverbose) | |
+ printf("jail: module create method failed (error=%d)\n", error); | |
goto done_deref; | |
+ } | |
} | |
error = osd_jail_call(pr, PR_METHOD_SET, opts); | |
- if (error) | |
+ if (error) { | |
+ if (bootverbose) | |
+ printf("jail: module set method failed (error=%d)\n", error); | |
goto done_deref; | |
+ } | |
/* | |
* A new prison is now ready to be seen; either it has gained a user | |
@@ -2304,16 +2473,22 @@ sys_jail_get(struct thread *td, struct jail_get_args *uap) | |
int error; | |
/* Check that we have an even number of iovecs. */ | |
- if (uap->iovcnt & 1) | |
+ if (uap->iovcnt & 1) { | |
+ if (bootverbose) | |
+ printf("jail_get: odd number of iovecs (error=%d)\n", EINVAL); | |
return (EINVAL); | |
+ } | |
error = copyinuio(uap->iovp, uap->iovcnt, &auio); | |
if (error) | |
return (error); | |
error = kern_jail_get(td, auio, uap->flags); | |
- if (error == 0) | |
+ if (error == 0) { | |
error = copyout(auio->uio_iov, uap->iovp, | |
uap->iovcnt * sizeof(struct iovec)); | |
+ if (error && bootverbose) | |
+ printf("jail: failed to get jail parameters (error=%d)\n", error); | |
+ } | |
freeuio(auio); | |
return (error); | |
} | |
@@ -2330,13 +2505,19 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags) | |
int drflags, error, errmsg_len, errmsg_pos, i, jid, len, pos; | |
unsigned f; | |
- if (flags & ~JAIL_GET_MASK) | |
+ if (flags & ~JAIL_GET_MASK) { | |
+ if (bootverbose) | |
+ printf("jail: invalid flags (error=EINVAL)\n"); | |
return (EINVAL); | |
+ } | |
/* Get the parameter list. */ | |
error = vfs_buildopts(optuio, &opts); | |
- if (error) | |
+ if (error) { | |
+ if (bootverbose) | |
+ printf("jail: failed to build options list (error=%d)\n", error); | |
return (error); | |
+ } | |
errmsg_pos = vfs_getopt_pos(opts, "errmsg"); | |
mypr = td->td_ucred->cr_prison; | |
pr = NULL; | |
@@ -2359,6 +2540,8 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags) | |
} | |
error = ENOENT; | |
vfs_opterror(opts, "no jail after %d", jid); | |
+ if (bootverbose) | |
+ printf("jail: no jail found after jid %d (error=%d)\n", jid, error); | |
goto done; | |
} else if (error != ENOENT) | |
goto done; | |
@@ -2374,12 +2557,16 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags) | |
error = ENOENT; | |
vfs_opterror(opts, "jail %d is dying", | |
jid); | |
+ if (bootverbose) | |
+ printf("jail: jail %d is dying (error=%d)\n", jid, error); | |
goto done; | |
} | |
goto found_prison; | |
} | |
error = ENOENT; | |
vfs_opterror(opts, "jail %d not found", jid); | |
+ if (bootverbose) | |
+ printf("jail: jail %d not found (error=%d)\n", jid, error); | |
goto done; | |
} | |
} else if (error != ENOENT) | |
@@ -2388,6 +2575,8 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags) | |
error = vfs_getopt(opts, "name", (void **)&name, &len); | |
if (error == 0) { | |
if (len == 0 || name[len - 1] != '\0') { | |
+ if (bootverbose) | |
+ printf("jail: invalid name parameter length or termination (error=EINVAL)\n"); | |
error = EINVAL; | |
goto done; | |
} | |
@@ -2553,6 +2742,8 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags) | |
/* By now, all parameters should have been noted. */ | |
TAILQ_FOREACH(opt, opts, link) { | |
if (!opt->seen && strcmp(opt->name, "errmsg")) { | |
+ if (bootverbose) | |
+ printf("jail: unknown parameter: %s\n", opt->name); | |
error = EINVAL; | |
vfs_opterror(opts, "unknown parameter: %s", opt->name); | |
goto done; | |
@@ -2574,8 +2765,11 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags) | |
error = copyout(opt->value, | |
optuio->uio_iov[pos].iov_base, | |
opt->len); | |
- if (error) | |
+ if (error) { | |
+ if (bootverbose) | |
+ printf("jail: failed to copy out parameter value (error=%d)\n", error); | |
break; | |
+ } | |
} | |
} | |
} | |
@@ -2618,12 +2812,17 @@ sys_jail_remove(struct thread *td, struct jail_remove_args *uap) | |
int error; | |
error = priv_check(td, PRIV_JAIL_REMOVE); | |
- if (error) | |
+ if (error) { | |
+ if (bootverbose) | |
+ printf("jail: insufficient privileges to remove jail (error=%d)\n", error); | |
return (error); | |
+ } | |
sx_xlock(&allprison_lock); | |
pr = prison_find_child(td->td_ucred->cr_prison, uap->jid); | |
if (pr == NULL) { | |
+ if (bootverbose) | |
+ printf("jail: jail %d not found for removal\n", uap->jid); | |
sx_xunlock(&allprison_lock); | |
return (EINVAL); | |
} | |
@@ -2649,18 +2848,25 @@ sys_jail_attach(struct thread *td, struct jail_attach_args *uap) | |
int error; | |
error = priv_check(td, PRIV_JAIL_ATTACH); | |
- if (error) | |
+ if (error) { | |
+ if (bootverbose) | |
+ printf("jail: insufficient privileges to attach to jail (error=%d)\n", error); | |
return (error); | |
+ } | |
sx_slock(&allprison_lock); | |
pr = prison_find_child(td->td_ucred->cr_prison, uap->jid); | |
if (pr == NULL) { | |
+ if (bootverbose) | |
+ printf("jail: jail %d not found for attachment (error=EINVAL)\n", uap->jid); | |
sx_sunlock(&allprison_lock); | |
return (EINVAL); | |
} | |
/* Do not allow a process to attach to a prison that is not alive. */ | |
if (!prison_isalive(pr)) { | |
+ if (bootverbose) | |
+ printf("jail: cannot attach to non-alive jail %d (error=EINVAL)\n", uap->jid); | |
mtx_unlock(&pr->pr_mtx); | |
sx_sunlock(&allprison_lock); | |
return (EINVAL); | |
@@ -2696,6 +2902,8 @@ do_jail_attach(struct thread *td, struct prison *pr, int drflags) | |
/* Let modules do whatever they need to prepare for attaching. */ | |
error = osd_jail_call(pr, PR_METHOD_ATTACH, td); | |
if (error) { | |
+ if (bootverbose) | |
+ printf("jail: module attachment preparation failed (error=%d)\n", error); | |
prison_deref(pr, drflags); | |
return (error); | |
} | |
@@ -2707,19 +2915,31 @@ do_jail_attach(struct thread *td, struct prison *pr, int drflags) | |
*/ | |
p = td->td_proc; | |
error = cpuset_setproc_update_set(p, pr->pr_cpuset); | |
- if (error) | |
+ if (error) { | |
+ if (bootverbose) | |
+ printf("jail: failed to update CPU set for jail (error=%d)\n", error); | |
goto e_revert_osd; | |
+ } | |
vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY); | |
- if ((error = change_dir(pr->pr_root, td)) != 0) | |
+ if ((error = change_dir(pr->pr_root, td)) != 0) { | |
+ if (bootverbose) | |
+ printf("jail: failed to change directory to jail root (error=%d)\n", error); | |
goto e_unlock; | |
+ } | |
#ifdef MAC | |
- if ((error = mac_vnode_check_chroot(td->td_ucred, pr->pr_root))) | |
+ if ((error = mac_vnode_check_chroot(td->td_ucred, pr->pr_root))) { | |
+ if (bootverbose) | |
+ printf("jail: MAC check failed for jail root (error=%d)\n", error); | |
goto e_unlock; | |
+ } | |
#endif | |
VOP_UNLOCK(pr->pr_root); | |
- if ((error = pwd_chroot_chdir(td, pr->pr_root))) | |
+ if ((error = pwd_chroot_chdir(td, pr->pr_root))) { | |
+ if (bootverbose) | |
+ printf("jail: failed to change process root directory (error=%d)\n", error); | |
goto e_revert_osd; | |
+ } | |
newcred = crget(); | |
PROC_LOCK(p); | |
@@ -2745,6 +2965,8 @@ do_jail_attach(struct thread *td, struct prison *pr, int drflags) | |
* with it. | |
*/ | |
if (!prison_isalive(pr)) { | |
+ if (bootverbose) | |
+ printf("jail: prison died during credential change, killing process (jid=%d)\n", pr->pr_id); | |
PROC_LOCK(p); | |
kern_psignal(p, SIGKILL); | |
PROC_UNLOCK(p); | |
@@ -2779,8 +3001,12 @@ prison_find(int prid) | |
break; | |
KASSERT(prison_isvalid(pr), ("Found invalid prison %p", pr)); | |
mtx_lock(&pr->pr_mtx); | |
+ if (bootverbose) | |
+ printf("jail: found prison %d\n", prid); | |
return (pr); | |
} | |
+ if (bootverbose) | |
+ printf("jail: prison %d not found\n", prid); | |
return (NULL); | |
} | |
@@ -2917,6 +3143,8 @@ prison_free(struct prison *pr) | |
* Don't remove the last reference in this context, | |
* in case there are locks held. | |
*/ | |
+ if (bootverbose) | |
+ printf("jail: scheduling deferred free for prison %d\n", pr->pr_id); | |
taskqueue_enqueue(taskqueue_jail_remove, &pr->pr_task); | |
} | |
} | |
@@ -2934,6 +3162,8 @@ prison_free_not_last(struct prison *pr) | |
KASSERT(!lastref, | |
("prison_free_not_last freed last ref on prison %p (jid=%d).", | |
pr, pr->pr_id)); | |
+ if (lastref && bootverbose) | |
+ printf("jail: prison_free_not_last unexpectedly freed last ref on prison %d\n", pr->pr_id); | |
#else | |
refcount_release(&pr->pr_ref); | |
#endif | |
@@ -3052,8 +3282,12 @@ prison_complete(void *context, int pending) | |
* This could be called to release the last reference, or the last | |
* user reference (plus the reference held in prison_proc_free). | |
*/ | |
+ if (bootverbose) | |
+ printf("jail: completing deferred free for prison %d\n", pr->pr_id); | |
drflags = prison_lock_xlock(pr, PD_DEREF); | |
if (pr->pr_flags & PR_COMPLETE_PROC) { | |
+ if (bootverbose) | |
+ printf("jail: completing process free for prison %d\n", pr->pr_id); | |
pr->pr_flags &= ~PR_COMPLETE_PROC; | |
drflags |= PD_DEUREF; | |
} | |
@@ -3469,8 +3703,11 @@ prison_check_af(struct ucred *cred, int af) | |
{ | |
mtx_lock(&pr->pr_mtx); | |
if ((pr->pr_flags & PR_IP4) && | |
- pr->pr_addrs[PR_INET] == NULL) | |
+ pr->pr_addrs[PR_INET] == NULL) { | |
error = EAFNOSUPPORT; | |
+ if (bootverbose) | |
+ printf("jail: IPv4 not supported in jail (error=%d)\n", error); | |
+ } | |
mtx_unlock(&pr->pr_mtx); | |
} | |
break; | |
@@ -3481,8 +3718,11 @@ prison_check_af(struct ucred *cred, int af) | |
{ | |
mtx_lock(&pr->pr_mtx); | |
if ((pr->pr_flags & PR_IP6) && | |
- pr->pr_addrs[PR_INET6] == NULL) | |
+ pr->pr_addrs[PR_INET6] == NULL) { | |
error = EAFNOSUPPORT; | |
+ if (bootverbose) | |
+ printf("jail: IPv6 not supported in jail (error=%d)\n", error); | |
+ } | |
mtx_unlock(&pr->pr_mtx); | |
} | |
break; | |
@@ -3492,8 +3732,11 @@ prison_check_af(struct ucred *cred, int af) | |
case AF_NETLINK: | |
break; | |
default: | |
- if (!(pr->pr_allow & PR_ALLOW_SOCKET_AF)) | |
+ if (!(pr->pr_allow & PR_ALLOW_SOCKET_AF)) { | |
error = EAFNOSUPPORT; | |
+ if (bootverbose) | |
+ printf("jail: address family not allowed in jail (error=%d)\n", error); | |
+ } | |
} | |
return (error); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
jail: module attachment preparation failed (error=22) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment