Now patch is attached:)

-- 
Pawel Jakub Dawidek
UNIX Systems Administrator
http://garage.freebsd.pl
Am I Evil? Yes, I Am.
diff -ru /usr/src/sys/kern/kern_jail.c ./sys/kern/kern_jail.c
--- /usr/src/sys/kern/kern_jail.c       Tue Jan 21 09:55:54 2003
+++ ./sys/kern/kern_jail.c      Mon Feb 17 07:11:42 2003
@@ -6,7 +6,7 @@
  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
  * ----------------------------------------------------------------------------
  *
- * $FreeBSD: src/sys/kern/kern_jail.c,v 1.29 2003/01/21 08:55:54 alfred Exp $
+ * $FreeBSD$
  *
  */
 
@@ -28,6 +28,14 @@
 
 MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
 
+#ifndef OLDJAIL
+SLIST_HEAD(, prison_children) prison_head =
+    SLIST_HEAD_INITIALIZER(&prison_head);
+struct mtx prison_head_mtx;
+MTX_SYSINIT(prison_head_lock, &prison_head_mtx, "prison_head mutex lock",
+    MTX_DEF);
+#endif
+
 SYSCTL_DECL(_security);
 SYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0,
     "Jail rules");
@@ -65,11 +73,18 @@
        struct jail j;
        struct chroot_args ca;
        struct ucred *newcred = NULL, *oldcred;
+#ifndef OLDJAIL
+       u_int i;
+#endif
 
        error = copyin(uap->jail, &j, sizeof j);
        if (error)
                return (error);
+#ifdef OLDJAIL
        if (j.version != 0)
+#else
+       if (j.version != 1)
+#endif
                return (EINVAL);
 
        MALLOC(pr, struct prison *, sizeof *pr , M_PRISON, M_ZERO);
@@ -85,12 +100,40 @@
        if (error)
                goto bail;
        newcred = crget();
+#ifdef OLDJAIL
        pr->pr_ip = j.ip_number;
+#else
+       MALLOC(pr->pr_ips, u_int32_t *, sizeof(u_int32_t) * j.nips, M_PRISON,
+           0);
+       error = copyin(j.ips, pr->pr_ips, sizeof(u_int32_t) * j.nips);
+       if (error) {
+               FREE(pr->pr_ips, M_PRISON);
+               goto bail;
+       }
+       if (jailed(p->p_ucred)) {
+               for (i = 0; i < j.nips; ++i) {
+                       if (!prison_validip(p->p_ucred, pr->pr_ips[i])) {
+                               error = EINVAL;
+                               FREE(pr->pr_ips, M_PRISON);
+                               goto bail;
+                       }
+               }
+       }
+       pr->pr_nips = j.nips;
+#endif
+
+#ifdef OLDJAIL
        PROC_LOCK(p);
        /* Implicitly fail if already in jail.  */
        error = suser_cred(p->p_ucred, 0);
        if (error)
                goto badcred;
+#else
+       pr->pr_pprison = p->p_ucred->cr_prison;
+       SLIST_INIT(&pr->pr_children);
+       prison_addchild(p->p_ucred->cr_prison, pr);
+       PROC_LOCK(p);
+#endif
        oldcred = p->p_ucred;
        crcopy(newcred, oldcred);
        p->p_ucred = newcred;
@@ -99,7 +142,9 @@
        PROC_UNLOCK(p);
        crfree(oldcred);
        return (0);
+#ifdef OLDJAIL
 badcred:
+#endif
        PROC_UNLOCK(p);
        crfree(newcred);
 bail:
