Index: sys/kern/kern_jail.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_jail.c,v retrieving revision 1.34 diff -u -p -r1.34 kern_jail.c --- sys/kern/kern_jail.c 11 Jun 2003 00:56:55 -0000 1.34 +++ sys/kern/kern_jail.c 28 Nov 2003 21:02:04 -0000 @@ -10,6 +10,7 @@ #include __FBSDID("$FreeBSD: src/sys/kern/kern_jail.c,v 1.34 2003/06/11 00:56:55 obrien Exp $"); +#include "opt_inet6.h" #include #include #include @@ -46,7 +47,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, @@ -115,6 +116,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; @@ -342,18 +346,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/sys/jail.h =================================================================== RCS file: /home/ncvs/src/sys/sys/jail.h,v retrieving revision 1.18 diff -u -p -r1.18 jail.h --- sys/sys/jail.h 9 Apr 2003 02:55:18 -0000 1.18 +++ sys/sys/jail.h 28 Nov 2003 21:05:05 -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 @@ -66,6 +68,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 mtx pr_mtx; @@ -96,7 +99,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.45 diff -u -p -r1.45 jail.8 --- usr.sbin/jail/jail.8 11 Nov 2003 18:34:29 -0000 1.45 +++ usr.sbin/jail/jail.8 17 Nov 2003 19:49:55 -0000 @@ -43,6 +43,7 @@ .Nm .Op Fl i .Op Fl u Ar username +.Op Fl 6 Ar ip6-number .Ar path hostname ip-number command ... .Sh DESCRIPTION The @@ -57,6 +58,8 @@ Output the jail identifier of the newly The user name 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.14 diff -u -p -r1.14 jail.c --- usr.sbin/jail/jail.c 6 Jul 2003 12:44:11 -0000 1.14 +++ usr.sbin/jail/jail.c 28 Nov 2003 21:05:34 -0000 @@ -12,6 +12,7 @@ __FBSDID("$FreeBSD: src/usr.sbin/jail/ja #include #include +#include #include #include @@ -36,12 +37,16 @@ main(int argc, char **argv) struct in_addr in; int ch, groups[NGROUPS], i, iflag, ngroups; char *username; + char *ipv6 = NULL; iflag = 0; username = NULL; - while ((ch = getopt(argc, argv, "iu:")) != -1) { + while ((ch = getopt(argc, argv, "iu:6:")) != -1) { switch (ch) { + case '6': + ipv6 = optarg; + break; case 'i': iflag = 1; break; @@ -56,7 +61,6 @@ main(int argc, char **argv) argv += optind; if (argc < 4) usage(); - if (username != NULL) { pwd = getpwnam(username); if (pwd == NULL) @@ -77,6 +81,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"); @@ -104,6 +113,6 @@ usage(void) { (void)fprintf(stderr, - "usage: jail [-i] [-u username] path hostname ip-number command ...\n"); + "usage: jail [-i] [-6 ip6-number] [-u username] path hostname ip-number command ...\n"); exit(1); } Index: sys/netinet/tcp_usrreq.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/tcp_usrreq.c,v retrieving revision 1.90 diff -u -p -r1.90 tcp_usrreq.c --- sys/netinet/tcp_usrreq.c 26 Nov 2003 01:40:43 -0000 1.90 +++ sys/netinet/tcp_usrreq.c 28 Nov 2003 21:02:08 -0000 @@ -415,6 +415,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); @@ -423,6 +426,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.45 diff -u -p -r1.45 in6_pcb.c --- sys/netinet6/in6_pcb.c 20 Nov 2003 20:07:39 -0000 1.45 +++ sys/netinet6/in6_pcb.c 28 Nov 2003 21:02:08 -0000 @@ -137,6 +137,13 @@ in6_pcbbind(inp, nam, td) if (!in6_ifaddr) /* XXX broken! */ return (EADDRNOTAVAIL); + if (jailed(td->td_ucred)) { + struct in6_addr tmp_addr6; + + prison_getip6(td->td_ucred, (u_int8_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) @@ -150,7 +157,10 @@ in6_pcbbind(inp, nam, td) */ if (nam->sa_family != AF_INET6) return (EAFNOSUPPORT); - + if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) + if (prison_ip6(td->td_ucred, (u_int8_t **) + &sin6->sin6_addr)) + return (EINVAL); /* KAME hack: embed scopeid */ if (in6_embedscope(&sin6->sin6_addr, sin6, inp, NULL) != 0) return EINVAL; @@ -189,16 +199,19 @@ in6_pcbbind(inp, nam, td) } if (lport) { struct inpcb *t; + int prison = 0; /* GROSS */ if (ntohs(lport) < IPV6PORT_RESERVED && td && suser_cred(td->td_ucred, PRISON_ROOT)) return (EACCES); + if (td && jailed(td->td_ucred)) + 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)) { if ((!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) || @@ -241,6 +254,10 @@ in6_pcbbind(inp, nam, td) return (EADDRINUSE); } } + if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && + td && prison_ip6(td->td_ucred, (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) ? @@ -273,6 +290,11 @@ in6_pcbbind(inp, nam, td) } inp->in6p_laddr = sin6->sin6_addr; } + if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) + && td && prison_ip6(td->td_ucred, (u_int8_t **) + &inp->in6p_laddr)) + return (EINVAL); + if (lport == 0) { int e; if ((e = in6_pcbsetport(&inp->in6p_laddr, inp, td)) != 0) @@ -280,6 +302,7 @@ in6_pcbbind(inp, nam, td) } else { inp->inp_lport = lport; + if (in_pcbinshash(inp) != 0) { inp->in6p_laddr = in6addr_any; inp->inp_lport = 0; @@ -370,6 +393,20 @@ in6_pcbconnect(inp, nam, td) register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam; int error; + if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) && jailed(td->td_ucred)) { + struct sockaddr_in6 sa6; + + bzero(&sa6, sizeof(sa6)); + prison_getip6(td->td_ucred, (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, td); + 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.40 diff -u -p -r1.40 udp6_usrreq.c --- sys/netinet6/udp6_usrreq.c 26 Nov 2003 01:40:44 -0000 1.40 +++ sys/netinet6/udp6_usrreq.c 28 Nov 2003 21:02:08 -0000 @@ -84,6 +84,7 @@ #include #include #include +#include #include #include @@ -497,7 +498,7 @@ udp6_getcred(SYSCTL_HANDLER_ARGS) struct inpcb *inp; int error, s; - error = suser(req->td); + error = suser_cred(req->td->td_ucred, PRISON_ROOT); if (error) return (error); @@ -517,6 +518,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: @@ -524,8 +528,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 @@ -639,6 +643,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); splx(s); if (error == 0) { @@ -652,6 +659,11 @@ udp6_connect(struct socket *so, struct s if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) return EISCONN; s = splnet(); + if (td && jailed(td->td_ucred)) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam; + + prison_remote_ip6(td->td_ucred, (u_int8_t **)&sin6->sin6_addr); + } error = in6_pcbconnect(inp, nam, td); splx(s); if (error == 0) {