From 5825b2265ea18876420a0aa5e62216a0592b0065 Mon Sep 17 00:00:00 2001 From: Michael Neumann Date: Thu, 1 Jan 2009 18:24:10 +0000 Subject: [PATCH] Refactor sys_jail() and fix bugs. Fixes two issues: * uap->sysmsg_result was not consistently assigned -1 in case of an error. * A version 0 syscall triggered a copyinstr(j.hostname, ...) on an uninitialized struct jail j. --- sys/kern/kern_jail.c | 170 +++++++++++++++++++++++++------------------ 1 file changed, 99 insertions(+), 71 deletions(-) diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index b17f4290c4..15e94565da 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -122,6 +122,70 @@ kern_jail_attach(int jid) return(0); } +static int +assign_prison_id(struct prison *pr) +{ + int tryprid; + struct prison *tpr; + + tryprid = lastprid + 1; + if (tryprid == JAIL_MAX) + tryprid = 1; +next: + LIST_FOREACH(tpr, &allprison, pr_list) { + if (tpr->pr_id != tryprid) + continue; + tryprid++; + if (tryprid == JAIL_MAX) { + return (ERANGE); + } + goto next; + } + pr->pr_id = lastprid = tryprid; + + return (0); +} + +static int +kern_jail(struct prison *pr, struct jail *j) +{ + int error; + struct nlookupdata nd; + + error = nlookup_init(&nd, j->path, UIO_USERSPACE, NLC_FOLLOW); + if (error) { + nlookup_done(&nd); + return (error); + } + error = nlookup(&nd); + if (error) { + nlookup_done(&nd); + return (error); + } + cache_copy(&nd.nl_nch, &pr->pr_root); + + varsymset_init(&pr->pr_varsymset, NULL); + prison_ipcache_init(pr); + + error = assign_prison_id(pr); + if (error) { + varsymset_clean(&pr->pr_varsymset); + nlookup_done(&nd); + return (error); + } + + LIST_INSERT_HEAD(&allprison, pr, pr_list); + prisoncount++; + + error = kern_jail_attach(pr->pr_id); + if (error) { + LIST_REMOVE(pr, pr_list); + varsymset_clean(&pr->pr_varsymset); + } + nlookup_done(&nd); + return (error); +} + /* * jail() * @@ -130,45 +194,48 @@ kern_jail_attach(int jid) int sys_jail(struct jail_args *uap) { - struct prison *pr, *tpr; - struct jail j; - struct jail_v0 jv0; struct thread *td = curthread; - int error, tryprid, i; - uint32_t jversion; - struct nlookupdata nd; - /* Multiip */ - struct sockaddr_storage *uips; /* Userland ips */ - struct sockaddr_in ip4addr; + struct prison *pr; struct jail_ip_storage *jip; - /* Multiip */ + struct jail j; + int error; + uint32_t jversion; + + uap->sysmsg_result = -1; error = priv_check(td, PRIV_ROOT); - if (error) { - uap->sysmsg_result = -1; + if (error) return (error); - } + error = copyin(uap->jail, &jversion, sizeof(jversion)); - if (error) { - uap->sysmsg_result = -1; + if (error) return (error); - } + pr = kmalloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO); SLIST_INIT(&pr->pr_ips); switch (jversion) { case 0: /* Single IPv4 jails. */ - + { + struct jail_v0 jv0; + struct sockaddr_in ip4addr; + error = copyin(uap->jail, &jv0, sizeof(jv0)); if (error) - goto bail; + goto out; + + j.path = jv0.path; + j.hostname = jv0.hostname; + jip = kmalloc(sizeof(*jip), M_PRISON, M_WAITOK | M_ZERO); ip4addr.sin_family = AF_INET; ip4addr.sin_addr.s_addr = htonl(jv0.ip_number); memcpy(&jip->ip, &ip4addr, sizeof(ip4addr)); SLIST_INSERT_HEAD(&pr->pr_ips, jip, entries); break; + } + case 1: /* * DragonFly multi noIP/IPv4/IPv6 jails @@ -179,74 +246,35 @@ sys_jail(struct jail_args *uap) error = copyin(uap->jail, &j, sizeof(j)); if (error) - goto bail; - uips = kmalloc((sizeof(*uips) * j.n_ips), M_PRISON, - M_WAITOK | M_ZERO); - error = copyin(j.ips, uips, (sizeof(*uips) * j.n_ips)); - if (error) { - kfree(uips, M_PRISON); - goto bail; - } - for (i = 0; i < j.n_ips; i++) { - jip = kmalloc(sizeof(*jip), M_PRISON, + goto out; + + for (int i = 0; i < j.n_ips; i++) { + jip = kmalloc(sizeof(*jip), M_PRISON, M_WAITOK | M_ZERO); - memcpy(&jip->ip, &uips[i], sizeof(*uips)); SLIST_INSERT_HEAD(&pr->pr_ips, jip, entries); + error = copyin(&j.ips[i], &jip->ip, + sizeof(struct sockaddr_storage)); + if (error) + goto out; } - kfree(uips, M_PRISON); break; default: error = EINVAL; - goto bail; + goto out; } error = copyinstr(j.hostname, &pr->pr_host, sizeof(pr->pr_host), 0); if (error) - goto bail; - error = nlookup_init(&nd, j.path, UIO_USERSPACE, NLC_FOLLOW); - if (error) - goto nlookup_init_clean; - error = nlookup(&nd); - if (error) - goto nlookup_init_clean; - cache_copy(&nd.nl_nch, &pr->pr_root); + goto out; - varsymset_init(&pr->pr_varsymset, NULL); - prison_ipcache_init(pr); - - tryprid = lastprid + 1; - if (tryprid == JAIL_MAX) - tryprid = 1; -next: - LIST_FOREACH(tpr, &allprison, pr_list) { - if (tpr->pr_id != tryprid) - continue; - tryprid++; - if (tryprid == JAIL_MAX) { - error = ERANGE; - goto varsym_clean; - } - goto next; - } - pr->pr_id = lastprid = tryprid; - LIST_INSERT_HEAD(&allprison, pr, pr_list); - prisoncount++; - - error = kern_jail_attach(pr->pr_id); + error = kern_jail(pr, &j); if (error) - goto jail_attach_clean; + goto out; - nlookup_done(&nd); uap->sysmsg_result = pr->pr_id; return (0); -jail_attach_clean: - LIST_REMOVE(pr, pr_list); -varsym_clean: - varsymset_clean(&pr->pr_varsymset); -nlookup_init_clean: - nlookup_done(&nd); -bail: +out: /* Delete all ips */ while (!SLIST_EMPTY(&pr->pr_ips)) { jip = SLIST_FIRST(&pr->pr_ips); @@ -254,7 +282,7 @@ bail: kfree(jip, M_PRISON); } kfree(pr, M_PRISON); - return(error); + return (error); } /* -- 2.41.0