@@ -111,14 +156,56 @@
 void
 prison_free(struct prison *pr)
 {
+#ifndef OLDJAIL
+       struct prison_children *pc;
+       struct prison *ppr;
+#endif
 
        mtx_lock(&pr->pr_mtx);
        pr->pr_ref--;
        if (pr->pr_ref == 0) {
+#ifndef OLDJAIL
+               ppr = pr->pr_pprison;
+               pc = NULL;
+               if (ppr == NULL) {
+                       mtx_lock(&prison_head_mtx);
+                       SLIST_FOREACH(pc, &prison_head, pc_next) {
+                               if (pc->pc_child == pr)
+                                       break;
+                       }
+                       SLIST_REMOVE(&prison_head, pc, prison_children,
+                           pc_next);
+               } else {
+                       SLIST_FOREACH(pc, &ppr->pr_children, pc_next) {
+                               if (pc->pc_child == pr)
+                                       break;
+                       }
+                       SLIST_REMOVE(&ppr->pr_children, pc, prison_children,
+                           pc_next);
+               }
+               KASSERT(pc != NULL, ("Child have to be on list."));
+               FREE(pc, M_PRISON);
+               SLIST_FOREACH(pc, &pr->pr_children, pc_next) {
+                       mtx_lock(&pc->pc_child->pr_mtx);
+                       pc->pc_child->pr_pprison = ppr;
+                       mtx_unlock(&pc->pc_child->pr_mtx);
+                       if (ppr == NULL)
+                               SLIST_INSERT_HEAD(&prison_head, pc, pc_next);
+                       else {
+                               SLIST_INSERT_HEAD(&ppr->pr_children, pc,
+                                   pc_next);
+                       }
+               }
+               if (ppr == NULL)
+                       mtx_unlock(&prison_head_mtx);
+#endif /* !OLDJAIL */
                mtx_unlock(&pr->pr_mtx);
                mtx_destroy(&pr->pr_mtx);
                if (pr->pr_linux != NULL)
                        FREE(pr->pr_linux, M_PRISON);
+#ifndef OLDJAIL
+               FREE(pr->pr_ips, M_PRISON);
+#endif
                FREE(pr, M_PRISON);
                return;
        }
@@ -138,7 +225,36 @@
 prison_getip(struct ucred *cred)
 {
 
+#ifdef OLDJAIL
        return (cred->cr_prison->pr_ip);
+#else
+       return (cred->cr_prison->pr_ips[0]);
+#endif
+
+}
+
+/*
+ * Returns 1 if IP belongs to prison, otherwise 0.
+ */
+int
+prison_validip(struct ucred *cred, u_int32_t ip)
+{
+#ifndef OLDJAIL
+       register struct prison *pr;
+       register u_int i;
+#endif
+
+#ifdef OLDJAIL
+       return (cred->cr_prison->pr_ip == ip);
+#else
+       pr = cred->cr_prison;
+       for (i = 0; i < pr->pr_nips; ++i) {
+               if (ip == pr->pr_ips[i])
+                       return (1);
+       }
+
+       return (0);
+#endif
 }
 
 int
@@ -152,23 +268,14 @@
                tmp = *ip;
        else
                tmp = ntohl(*ip);
-       if (tmp == INADDR_ANY) {
+       if (tmp == INADDR_ANY || tmp == INADDR_LOOPBACK) {
                if (flag) 
-                       *ip = cred->cr_prison->pr_ip;
+                       *ip = prison_getip(cred);
                else
-                       *ip = htonl(cred->cr_prison->pr_ip);
+                       *ip = htonl(prison_getip(cred));
                return (0);
        }
-       if (tmp == INADDR_LOOPBACK) {
-               if (flag)
-                       *ip = cred->cr_prison->pr_ip;
-               else
-                       *ip = htonl(cred->cr_prison->pr_ip);
-               return (0);
-       }
-       if (cred->cr_prison->pr_ip != tmp)
-               return (1);
-       return (0);
+       return (!prison_validip(cred, tmp));
 }
 
 void
@@ -184,9 +291,9 @@
                tmp = ntohl(*ip);
        if (tmp == INADDR_LOOPBACK) {
                if (flag)
-                       *ip = cred->cr_prison->pr_ip;
+                       *ip = prison_getip(cred);
                else
-                       *ip = htonl(cred->cr_prison->pr_ip);
+                       *ip = htonl(prison_getip(cred));
                return;
        }
        return;
@@ -202,7 +309,7 @@
                ok = 1;
        else if (sai->sin_family != AF_INET)
                ok = 0;
-       else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr))
+       else if (!prison_validip(cred, ntohl(sai->sin_addr.s_addr)))
                ok = 1;
        else
                ok = 0;
