Refactor sys_jail() and fix bugs.
authorMichael Neumann <mneumann@ntecs.de>
Thu, 1 Jan 2009 18:24:10 +0000 (18:24 +0000)
committerMichael Neumann <mneumann@ntecs.de>
Thu, 1 Jan 2009 18:24:10 +0000 (18:24 +0000)
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

index b17f429..15e9456 100644 (file)
@@ -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);
 }
 
 /*