Index: sys/kern/kern_jail.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_jail.c,v retrieving revision 1.50 diff -u -p -r1.50 kern_jail.c --- sys/kern/kern_jail.c 23 Jun 2005 22:13:28 -0000 1.50 +++ sys/kern/kern_jail.c 12 Aug 2005 20:37:19 -0000 @@ -12,6 +12,7 @@ __FBSDID("$FreeBSD: src/sys/kern/kern_ja #include "opt_mac.h" +#include "opt_inet6.h" #include #include #include @@ -49,7 +50,7 @@ SYSCTL_INT(_security_jail, OID_AUTO, set int jail_socket_unixiproute_only = 1; SYSCTL_INT(_security_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW, &jail_socket_unixiproute_only, 0, - "Processes in jail are limited to creating UNIX/IPv4/route sockets only"); + "Processes in jail are limited to creating UNIX/IP/route sockets only"); int jail_sysvipc_allowed = 0; SYSCTL_INT(_security_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW, @@ -134,6 +135,9 @@ jail(struct thread *td, struct jail_args error = copyinstr(j.hostname, &pr->pr_host, sizeof(pr->pr_host), 0); if (error) goto e_dropvnref; +#ifdef INET6 + memcpy(&pr->pr_ip6, &j.ip6_number, sizeof(pr->pr_ip6)); +#endif pr->pr_ip = j.ip_number; pr->pr_linux = NULL; pr->pr_securelevel = securelevel; @@ -375,18 +379,82 @@ prison_remote_ip(struct ucred *cred, int return; } +#ifdef INET6 +void +prison_getip6(struct ucred *ucred, u_int8_t **ip6) +{ + + memcpy(ip6, &ucred->cr_prison->pr_ip6, + sizeof(ucred->cr_prison->pr_ip6)); +} + +int +prison_ip6(struct ucred *ucred, u_int8_t **ip6) +{ + struct in6_addr tmp; + + if (!jailed(ucred)) + return (0); + memcpy(&tmp, ip6, sizeof(tmp)); + if (IN6_IS_ADDR_LOOPBACK(&tmp) || + IN6_IS_ADDR_UNSPECIFIED(&tmp)) { + memcpy(ip6, &ucred->cr_prison->pr_ip6, sizeof(tmp)); + return (0); + } + if (IN6_ARE_ADDR_EQUAL((struct in6_addr *)ip6, + (struct in6_addr *)&ucred->cr_prison->pr_ip6)) + return (1); + return (0); +} + +void +prison_remote_ip6(struct ucred *cred, u_int8_t **ip) +{ + struct in6_addr tmp; + + if (!jailed(cred)) + return; + memcpy(&tmp, ip, sizeof(tmp)); + if (IN6_IS_ADDR_LOOPBACK(&tmp)) { + memcpy(ip, &cred->cr_prison->pr_ip6, sizeof(tmp)); + return; + } + return; +} + +#endif + int prison_if(struct ucred *cred, struct sockaddr *sa) { struct sockaddr_in *sai; +#ifdef INET6 + struct sockaddr_in6 *sa6; +#endif int ok; sai = (struct sockaddr_in *)sa; - if ((sai->sin_family != AF_INET) && jail_socket_unixiproute_only) - ok = 1; - else if (sai->sin_family != AF_INET) - ok = 0; - else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr)) +#ifdef INET6 + sa6 = (struct sockaddr_in6 *)sa; +#endif + if (sai->sin_family == AF_INET) { + if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr)) + ok = 1; + else + ok = 0; + } else +#ifdef INET6 + if (sai->sin_family == AF_INET6) { + if (!IN6_ARE_ADDR_EQUAL((struct in6_addr *) + &cred->cr_prison->pr_ip6, + (struct in6_addr *)&sa6->sin6_addr)) + ok = 1; + else + ok = 0; + } + else +#endif + if (jail_socket_unixiproute_only) ok = 1; else ok = 0; Index: sys/kern/uipc_socket.c =================================================================== RCS file: /home/ncvs/src/sys/kern/uipc_socket.c,v retrieving revision 1.244 diff -u -p -r1.244 uipc_socket.c --- sys/kern/uipc_socket.c 1 Aug 2005 21:15:09 -0000 1.244 +++ sys/kern/uipc_socket.c 12 Aug 2005 22:24:47 -0000 @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD: src/sys/kern/uipc_socket.c,v 1.244 2005/08/01 21:15:09 kbyanc Exp $"); #include "opt_inet.h" +#include "opt_inet6.h" #include "opt_mac.h" #include "opt_zero.h" @@ -193,6 +194,9 @@ socreate(dom, aso, type, proto, cred, td if (jailed(cred) && jail_socket_unixiproute_only && prp->pr_domain->dom_family != PF_LOCAL && prp->pr_domain->dom_family != PF_INET && +#ifdef INET6 + prp->pr_domain->dom_family != PF_INET6 && +#endif prp->pr_domain->dom_family != PF_ROUTE) { return (EPROTONOSUPPORT); } Index: sys/netinet/tcp_usrreq.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/tcp_usrreq.c,v retrieving revision 1.125 diff -u -p -r1.125 tcp_usrreq.c --- sys/netinet/tcp_usrreq.c 25 Jul 2005 12:31:42 -0000 1.125 +++ sys/netinet/tcp_usrreq.c 12 Aug 2005 20:37:19 -0000 @@ -409,6 +409,9 @@ tcp6_usr_connect(struct socket *so, stru in6_sin6_2_sin(&sin, sin6p); inp->inp_vflag |= INP_IPV4; inp->inp_vflag &= ~INP_IPV6; + if (td && jailed(td->td_ucred)) + prison_remote_ip(td->td_ucred, 0, + &sin.sin_addr.s_addr); if ((error = tcp_connect(tp, (struct sockaddr *)&sin, td)) != 0) goto out; error = tcp_output(tp); @@ -417,6 +420,8 @@ tcp6_usr_connect(struct socket *so, stru inp->inp_vflag &= ~INP_IPV4; inp->inp_vflag |= INP_IPV6; inp->inp_inc.inc_isipv6 = 1; + if (td && jailed(td->td_ucred)) + prison_remote_ip6(td->td_ucred, (u_int8_t **)&sin6p->sin6_addr); if ((error = tcp6_connect(tp, nam, td)) != 0) goto out; error = tcp_output(tp); Index: sys/netinet6/in6_pcb.c =================================================================== RCS file: /home/ncvs/src/sys/netinet6/in6_pcb.c,v retrieving revision 1.63 diff -u -p -r1.63 in6_pcb.c --- sys/netinet6/in6_pcb.c 25 Jul 2005 12:31:42 -0000 1.63 +++ sys/netinet6/in6_pcb.c 12 Aug 2005 21:04:20 -0000 @@ -135,6 +135,13 @@ in6_pcbbind(inp, nam, cred) if (!in6_ifaddr) /* XXX broken! */ return (EADDRNOTAVAIL); + if (jailed(cred)) { + struct in6_addr tmp_addr6; + + prison_getip6(cred, (uint8_t **)&tmp_addr6); + if (IN6_IS_ADDR_UNSPECIFIED(&tmp_addr6)) + return (EADDRNOTAVAIL); + } if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) return (EINVAL); if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) @@ -151,6 +158,9 @@ in6_pcbbind(inp, nam, cred) if (nam->sa_family != AF_INET6) return (EAFNOSUPPORT); + if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && + prison_ip6(cred, (u_int8_t **)&sin6->sin6_addr)) + return (EINVAL); if ((error = sa6_embedscope(sin6, ip6_use_defzone)) != 0) return(error); @@ -186,16 +196,19 @@ in6_pcbbind(inp, nam, cred) } if (lport) { struct inpcb *t; + int prison = 1; /* GROSS */ if (ntohs(lport) < IPV6PORT_RESERVED && suser_cred(cred, SUSER_ALLOWJAIL)) return (EACCES); + if (jailed(cred)) + prison = 1; if (so->so_cred->cr_uid != 0 && !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr, lport, - INPLOOKUP_WILDCARD); + prison ? 0 : INPLOOKUP_WILDCARD); if (t && ((t->inp_vflag & INP_TIMEWAIT) == 0) && (so->so_type != SOCK_STREAM || @@ -225,6 +238,10 @@ in6_pcbbind(inp, nam, cred) return (EADDRINUSE); } } + if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && + prison_ip6(cred, (u_int8_t **) + &sin6->sin6_addr)) + return (EADDRNOTAVAIL); t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr, lport, wild); if (t && (reuseport & ((t->inp_vflag & INP_TIMEWAIT) ? @@ -257,6 +274,11 @@ in6_pcbbind(inp, nam, cred) } inp->in6p_laddr = sin6->sin6_addr; } + if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) + && prison_ip6(cred, (u_int8_t **) + &inp->in6p_laddr)) + return (EINVAL); + if (lport == 0) { int e; if ((e = in6_pcbsetport(&inp->in6p_laddr, inp, cred)) != 0) @@ -264,6 +286,7 @@ in6_pcbbind(inp, nam, cred) } else { inp->inp_lport = lport; + if (in_pcbinshash(inp) != 0) { inp->in6p_laddr = in6addr_any; inp->inp_lport = 0; @@ -367,6 +390,20 @@ in6_pcbconnect(inp, nam, cred) INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); INP_LOCK_ASSERT(inp); + if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) && jailed(cred)) { + struct sockaddr_in6 sa6; + + bzero(&sa6, sizeof(sa6)); + prison_getip6(cred, (u_int8_t **)&sa6.sin6_addr); + if (IN6_IS_ADDR_UNSPECIFIED(&sa6.sin6_addr)) + return (EADDRNOTAVAIL); + sa6.sin6_len = sizeof(sa6); + sa6.sin6_family = AF_INET6; + /* XXX scope_id ? */ + error = in6_pcbbind(inp, (struct sockaddr *)&sa6, cred); + if (error) + return (error); + } /* * Call inner routine, to assign local interface address. * in6_pcbladdr() may automatically fill in sin6_scope_id. Index: sys/netinet6/udp6_usrreq.c =================================================================== RCS file: /home/ncvs/src/sys/netinet6/udp6_usrreq.c,v retrieving revision 1.55 diff -u -p -r1.55 udp6_usrreq.c --- sys/netinet6/udp6_usrreq.c 25 Jul 2005 12:31:42 -0000 1.55 +++ sys/netinet6/udp6_usrreq.c 12 Aug 2005 21:05:48 -0000 @@ -80,6 +80,7 @@ #include #include #include +#include #include #include @@ -462,7 +463,7 @@ udp6_getcred(SYSCTL_HANDLER_ARGS) struct inpcb *inp; int error, s; - error = suser(req->td); + error = suser_cred(req->td->td_ucred, SUSER_ALLOWJAIL); if (error) return (error); @@ -486,6 +487,9 @@ udp6_getcred(SYSCTL_HANDLER_ARGS) error = ENOENT; goto out; } + error = cr_canseesocket(req->td->td_ucred, inp->inp_socket); + if (error) + goto out; cru2x(inp->inp_socket->so_cred, &xuc); error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); out: @@ -493,8 +497,8 @@ out: return (error); } -SYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, - 0, 0, +SYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, + CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_PRISON, 0, 0, udp6_getcred, "S,xucred", "Get the xucred of a UDP6 connection"); static int @@ -634,6 +638,9 @@ udp6_connect(struct socket *so, struct s return EISCONN; in6_sin6_2_sin(&sin, sin6_p); s = splnet(); + if (td && jailed(td->td_ucred)) + prison_remote_ip(td->td_ucred, 0, + &sin.sin_addr.s_addr); error = in_pcbconnect(inp, (struct sockaddr *)&sin, td->td_ucred); splx(s); @@ -650,6 +657,11 @@ udp6_connect(struct socket *so, struct s goto out; } s = splnet(); + if (td && jailed(td->td_ucred)) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam; + + prison_remote_ip6(td->td_ucred, (uint8_t **)&sin6->sin6_addr); + } error = in6_pcbconnect(inp, nam, td->td_ucred); splx(s); if (error == 0) { Index: sys/sys/jail.h =================================================================== RCS file: /home/ncvs/src/sys/sys/jail.h,v retrieving revision 1.26 diff -u -p -r1.26 jail.h --- sys/sys/jail.h 9 Jun 2005 18:49:19 -0000 1.26 +++ sys/sys/jail.h 12 Aug 2005 20:37:19 -0000 @@ -18,6 +18,7 @@ struct jail { char *path; char *hostname; u_int32_t ip_number; + u_int8_t ip6_number[16]; }; struct xprison { @@ -26,6 +27,7 @@ struct xprison { char pr_path[MAXPATHLEN]; char pr_host[MAXHOSTNAMELEN]; u_int32_t pr_ip; + u_int8_t pr_ip6[16]; }; #define XPRISON_VERSION 1 @@ -69,6 +71,7 @@ struct prison { 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_int8_t pr_ip6[16]; /* (c) ip6 addr host */ void *pr_linux; /* (p) linux abi */ int pr_securelevel; /* (p) securelevel */ struct task pr_task; /* (d) destroy task */ @@ -110,7 +113,11 @@ u_int32_t prison_getip(struct ucred *cre void prison_hold(struct prison *pr); int prison_if(struct ucred *cred, struct sockaddr *sa); int prison_ip(struct ucred *cred, int flag, u_int32_t *ip); +#ifdef INET6 +void prison_getip6(struct ucred *cred, u_int8_t **ip6); +int prison_ip6(struct ucred *cred, u_int8_t **ip6); +void prison_remote_ip6(struct ucred *cred, u_int8_t **ip6); +#endif void prison_remote_ip(struct ucred *cred, int flags, u_int32_t *ip); - #endif /* _KERNEL */ #endif /* !_SYS_JAIL_H_ */ Index: usr.sbin/jail/jail.8 =================================================================== RCS file: /home/ncvs/src/usr.sbin/jail/jail.8,v retrieving revision 1.69 diff -u -p -r1.69 jail.8 --- usr.sbin/jail/jail.8 25 Jul 2005 16:04:30 -0000 1.69 +++ usr.sbin/jail/jail.8 12 Aug 2005 20:56:53 -0000 @@ -43,6 +43,7 @@ .Nm .Op Fl i .Op Fl l u Ar username | Fl U Ar username +.Op Fl 6 Ar ip6-number .Ar path hostname ip-number command ... .Sh DESCRIPTION The @@ -77,6 +78,8 @@ should run. The user name from jailed environment as whom the .Ar command should run. +.It Fl 6 Ar ip6 addr +set the IPv6 address assigned to the prison. .It Ar path Directory which is to be the root of the prison. .It Ar hostname Index: usr.sbin/jail/jail.c =================================================================== RCS file: /home/ncvs/src/usr.sbin/jail/jail.c,v retrieving revision 1.20 diff -u -p -r1.20 jail.c --- usr.sbin/jail/jail.c 17 Nov 2004 10:01:48 -0000 1.20 +++ usr.sbin/jail/jail.c 12 Aug 2005 22:10:54 -0000 @@ -12,6 +12,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/jail/ja #include #include +#include #include #include @@ -56,13 +57,14 @@ main(int argc, char **argv) gid_t groups[NGROUPS]; int ch, i, iflag, lflag, ngroups, uflag, Uflag; char path[PATH_MAX], *username; + char *ipv6 = NULL; static char *cleanenv; const char *shell, *p = NULL; iflag = lflag = uflag = Uflag = 0; username = cleanenv = NULL; - while ((ch = getopt(argc, argv, "ilu:U:")) != -1) { + while ((ch = getopt(argc, argv, "ilu:U6:")) != -1) { switch (ch) { case 'i': iflag = 1; @@ -78,6 +80,9 @@ main(int argc, char **argv) case 'l': lflag = 1; break; + case '6': + ipv6 = optarg; + break; default: usage(); } @@ -103,6 +108,11 @@ main(int argc, char **argv) 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); + if (ipv6) { + if (inet_pton(AF_INET6, ipv6, &j.ip6_number) != 1) + errx(1, "Could not make sense of ipv6: %s", ipv6); + } else + bzero(&j.ip6_number, sizeof(j.ip6_number)); i = jail(&j); if (i == -1) err(1, "jail"); @@ -149,7 +159,7 @@ usage(void) { (void)fprintf(stderr, "%s%s\n", - "usage: jail [-i] [-l -u username | -U username]", + "usage: jail [-i] [-6 ip6-number] [-l -u username | -U username]", " path hostname ip-number command ..."); exit(1); }