Project

General

Profile

Bug #518 ยป jail-fixaddr.diff

corecode, 01/17/2007 03:43 PM

View differences:

sys/jail.h 17 Jan 2007 12:45:47 -0000
/* Used to store the IPs of the jail */
struct jail_ip_storage {
SLIST_ENTRY(jail_ip_storage) entries;
struct sockaddr_storage ip;
SLIST_ENTRY(jail_ip_storage) entries;
};
/*
......
struct nchandle pr_root; /* namecache entry of root */
char pr_host[MAXHOSTNAMELEN]; /* host name */
SLIST_HEAD(iplist, jail_ip_storage) pr_ips; /* list of IP addresses */
struct sockaddr_storage *local_ip4; /* cache for a loopback ipv4 address */
struct sockaddr_storage *nonlocal_ip4; /* cache for a non loopback ipv4 address */
struct sockaddr_storage *local_ip6; /* cache for a loopback ipv6 address */
struct sockaddr_storage *nonlocal_ip6; /* cache for a non loopback ipv6 address */
struct sockaddr_in *local_ip4; /* cache for a loopback ipv4 address */
struct sockaddr_in *nonlocal_ip4; /* cache for a non loopback ipv4 address */
struct sockaddr_in6 *local_ip6; /* cache for a loopback ipv6 address */
struct sockaddr_in6 *nonlocal_ip6; /* cache for a non loopback ipv6 address */
void *pr_linux; /* Linux ABI emulation */
int pr_securelevel; /* jail securelevel */
struct varsymset pr_varsymset; /* jail varsyms */
......
void prison_hold(struct prison *);
void prison_free(struct prison *);
int jailed_ip(struct prison *, struct sockaddr *);
int prison_get_local(struct prison *pr, struct sockaddr *);
int prison_get_nonlocal(struct prison *pr, struct sockaddr *);
struct sockaddr *
prison_get_local(struct prison *pr, sa_family_t, struct sockaddr *);
struct sockaddr *
prison_get_nonlocal(struct prison *pr, sa_family_t, struct sockaddr *);
/*
* Return 1 if the passed credential is in a jail, otherwise 0.
kern/kern_jail.c 17 Jan 2007 12:53:16 -0000
#include <netinet6/in6_var.h>
static struct prison *prison_find(int);
static void prison_ipcache_init(struct prison *);
MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
......
cache_copy(&nd.nl_nch, &pr->pr_root);
varsymset_init(&pr->pr_varsymset, NULL);
prison_ipcache_init(pr);
tryprid = lastprid + 1;
if (tryprid == JAIL_MAX)
......
return(kern_jail_attach(uap->jid));
}
static void
prison_ipcache_init(struct prison *pr)
{
struct jail_ip_storage *jis;
struct sockaddr_in *ip4;
struct sockaddr_in6 *ip6;
SLIST_FOREACH(jis, &pr->pr_ips, entries) {
switch (jis->ip.ss_family) {
case AF_INET:
ip4 = (struct sockaddr_in *)&jis->ip;
if ((ntohl(ip4->sin_addr.s_addr) >> IN_CLASSA_NSHIFT) ==
IN_LOOPBACKNET) {
/* loopback address */
if (pr->local_ip4 == NULL)
pr->local_ip4 = ip4;
} else {
/* public address */
if (pr->nonlocal_ip4 == NULL)
pr->nonlocal_ip4 = ip4;
}
break;
case AF_INET6:
ip6 = (struct sockaddr_in6 *)&jis->ip;
if (IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr)) {
/* loopback address */
if (pr->local_ip6 == NULL)
pr->local_ip6 = ip6;
} else {
/* public address */
if (pr->nonlocal_ip6 == NULL)
pr->nonlocal_ip6 = ip6;
}
break;
}
}
}
/*
* Changes INADDR_LOOPBACK for a valid jail address.
* ip is in network byte order.
......
ip4->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) ||
(ip->sa_family == AF_INET6 &&
IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr))) {
if (!prison_get_local(pr, ip) && !prison_get_nonlocal(pr, ip))
if (!prison_get_local(pr, ip->sa_family, ip) &&
!prison_get_nonlocal(pr, ip->sa_family, ip))
return(0);
else
return(1);
......
ip4->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) ||
(ip->sa_family == AF_INET6 &&
IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr))) {
if (!prison_get_local(pr, ip) && !prison_get_nonlocal(pr, ip))
if (!prison_get_local(pr, ip->sa_family, ip) &&
!prison_get_nonlocal(pr, ip->sa_family, ip))
return(0);
else
return(1);
......
/*
* Prison get non loopback ip:
* Put on *ip the first IP address that is not a loopback address.
* af is the address family of the ip we want (AF_INET|AF_INET6).
* - af is the address family of the ip we want (AF_INET|AF_INET6).
* - If ip != NULL, put the first IP address that is not a loopback address
* into *ip.
*
* ip is in network by order and we don't touch it unless we find a valid ip.
* Return 1 if we've found a non loopback ip, else return 0.
* No matter if ip == NULL or not, we return either a valid struct sockaddr *,
* or NULL. This struct may not be modified.
*/
int
prison_get_nonlocal(struct prison *pr, struct sockaddr *ip)
struct sockaddr *
prison_get_nonlocal(struct prison *pr, sa_family_t af, struct sockaddr *ip)
{
struct jail_ip_storage *jis;
struct sockaddr_in *jip4, *ip4;
struct sockaddr_in6 *jip6, *ip6;
struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
ip4 = (struct sockaddr_in *)ip;
ip6 = (struct sockaddr_in6 *)ip;
/* Check if it is cached */
switch(ip->sa_family) {
case AF_INET:
/* -1 Means that we don't have any address */
if (pr->nonlocal_ip4 == (struct sockaddr_storage *)-1)
return(0);
if (pr->nonlocal_ip4 != NULL) {
jip4 = (struct sockaddr_in *) pr->nonlocal_ip4;
ip4->sin_addr.s_addr = jip4->sin_addr.s_addr;
}
break;
case AF_INET6:
/* -1 Means that we don't have any address */
if (pr->nonlocal_ip6 == (struct sockaddr_storage *)-1)
return(0);
if (pr->nonlocal_ip6 != NULL) {
jip6 = (struct sockaddr_in6 *) pr->nonlocal_ip6;
ip6->sin6_addr = jip6->sin6_addr;
}
break;
};
SLIST_FOREACH(jis, &pr->pr_ips, entries) {
switch (ip->sa_family) {
case AF_INET:
jip4 = (struct sockaddr_in *) &jis->ip;
if (jip4->sin_family == AF_INET &&
((ntohl(jip4->sin_addr.s_addr) >> IN_CLASSA_NSHIFT) != IN_LOOPBACKNET)) {
pr->nonlocal_ip4 = &jis->ip;
ip4->sin_addr.s_addr = jip4->sin_addr.s_addr;
return(1);
}
break;
case AF_INET6:
jip6 = (struct sockaddr_in6 *) &jis->ip;
if ( jip6->sin6_family == AF_INET6 &&
!IN6_IS_ADDR_LOOPBACK(&jip6->sin6_addr)) {
pr->nonlocal_ip6 = &jis->ip;
ip6->sin6_addr = jip6->sin6_addr;
return(1);
}
break;
}
switch(af) {
case AF_INET:
if (ip4 != NULL && pr->nonlocal_ip4 != NULL)
ip4->sin_addr.s_addr = pr->nonlocal_ip4->sin_addr.s_addr;
return (struct sockaddr *)pr->nonlocal_ip4;
case AF_INET6:
if (ip6 != NULL && pr->nonlocal_ip6 != NULL)
ip6->sin6_addr = pr->nonlocal_ip6->sin6_addr;
return (struct sockaddr *)pr->nonlocal_ip6;
}
if (ip->sa_family == AF_INET)
pr->nonlocal_ip4 = (struct sockaddr_storage *)-1;
else
pr->nonlocal_ip6 = (struct sockaddr_storage *)-1;
return(0);
/* NOTREACHED */
return NULL;
}
/*
* Prison get loopback ip.
* Put on *ip the first loopback IP address.
* af is the address family of the ip we want (AF_INET|PF_INET).
* *ip is in network by order and we don't touch it unless we find a valid ip.
* return 1 if we've found a loopback ip, else return 0.
* - af is the address family of the ip we want (AF_INET|AF_INET6).
* - If ip != NULL, put the first IP address that is not a loopback address
* into *ip.
*
* ip is in network by order and we don't touch it unless we find a valid ip.
* No matter if ip == NULL or not, we return either a valid struct sockaddr *,
* or NULL. This struct may not be modified.
*/
int
prison_get_local(struct prison *pr, struct sockaddr *ip)
struct sockaddr *
prison_get_local(struct prison *pr, sa_family_t af, struct sockaddr *ip)
{
struct jail_ip_storage *jis;
struct sockaddr_in *jip4, *ip4;
struct sockaddr_in6 *jip6, *ip6;
struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
ip4 = (struct sockaddr_in *)ip;
ip6 = (struct sockaddr_in6 *)ip;
/* Check if it is cached */
switch(ip->sa_family) {
case AF_INET:
/* -1 Means that we don't have any address */
if (pr->local_ip4 == (struct sockaddr_storage *)-1)
return(0);
if (pr->local_ip4 != NULL) {
jip4 = (struct sockaddr_in *) pr->local_ip4;
ip4->sin_addr.s_addr = jip4->sin_addr.s_addr;
}
break;
case AF_INET6:
/* -1 Means that we don't have any address */
if (pr->local_ip6 == (struct sockaddr_storage *)-1)
return(0);
if (pr->local_ip6 != NULL) {
jip6 = (struct sockaddr_in6 *) pr->local_ip6;
ip6->sin6_addr = jip6->sin6_addr;
}
break;
};
SLIST_FOREACH(jis, &pr->pr_ips, entries) {
switch(ip->sa_family) {
case AF_INET:
jip4 = (struct sockaddr_in *) &jis->ip;
if (jip4->sin_family == AF_INET &&
((ntohl(jip4->sin_addr.s_addr) >> IN_CLASSA_NSHIFT)
== IN_LOOPBACKNET)) {
pr->local_ip4 = &jis->ip;
ip4->sin_addr.s_addr = jip4->sin_addr.s_addr;
return(1);
}
break;
case AF_INET6:
jip6 = (struct sockaddr_in6 *) &jis->ip;
if (jip6->sin6_family == AF_INET6 &&
IN6_IS_ADDR_LOOPBACK(&jip6->sin6_addr)) {
pr->local_ip6 = &jis->ip;
ip6->sin6_addr = jip6->sin6_addr;
return(1);
}
break;
}
switch(af) {
case AF_INET:
if (ip4 != NULL && pr->local_ip4 != NULL)
ip4->sin_addr.s_addr = pr->local_ip4->sin_addr.s_addr;
return (struct sockaddr *)pr->local_ip4;
case AF_INET6:
if (ip6 != NULL && pr->local_ip6 != NULL)
ip6->sin6_addr = pr->local_ip6->sin6_addr;
return (struct sockaddr *)pr->local_ip6;
}
if (ip->sa_family == AF_INET)
pr->local_ip4 = (struct sockaddr_storage *)-1;
else
pr->local_ip6 = (struct sockaddr_storage *)-1;
return(0);
/* NOTREACHED */
return NULL;
}
/* Check if the IP is among ours, if it is return 1, else 0 */
netinet/in_pcb.c 17 Jan 2007 12:58:07 -0000
struct in_ifaddr *ia;
struct ucred *cred = NULL;
struct sockaddr_in *sin = (struct sockaddr_in *)nam;
struct sockaddr_in jsin;
struct sockaddr *jsin;
int jailed = 0;
if (nam->sa_len != sizeof *sin)
......
* Don't do pcblookup call here; return interface in plocal_sin
* and exit to caller, that will do the lookup.
*/
if (jailed) {
jsin.sin_family = AF_INET;
if (!prison_get_nonlocal(cred->cr_prison,
sintosa(&jsin)) &&
!prison_get_local(cred->cr_prison, sintosa(&jsin)))
/* IPv6 only Jail */
return (EADDRNOTAVAIL);
*plocal_sin = &jsin;
if (ia == NULL && jailed) {
if ((jsin = prison_get_nonlocal(cred->cr_prison, AF_INET, NULL)) != NULL ||
(jsin = prison_get_local(cred->cr_prison, AF_INET, NULL)) != NULL)
*plocal_sin = satosin(jsin);
else
/* IPv6 only Jail */
return (EADDRNOTAVAIL);
} else {
*plocal_sin = &ia->ia_addr;
}
    (1-1/1)