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");
msg39977/pgp00000.pgp
Description: PGP signature