--- sys/kern/kern_jail.c.orig Sun Jun 27 11:03:21 2004 +++ sys/kern/kern_jail.c Mon Nov 15 13:41:14 2004 @@ -107,7 +107,7 @@ error = copyin(uap->jail, &j, sizeof(j)); if (error) return (error); - if (j.version != 0) + if (j.version != 1) return (EINVAL); MALLOC(pr, struct prison *, sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO); @@ -130,7 +130,14 @@ error = copyinstr(j.hostname, &pr->pr_host, sizeof(pr->pr_host), 0); if (error) goto e_dropvnref; - pr->pr_ip = j.ip_number; + if (j.nips >= JAIL_MAX_IPS) + goto e_dropvnref; + MALLOC(pr->pr_ips, u_int32_t *, sizeof(u_int32_t) * j.nips, + M_PRISON, M_WAITOK); + error = copyin(j.ips, pr->pr_ips, sizeof(u_int32_t) * j.nips); + if (error) + goto e_freeips; + pr->pr_nips = j.nips; pr->pr_linux = NULL; pr->pr_securelevel = securelevel; @@ -146,7 +153,7 @@ if (tryprid == JAIL_MAX) { mtx_unlock(&allprison_mtx); error = EAGAIN; - goto e_dropvnref; + goto e_freeips; } goto next; } @@ -169,6 +176,8 @@ LIST_REMOVE(pr, pr_list); prisoncount--; mtx_unlock(&allprison_mtx); +e_freeips: + FREE(pr->pr_ips, M_PRISON); e_dropvnref: mtx_lock(&Giant); vrele(pr->pr_root); @@ -301,6 +310,7 @@ mtx_destroy(&pr->pr_mtx); if (pr->pr_linux != NULL) FREE(pr->pr_linux, M_PRISON); + FREE(pr->pr_ips, M_PRISON); FREE(pr, M_PRISON); } @@ -317,9 +327,10 @@ prison_getip(struct ucred *cred) { - return (cred->cr_prison->pr_ip); + return (cred->cr_prison->pr_ips[0]); } + int prison_ip(struct ucred *cred, int flag, u_int32_t *ip) { @@ -331,23 +342,16 @@ tmp = *ip; else tmp = ntohl(*ip); - if (tmp == INADDR_ANY) { - if (flag) - *ip = cred->cr_prison->pr_ip; - else - *ip = htonl(cred->cr_prison->pr_ip); - return (0); - } if (tmp == INADDR_LOOPBACK) { if (flag) - *ip = cred->cr_prison->pr_ip; + *ip = cred->cr_prison->pr_ips[0]; else - *ip = htonl(cred->cr_prison->pr_ip); + *ip = htonl(cred->cr_prison->pr_ips[0]); return (0); } - if (cred->cr_prison->pr_ip != tmp) - return (1); - return (0); + if (tmp == INADDR_ANY || jailed_ip(cred, tmp)) + return (0); + return (1); } void @@ -363,9 +367,9 @@ tmp = ntohl(*ip); if (tmp == INADDR_LOOPBACK) { if (flag) - *ip = cred->cr_prison->pr_ip; + *ip = cred->cr_prison->pr_ips[0]; else - *ip = htonl(cred->cr_prison->pr_ip); + *ip = htonl(cred->cr_prison->pr_ips[0]); return; } return; @@ -382,13 +386,31 @@ 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 (!jailed_ip(cred, ntohl(sai->sin_addr.s_addr))) ok = 1; else ok = 0; return (ok); } +int +jailed_ip(struct ucred *cred, u_int32_t ip) +{ + register struct prison *pr; + register u_int i; + + if (!jailed(cred)) + return(1); + + pr = cred->cr_prison; + for (i = 0; i < pr->pr_nips; ++i) { + if (pr->pr_ips[i] == ip) + return (1); + } + + return (0); +} + /* * Return 0 if jails permit p1 to frob p2, otherwise ESRCH. */ @@ -478,7 +500,8 @@ xp->pr_id = pr->pr_id; strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path)); strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host)); - xp->pr_ip = pr->pr_ip; + memcpy(xp->pr_ips, pr->pr_ips, sizeof(u_int32_t) * pr->pr_nips); + xp->pr_nips = pr->pr_nips; mtx_unlock(&pr->pr_mtx); xp++; } --- sys/netinet/in_pcb.c.orig Thu Oct 21 11:30:47 2004 +++ sys/netinet/in_pcb.c Mon Nov 15 13:54:02 2004 @@ -265,7 +265,7 @@ struct in_addr laddr; u_short lport = 0; int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); - int error, prison = 0; + int error; INP_INFO_WLOCK_ASSERT(pcbinfo); INP_LOCK_ASSERT(inp); @@ -289,9 +289,8 @@ if (sin->sin_family != AF_INET) return (EAFNOSUPPORT); #endif - if (sin->sin_addr.s_addr != INADDR_ANY) - if (prison_ip(cred, 0, &sin->sin_addr.s_addr)) - return(EINVAL); + if (cred && prison_ip(cred, 0, &sin->sin_addr.s_addr)) + return(EINVAL); if (sin->sin_port != *lportp) { /* Don't allow the port to change. */ if (*lportp != 0) @@ -323,13 +322,11 @@ ntohs(lport) >= ipport_reservedlow && suser_cred(cred, SUSER_ALLOWJAIL)) return (EACCES); - if (jailed(cred)) - prison = 1; + /* mijail5 patch failed - guy */ if (so->so_cred->cr_uid != 0 && !IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { - t = in_pcblookup_local(inp->inp_pcbinfo, - sin->sin_addr, lport, - prison ? 0 : INPLOOKUP_WILDCARD); + t = in_pcblookup_local(cred, inp->inp_pcbinfo, + sin->sin_addr, lport, INPLOOKUP_WILDCARD); /* * XXX * This entire block sorely needs a rewrite. @@ -346,10 +343,10 @@ t->inp_socket->so_cred->cr_uid)) return (EADDRINUSE); } - if (prison && prison_ip(cred, 0, &sin->sin_addr.s_addr)) + if (cred && prison_ip(cred, 0, &sin->sin_addr.s_addr)) return (EADDRNOTAVAIL); - t = in_pcblookup_local(pcbinfo, sin->sin_addr, - lport, prison ? 0 : wild); + t = in_pcblookup_local(cred, pcbinfo, sin->sin_addr, + lport, wild); if (t && (t->inp_vflag & INP_TIMEWAIT)) { if ((reuseport & intotw(t)->tw_so_options) == 0) return (EADDRINUSE); @@ -374,15 +371,15 @@ u_short first, last; int count; - if (laddr.s_addr != INADDR_ANY) - if (prison_ip(cred, 0, &laddr.s_addr)) - return (EINVAL); + if (cred && prison_ip(cred, 0, &laddr.s_addr)) + return (EINVAL); if (inp->inp_flags & INP_HIGHPORT) { first = ipport_hifirstauto; /* sysctl */ last = ipport_hilastauto; lastport = &pcbinfo->lasthi; } else if (inp->inp_flags & INP_LOWPORT) { + /* mijail5 patch failed - guy */ if ((error = suser_cred(cred, SUSER_ALLOWJAIL)) != 0) return error; first = ipport_lowfirstauto; /* 1023 */ @@ -416,7 +413,7 @@ if (*lastport > first || *lastport < last) *lastport = first; lport = htons(*lastport); - } while (in_pcblookup_local(pcbinfo, laddr, lport, + } while (in_pcblookup_local(cred, pcbinfo, laddr, lport, wild)); } else { /* @@ -434,11 +431,11 @@ if (*lastport < first || *lastport > last) *lastport = first; lport = htons(*lastport); - } while (in_pcblookup_local(pcbinfo, laddr, lport, + } while (in_pcblookup_local(cred, pcbinfo, laddr, lport, wild)); } } - if (prison_ip(cred, 0, &laddr.s_addr)) + if (cred && prison_ip(cred, 0, &laddr.s_addr)) return (EINVAL); *laddrp = laddr.s_addr; *lportp = lport; @@ -527,7 +524,7 @@ struct sockaddr_in *sin = (struct sockaddr_in *)nam; struct in_ifaddr *ia; struct sockaddr_in sa; - struct ucred *socred; + struct ucred *socred = NULL; struct inpcb *oinp; struct in_addr laddr, faddr; u_short lport, fport; @@ -548,17 +545,8 @@ lport = *lportp; faddr = sin->sin_addr; fport = sin->sin_port; - socred = inp->inp_socket->so_cred; - if (laddr.s_addr == INADDR_ANY && jailed(socred)) { - bzero(&sa, sizeof(sa)); - sa.sin_addr.s_addr = htonl(prison_getip(socred)); - sa.sin_len = sizeof(sa); - sa.sin_family = AF_INET; - error = in_pcbbind_setup(inp, (struct sockaddr *)&sa, - &laddr.s_addr, &lport, cred); - if (error) - return (error); - } + if (inp->inp_socket != NULL) + socred = inp->inp_socket->so_cred; if (!TAILQ_EMPTY(&in_ifaddrhead)) { /* * If the destination address is INADDR_ANY, @@ -567,9 +555,12 @@ * and the primary interface supports broadcast, * choose the broadcast address for that interface. */ - if (faddr.s_addr == INADDR_ANY) - faddr = IA_SIN(TAILQ_FIRST(&in_ifaddrhead))->sin_addr; - else if (faddr.s_addr == (u_long)INADDR_BROADCAST && + if (faddr.s_addr == INADDR_ANY) { + if (cred != NULL && jailed(cred)) + faddr.s_addr = htonl(cred->cr_prison->pr_ips[0]); + else + faddr = IA_SIN(TAILQ_FIRST(&in_ifaddrhead))->sin_addr; + } else if (faddr.s_addr == (u_long)INADDR_BROADCAST && (TAILQ_FIRST(&in_ifaddrhead)->ia_ifp->if_flags & IFF_BROADCAST)) faddr = satosin(&TAILQ_FIRST( @@ -873,7 +864,8 @@ * Lookup a PCB based on the local address and port. */ struct inpcb * -in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) +in_pcblookup_local(cred, pcbinfo, laddr, lport_arg, wild_okay) + struct ucred *cred; struct inpcbinfo *pcbinfo; struct in_addr laddr; u_int lport_arg; @@ -897,13 +889,24 @@ if ((inp->inp_vflag & INP_IPV4) == 0) continue; #endif + if (cred != NULL && inp->inp_socket != NULL && + inp->inp_socket->so_cred->cr_prison != + cred->cr_prison) { + continue; + } if (inp->inp_faddr.s_addr == INADDR_ANY && inp->inp_laddr.s_addr == laddr.s_addr && inp->inp_lport == lport) { /* * Found. */ - return (inp); + /* Those values could be NULL, really. */ + if (inp->inp_socket == NULL || cred == NULL) + return (inp); + if (inp->inp_socket->so_cred->cr_prison == + cred->cr_prison) { + return (inp); + } } } /* @@ -978,8 +981,7 @@ * Lookup PCB in hash list. */ struct inpcb * -in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, - ifp) +in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp) struct inpcbinfo *pcbinfo; struct in_addr faddr, laddr; u_int fport_arg, lport_arg; @@ -987,7 +989,7 @@ struct ifnet *ifp; { struct inpcbhead *head; - register struct inpcb *inp; + register struct inpcb *inp, *jinp = NULL; u_short fport = fport_arg, lport = lport_arg; INP_INFO_RLOCK_ASSERT(pcbinfo); @@ -1007,15 +1009,32 @@ /* * Found. */ - return (inp); + if (inp->inp_socket == NULL || + inp->inp_socket->so_cred->cr_prison == NULL) { + return (inp); + } else { + if (jinp == NULL) + jinp = inp; + } } } + if (jinp != NULL) + return (jinp); if (wildcard) { struct inpcb *local_wild = NULL; #if defined(INET6) struct inpcb *local_wild_mapped = NULL; #endif /* defined(INET6) */ + struct inpcb *jinp_wild = NULL; + struct ucred *cred; + /* + * Order of socket selection: + * 1. non-jailed, non-wild. + * 2. non-jailed, wild. + * 3. jailed, non-wild. + * 4. jailed, wild. + */ head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; LIST_FOREACH(inp, head, inp_hash) { #ifdef INET6 @@ -1027,24 +1046,46 @@ if (ifp && ifp->if_type == IFT_FAITH && (inp->inp_flags & INP_FAITH) == 0) continue; - if (inp->inp_laddr.s_addr == laddr.s_addr) - return (inp); - else if (inp->inp_laddr.s_addr == INADDR_ANY) { + if (inp->inp_socket != NULL) + cred = inp->inp_socket->so_cred; + else + cred = NULL; + if (cred != NULL && jailed(cred)) { + if (jinp != NULL) + continue; + if (!jailed_ip(cred, + ntohl(laddr.s_addr))) { + continue; + } + } + if (inp->inp_laddr.s_addr == laddr.s_addr) { + if (cred != NULL && jailed(cred)) + jinp = inp; + else + return (inp); + } else if (inp->inp_laddr.s_addr == INADDR_ANY) { #if defined(INET6) if (INP_CHECK_SOCKAF(inp->inp_socket, AF_INET6)) local_wild_mapped = inp; else #endif /* defined(INET6) */ - local_wild = inp; + if (cred != NULL && jailed(cred)) + jinp_wild = inp; + else + local_wild = inp; } } } + if (local_wild != NULL) + return (local_wild); #if defined(INET6) - if (local_wild == NULL) + if (local_wild_mapped != NULL) return (local_wild_mapped); #endif /* defined(INET6) */ - return (local_wild); + if (jinp != NULL) + return (jinp); + return (jinp_wild); } /* --- sys/netinet/in_pcb.h.orig Mon Aug 16 20:32:07 2004 +++ sys/netinet/in_pcb.h Mon Nov 15 12:54:28 2004 @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -345,7 +346,7 @@ void in_pcbdisconnect(struct inpcb *); int in_pcbinshash(struct inpcb *); struct inpcb * - in_pcblookup_local(struct inpcbinfo *, + in_pcblookup_local(struct ucred *, struct inpcbinfo *, struct in_addr, u_int, int); struct inpcb * in_pcblookup_hash(struct inpcbinfo *, struct in_addr, u_int, --- sys/netinet6/in6_pcb.c.orig Thu Oct 21 11:30:47 2004 +++ sys/netinet6/in6_pcb.c Mon Nov 15 13:58:40 2004 @@ -211,9 +211,9 @@ struct sockaddr_in sin; in6_sin6_2_sin(&sin, sin6); - t = in_pcblookup_local(pcbinfo, - sin.sin_addr, lport, - INPLOOKUP_WILDCARD); + t = in_pcblookup_local(cred, pcbinfo, + sin.sin_addr, lport, + INPLOOKUP_WILDCARD); if (t && ((t->inp_vflag & INP_TIMEWAIT) == 0) && @@ -236,7 +236,7 @@ struct sockaddr_in sin; in6_sin6_2_sin(&sin, sin6); - t = in_pcblookup_local(pcbinfo, sin.sin_addr, + t = in_pcblookup_local(cred, pcbinfo, sin.sin_addr, lport, wild); if (t && t->inp_vflag & INP_TIMEWAIT) { if ((reuseport & --- sys/sys/jail.h.orig Mon Apr 26 21:46:52 2004 +++ sys/sys/jail.h Mon Nov 15 13:40:41 2004 @@ -17,17 +17,21 @@ u_int32_t version; char *path; char *hostname; - u_int32_t ip_number; + u_int32_t *ips; + u_int nips; }; +#define JAIL_MAX_IPS 256 + struct xprison { - int pr_version; - int pr_id; - char pr_path[MAXPATHLEN]; - char pr_host[MAXHOSTNAMELEN]; - u_int32_t pr_ip; + int pr_version; + int pr_id; + char pr_path[MAXPATHLEN]; + char pr_host[MAXHOSTNAMELEN]; + u_int32_t pr_ips[JAIL_MAX_IPS]; + u_int pr_nips; }; -#define XPRISON_VERSION 1 +#define XPRISON_VERSION 2 #ifndef _KERNEL @@ -66,7 +70,8 @@ char pr_path[MAXPATHLEN]; /* (c) chroot path */ struct vnode *pr_root; /* (c) vnode to rdir */ char pr_host[MAXHOSTNAMELEN]; /* (p) jail hostname */ - u_int32_t pr_ip; /* (c) ip addr host */ + u_int32_t *pr_ips; /* (c) ip addr host */ + u_int pr_nips; void *pr_linux; /* (p) linux abi */ int pr_securelevel; /* (p) securelevel */ struct task pr_task; /* (d) destroy task */ @@ -103,6 +108,7 @@ 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 jailed_ip(struct ucred *cred, u_int32_t ip); #endif /* !_KERNEL */ #endif /* !_SYS_JAIL_H_ */ --- usr.sbin/jail/jail.c.orig Sun Aug 15 10:21:50 2004 +++ usr.sbin/jail/jail.c Mon Nov 15 13:20:13 2004 @@ -57,6 +57,8 @@ char path[PATH_MAX], *username; static char *cleanenv; const char *shell, *p; + int c; + char * ip; iflag = lflag = uflag = Uflag = 0; username = cleanenv = NULL; @@ -96,12 +98,25 @@ if (chdir(path) != 0) err(1, "chdir: %s", path); memset(&j, 0, sizeof(j)); - j.version = 0; + j.version = 1; j.path = path; j.hostname = argv[1]; - if (inet_aton(argv[2], &in) == 0) - errx(1, "Could not make sense of ip-number: %s", argv[2]); - j.ip_number = ntohl(in.s_addr); + for (c = 1, ip = argv[2]; *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[2], ","); 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; i = jail(&j); if (i == -1) err(1, "jail"); @@ -149,6 +164,6 @@ (void)fprintf(stderr, "%s%s\n", "usage: jail [-i] [-l -u username | -U username]", - " path hostname ip-number command ..."); + " path hostname ip1[,ip2[...]] command ..."); exit(1); } --- usr.sbin/jls/jls.c.orig Tue Apr 22 15:24:56 2003 +++ usr.sbin/jls/jls.c Mon Nov 15 16:32:24 2004 @@ -43,7 +43,7 @@ { struct xprison *sxp, *xp; struct in_addr in; - size_t i, len; + size_t i, j, len; if (sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1) err(1, "sysctlbyname(): security.jail.list"); @@ -67,9 +67,13 @@ printf(" JID IP Address Hostname Path\n"); for (i = 0; i < len / sizeof(*xp); i++) { - in.s_addr = ntohl(xp->pr_ip); + in.s_addr = ntohl(xp->pr_ips[0]); printf("%6d %-15.15s %-29.29s %.74s\n", xp->pr_id, inet_ntoa(in), xp->pr_host, xp->pr_path); + for (j = 1; j < xp->pr_nips; ++j) { + in.s_addr = ntohl(xp->pr_ips[j]); + printf(" %-15.15s\n", inet_ntoa(in)); + } xp++; } free(sxp);