@@ -217,14 +324,17 @@
        struct ucred *cred1, *cred2;
 {
 
-       if (jailed(cred1)) {
-               if (!jailed(cred2))
-                       return (ESRCH);
-               if (cred2->cr_prison != cred1->cr_prison)
-                       return (ESRCH);
-       }
-
-       return (0);
+       if (!jailed(cred1))
+               return (0);
+       if (!jailed(cred2))
+               return (ESRCH);
+       if (cred2->cr_prison == cred1->cr_prison)
+               return (0);
+#ifndef OLDJAIL
+       if (prison_ischild(cred1->cr_prison, cred2->cr_prison))
+               return (0);
+#endif
+       return (ESRCH);
 }
 
 /*
@@ -256,3 +366,52 @@
        else
                strlcpy(buf, hostname, size);
 }
+
+int
+prison_maxseclvl(int seclvl, register struct prison *pr)
+{
+
+#ifndef OLDJAIL
+       for (; pr != NULL; pr = pr->pr_pprison)
+               seclvl = imax(seclvl, pr->pr_securelevel);
+       return (seclvl);
+#else
+       return (imax(seclvl, pr->pr_securelevel));
+#endif
+}
+
+#ifndef OLDJAIL
+void
+prison_addchild(struct prison *parent, struct prison *child)
+{
+       struct prison_children *pc;
+
+       MALLOC(pc, struct prison_children *, sizeof *pc , M_PRISON, M_ZERO);
+       pc->pc_child = child;
+       if (parent == NULL) {
+               mtx_lock(&prison_head_mtx);
+               SLIST_INSERT_HEAD(&prison_head, pc, pc_next);
+               mtx_unlock(&prison_head_mtx);
+               return;
+       }
+       mtx_lock(&parent->pr_mtx);
+       SLIST_INSERT_HEAD(&parent->pr_children, pc, pc_next);
+       mtx_unlock(&parent->pr_mtx);
+}
+
+/*
+ * Returns 1 if pr2 is a child of pr1, otherwise 0.
+ */
+int
+prison_ischild(register struct prison *pr1, register struct prison *pr2)
+{
+
+       for (pr2 = pr2->pr_pprison; pr2 != NULL; pr2 = pr2->pr_pprison) {
+               if (pr1 == pr2)
+                       return (1);
+       }
+
+       return (0);
+
+}
+#endif
diff -ru /usr/src/sys/kern/kern_mib.c ./sys/kern/kern_mib.c
--- /usr/src/sys/kern/kern_mib.c        Sun Jan  5 04:48:14 2003
+++ ./sys/kern/kern_mib.c       Mon Feb 17 05:51:16 2003
@@ -37,7 +37,7 @@
  * SUCH DAMAGE.
  *
  *     @(#)kern_sysctl.c       8.4 (Berkeley) 4/14/94
- * $FreeBSD: src/sys/kern/kern_mib.c,v 1.64 2003/01/05 03:48:14 jake Exp $
+ * $FreeBSD$
  */
 
 #include "opt_posix.h"
@@ -248,12 +248,12 @@
         * If the process is in jail, return the maximum of the global and
         * local levels; otherwise, return the global level.
         */
+       level = securelevel;
        if (pr != NULL) {
                mtx_lock(&pr->pr_mtx);
-               level = imax(securelevel, pr->pr_securelevel);
+               level = prison_maxseclvl(level, pr);
                mtx_unlock(&pr->pr_mtx);
-       } else
-               level = securelevel;
+       }
        error = sysctl_handle_int(oidp, &level, 0, req);
        if (error || !req->newptr)
                return (error);
@@ -264,7 +264,7 @@
        if (pr != NULL) {
                mtx_lock(&pr->pr_mtx);
                if (!regression_securelevel_nonmonotonic &&
-                   (level < imax(securelevel, pr->pr_securelevel))) {
+                   (level < prison_maxseclvl(securelevel, pr))) {
                        mtx_unlock(&pr->pr_mtx);
                        return (EPERM);
                }
diff -ru /usr/src/sys/kern/kern_prot.c ./sys/kern/kern_prot.c
--- /usr/src/sys/kern/kern_prot.c       Mon Feb 10 05:42:20 2003
+++ ./sys/kern/kern_prot.c      Mon Feb 17 05:51:16 2003
@@ -37,7 +37,7 @@
  * SUCH DAMAGE.
  *
  *     @(#)kern_prot.c 8.6 (Berkeley) 1/21/94
- * $FreeBSD: src/sys/kern/kern_prot.c,v 1.166 2003/02/10 04:42:20 jake Exp $
+ * $FreeBSD$
  */
 
 /*
@@ -1303,8 +1303,8 @@
        KASSERT(cr != NULL, ("securelevel_gt: null cr"));
        if (cr->cr_prison != NULL) {
                mtx_lock(&cr->cr_prison->pr_mtx);
-               active_securelevel = imax(cr->cr_prison->pr_securelevel,
-                   active_securelevel);
+               active_securelevel = prison_maxseclvl(active_securelevel,
+                   cr->cr_prison);
                mtx_unlock(&cr->cr_prison->pr_mtx);
        }
        return (active_securelevel > level ? EPERM : 0);
@@ -1319,8 +1319,8 @@
        KASSERT(cr != NULL, ("securelevel_ge: null cr"));
        if (cr->cr_prison != NULL) {
                mtx_lock(&cr->cr_prison->pr_mtx);
-               active_securelevel = imax(cr->cr_prison->pr_securelevel,
-                   active_securelevel);
+               active_securelevel = prison_maxseclvl(active_securelevel,
+                   cr->cr_prison);
                mtx_unlock(&cr->cr_prison->pr_mtx);
        }
        return (active_securelevel >= level ? EPERM : 0);
diff -ru /usr/src/sys/netinet/in_pcb.c ./sys/netinet/in_pcb.c
--- /usr/src/sys/netinet/in_pcb.c       Thu Feb 13 00:55:07 2003
+++ ./sys/netinet/in_pcb.c      Mon Feb 17 05:51:16 2003
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     @(#)in_pcb.c    8.4 (Berkeley) 5/24/95
- * $FreeBSD: src/sys/netinet/in_pcb.c,v 1.117 2003/02/12 23:55:07 hsu Exp $
+ * $FreeBSD$
  */
 
 #include "opt_ipsec.h"
@@ -1142,7 +1142,7 @@
 {
        if (!jailed(td->td_ucred))
                return (0);
-       if (ntohl(inp->inp_laddr.s_addr) == prison_getip(td->td_ucred))
+       if (prison_validip(td->td_ucred, ntohl(inp->inp_laddr.s_addr)))
                return (0);
        return (1);
 }
diff -ru /usr/src/sys/sys/jail.h ./sys/sys/jail.h
--- /usr/src/sys/sys/jail.h     Mon May  6 05:13:08 2002
+++ ./sys/sys/jail.h    Mon Feb 17 07:02:24 2003
@@ -6,7 +6,7 @@
  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
  * ----------------------------------------------------------------------------
  *
- * $FreeBSD: src/sys/sys/jail.h,v 1.17 2002/05/06 03:13:08 bde Exp $
+ * $FreeBSD$
  *
  */
 
@@ -17,7 +17,12 @@
        u_int32_t       version;
        char            *path;
        char            *hostname;
+#ifdef OLDJAIL
        u_int32_t       ip_number;
+#else
+       u_int32_t       *ips;
+       size_t          nips;
+#endif
 };
 
 #ifndef _KERNEL
@@ -34,6 +39,14 @@
 MALLOC_DECLARE(M_PRISON);
 #endif
 
+#ifndef OLDJAIL
+struct prison;
+struct prison_children {
+       struct prison   *pc_child;
+       SLIST_ENTRY(prison_children) pc_next;
+};
+#endif
+
 /*
  * This structure describes a prison.  It is pointed to by all struct
  * ucreds's of the inmates.  pr_ref keeps track of them and is used to
@@ -48,9 +61,18 @@
 struct prison {
        int              pr_ref;                        /* (p) refcount */
        char             pr_host[MAXHOSTNAMELEN];       /* (p) jail hostname */
+#ifdef OLDJAIL
        u_int32_t        pr_ip;                         /* (c) ip addr host */
+#else
+       size_t           pr_nips;                       /* numer of ips in table */
+       u_int32_t       *pr_ips;                        /* table with ips */
+#endif
        void            *pr_linux;                      /* (p) linux abi */
        int              pr_securelevel;                /* (p) securelevel */
+#ifndef OLDJAIL
+       struct prison   *pr_pprison;                    /* parent prison */
+       SLIST_HEAD(, prison_children) pr_children;      /* prison's children */
+#endif
        struct mtx       pr_mtx;
 };
 
@@ -77,6 +99,12 @@
 int prison_if(struct ucred *cred, struct sockaddr *sa);
 int prison_ip(struct ucred *cred, int flag, u_int32_t *ip);
 void prison_remote_ip(struct ucred *cred, int flags, u_int32_t *ip);
+int prison_maxseclvl(int seclvl, register struct prison *pr);
+int prison_validip(struct ucred *cred, u_int32_t ip);
+#ifndef OLDJAIL
+void prison_addchild(struct prison *parent, struct prison *child);
+int prison_ischild(register struct prison *pr1, register struct prison *pr2);
+#endif
 
 #endif /* !_KERNEL */
 #endif /* !_SYS_JAIL_H_ */
diff -ru /usr/src/usr.sbin/jail/jail.c ./usr.sbin/jail/jail.c
--- /usr/src/usr.sbin/jail/jail.c       Mon Apr 22 15:44:43 2002
+++ ./usr.sbin/jail/jail.c      Mon Feb 17 05:53:39 2003
@@ -6,7 +6,7 @@
  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
  * ----------------------------------------------------------------------------
  * 
- * $FreeBSD: src/usr.sbin/jail/jail.c,v 1.8 2002/04/22 13:44:43 des Exp $
+ * $FreeBSD$
  * 
  */
 
@@ -27,22 +27,55 @@
 {
        struct jail j;
        int i;
+#ifndef OLDJAIL
+       int c;
+#endif
        struct in_addr in;
 
-       if (argc < 5) 
+       if (argc < 5)  {
+#ifdef OLDJAIL
                errx(1, "usage: %s path hostname ip-number command ...\n",
                    argv[0]);
+#else
+               errx(1, "Usage: %s path hostname ip1[,ip2[...]] command ...\n",
+                   argv[0]);
+#endif
+       }
        i = chdir(argv[1]);
        if (i)
                err(1, "chdir %s", argv[1]);
        memset(&j, 0, sizeof(j));
+#ifdef OLDJAIL
        j.version = 0;
+#else
+       j.version = 1;
+#endif
        j.path = argv[1];
        j.hostname = argv[2];
+#ifdef OLDJAIL
        i = inet_aton(argv[3], &in);
        if (!i)
                errx(1, "Couldn't make sense of ip-number\n");
        j.ip_number = ntohl(in.s_addr);
+#else
+       for (c = 1, ip = argv[3]; *ip; ++ip) {
+               if (*ip == ',')
+                       ++c;
+       }
+       if ((j.ips = (u_int32_t *)malloc(sizeof(u_int32_t) * c)) == NULL)
+               errx(1, "malloc()");
+
+       for (c = 0, ip = strtok(argv[3], ","); ip;
+           ++c, ip = strtok(NULL, ",")) {
+               i = inet_aton(ip, &in);
+               if (!i) {
+                       free(j.ips);
+                       errx(1, "Couldn't make sense of ip-number\n");
+               }
+               j.ips[c] = ntohl(in.s_addr);
+       }
+       j.nips = c;
+#endif /* !OLDJAIL */
        i = jail(&j);
        if (i)
                err(1, "Imprisonment failed");

Attachment: msg39977/pgp00000.pgp
Description: PGP signature

Reply via email to