diff options
-rw-r--r-- | configure.ac | 7 | ||||
-rw-r--r-- | srcx/jails.c | 35 | ||||
-rw-r--r-- | srcx/jid.c | 8 | ||||
-rw-r--r-- | srcx/jkill.c | 10 | ||||
-rw-r--r-- | srcx/jps.c | 8 | ||||
-rw-r--r-- | srcx/jstart.c | 78 | ||||
-rw-r--r-- | srcx/util.c | 211 | ||||
-rw-r--r-- | srcx/util.h | 13 |
8 files changed, 238 insertions, 132 deletions
diff --git a/configure.ac b/configure.ac index 70e3484..a5b8c73 100644 --- a/configure.ac +++ b/configure.ac @@ -81,6 +81,13 @@ AC_CHECK_MEMBER([struct jail.ips], #include <sys/param.h> #include <sys/jail.h> ]]) +AC_CHECK_MEMBER([struct jail.ip4s], + [ JAIL_MULTIADDR=yes; AC_DEFINE_UNQUOTED(JAIL_MULTIADDR, 1, [Freebsd 7.2 Multiple IP support])], [], +[[ +#include <sys/types.h> +#include <sys/param.h> +#include <sys/jail.h> +]]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST diff --git a/srcx/jails.c b/srcx/jails.c index 0394a35..40b12a7 100644 --- a/srcx/jails.c +++ b/srcx/jails.c @@ -77,40 +77,15 @@ static void usage() static void list_jails() { - struct xprison* sxp; struct xprison* xp; size_t len, i; + jails jls; /* ... otherwise it's a name */ + jails_load(&jls); - if(sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1) - err(1, "couldn't list jails"); + while((xp = jails_next(&jls)) != NULL) + printf("%s\n", xp->pr_host); -retry: - - if(len <= 0) - return; - - sxp = xp = calloc(len, 1); - if(sxp == NULL) - err(1, "out of memory"); - - if(sysctlbyname("security.jail.list", xp, &len, NULL, 0) == -1) - { - if(errno == ENOMEM) - { - free(sxp); - goto retry; - } - - err(1, "couldn't list jails"); - } - - if(len < sizeof(*xp) || len % sizeof(*xp) || xp->pr_version != XPRISON_VERSION) - errx(1, "kernel and userland out of sync"); - - for(i = 0; i < (len / sizeof(*xp)); i++) - printf("%s\n", xp[i].pr_host); - - free(sxp); + jails_done(&jls); } @@ -54,9 +54,9 @@ static void usage(); int main(int argc, char* argv[]) { - struct xprison* sxp = NULL; struct xprison* xp = NULL; size_t len; + jails jls; char* e; /* Remove the program name */ @@ -69,8 +69,8 @@ int main(int argc, char* argv[]) if(running_in_jail() != 0) errx(1, "can't run from inside jail"); - len = get_jail_sysctl(&sxp); - xp = find_jail(argv[0], len, sxp); + jails_load(&jls); + xp = jails_find(&jls, argv[0]); strtol(argv[0], &e, 10); @@ -92,6 +92,8 @@ int main(int argc, char* argv[]) printf("%d\n", xp->pr_id); } + jails_done(&jls); + return 0; } diff --git a/srcx/jkill.c b/srcx/jkill.c index 1d5fa0e..aa7f9b8 100644 --- a/srcx/jkill.c +++ b/srcx/jkill.c @@ -88,8 +88,8 @@ static void usage_hr(const char* name); int main(int argc, char* argv[]) { - struct xprison* sxp = NULL; struct xprison* xp = NULL; + jails jls; size_t len; int jid, r, ret = 0; pid_t child; @@ -128,12 +128,12 @@ int main(int argc, char* argv[]) argc -= optind; argv += optind; - len = get_jail_sysctl(&sxp); + jails_load(&jls); /* For each jail */ for(; argc > 0; argc--, argv++) { - xp = find_jail(argv[0], len, sxp); + xp = jails_find(&jls, argv[0]); if(xp == NULL) { @@ -164,7 +164,7 @@ int main(int argc, char* argv[]) jid = xp->pr_id; /* Always free jail info before going into jail */ - free_jail_sysctl(len, sxp); + jails_done(&jls); if(jail_attach(jid) == -1) err(1, "couldn't attach to jail"); @@ -189,7 +189,7 @@ int main(int argc, char* argv[]) argv++; } - free_jail_sysctl(len, sxp); + jails_done(&jls); return ret; } } @@ -62,8 +62,8 @@ static void run_jail_ps(int argc, char* argv[]); int main(int argc, char* argv[]) { - struct xprison* sxp = NULL; struct xprison* xp = NULL; + jails jls; size_t len; int jid, ch = 0; int simple = 0; @@ -93,8 +93,8 @@ int main(int argc, char* argv[]) errx(1, "can't run from inside jail"); /* Translate the jail name into an id if neccessary */ - len = get_jail_sysctl(&sxp); - xp = find_jail(argv[0], len, sxp); + jails_load(&jls); + xp = jails_find(&jls, argv[0]); if(xp == NULL) errx(1, "unknown jail host name: %s", argv[0]); @@ -108,7 +108,7 @@ int main(int argc, char* argv[]) jid = xp->pr_id; /* Always free jail info before going into jail */ - free_jail_sysctl(len, sxp); + jails_done(&jls); /* Go into the jail */ if(jail_attach(jid) == -1) diff --git a/srcx/jstart.c b/srcx/jstart.c index 6360f06..c61f484 100644 --- a/srcx/jstart.c +++ b/srcx/jstart.c @@ -44,12 +44,15 @@ #include <sys/types.h> #include <sys/param.h> #include <sys/jail.h> +#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> +#include <netdb.h> #include <paths.h> #include <stdio.h> +#include <stdlib.h> #include <err.h> #include <unistd.h> #include <limits.h> @@ -66,7 +69,8 @@ static char* START_ARGS[] = { _PATH_BSHELL, START_SCRIPT, NULL }; static void usage(); -#ifdef JAIL_MULTIPATCH +/* Jail structure with multi address patch */ +#if defined(JAIL_MULTIPATCH) static void allocate_address(char* arg, struct jail* j) { @@ -101,7 +105,77 @@ static void free_address(struct jail* j) free(j->ips); } -#else /* !JAIL_MULTIPATCH */ +/* Jail structure with multi address (FreeBSD 7.2+) */ +#elif defined(JAIL_MULTIADDR) + +static void add_addresses(struct jail *j, struct addrinfo *all) +{ + struct addrinfo *res; + void *mem; + + for(res = all; res; res = res->ai_next) + { + switch(res->ai_family) + { + case AF_INET: + j->ip4 = realloc(j->ip4, sizeof (*(j->ip4)) * (j->ip4s + 1)); + if(j->ip4 == NULL) + errx(1, "out of memory"); + memcpy(j->ip4 + j->ip4s, &((struct sockaddr_in*)res->ai_addr)->sin_addr, sizeof (*(j->ip4))); + ++j->ip4s; + break; +#ifdef INET6 + case AF_INET6: + j->ip6 = realloc(j->ip6, sizeof (*(j->ip6)) * (j->ip6s + 1)); + if(j->ip6 == NULL) + errx(1, "out of memory"); + memcpy(j->ip6 + j->ip6s, &((struct sockaddr_in6*)res->ai_addr)->sin6_addr, sizeof (*(j->ip6))); + ++j->ip6s; + break; +#endif /* INET6 */ + default: + errx(1, "Address family %d not supported", res->ai_family); + } + } +} + +static void allocate_address(char* arg, struct jail* j) +{ + struct addrinfo hints, *res; + struct in_addr in; + char *ip; + int error, i = 0; + + j->ip4s = j->ip6s = 0; + j->ip4 = NULL; + j->ip6 = NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_protocol = IPPROTO_TCP; + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = PF_UNSPEC; + hints.ai_flags = AI_NUMERICHOST; + + for(i = 0, ip = strtok(arg, ","); ip; i++, ip = strtok(NULL, ",")) + { + error = getaddrinfo(ip, NULL, &hints, &res); + if(error != 0) + errx(1, "invalid ip address: %s", ip); + add_addresses(j, res); + freeaddrinfo(res); + } + + j->version = JAIL_API_VERSION; +} + +static void free_address(struct jail* j) +{ + free(j->ip4); + free(j->ip6); +} + +/* No jail multi addrs */ +#else static void allocate_address(char* arg, struct jail* j) { diff --git a/srcx/util.c b/srcx/util.c index 8894c61..ffea8ff 100644 --- a/srcx/util.c +++ b/srcx/util.c @@ -57,112 +57,155 @@ #include <string.h> #include <unistd.h> +#include <netinet/in.h> + #include "util.h" extern char** environ; -size_t get_jail_sysctl(struct xprison** ret) +void +jails_load (jails *jls) { - struct xprison* xp; - size_t len; - *ret = NULL; - - if(sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1) - err(1, "couldn't list jails"); - -retry: + struct xprison *xp; - if(len <= 0) - return 0; - - xp = calloc(len, 1); - if(xp == NULL) - err(1, "out of memory"); - - if(sysctlbyname("security.jail.list", xp, &len, NULL, 0) == -1) - { - if(errno == ENOMEM) - { - free(xp); - goto retry; - } + memset (jls, 0, sizeof (jails)); - err(1, "couldn't list jails"); - } + if(sysctlbyname("security.jail.list", NULL, &jls->length, NULL, 0) == -1) + err(1, "couldn't list jails"); - if(len < sizeof(*xp) || len % sizeof(*xp) || xp->pr_version != XPRISON_VERSION) - errx(1, "kernel and userland out of sync"); +retry: - *ret = xp; - return len / sizeof(*xp); + if(jls->length <= 0) + { + jls->data = NULL; + jls->last = NULL; + } + + jls->data = calloc(jls->length, 1); + if(jls->data == NULL) + err(1, "out of memory"); + + if(sysctlbyname("security.jail.list", jls->data, &jls->length, NULL, 0) == -1) + { + if(errno == ENOMEM) + { + free(jls->data); + jls->data = NULL; + goto retry; + } + + err(1, "couldn't list jails"); + } + + xp = jls->data; + if(jls->length < sizeof(*xp) || xp->pr_version != XPRISON_VERSION) + errx(1, "kernel and userland out of sync"); } -void free_jail_sysctl(size_t len, struct xprison* xp) +struct xprison* +jails_next (jails *jls) { - if(len == 0 || xp == NULL) - return; - - /* - * An extra precaution to prevent leakage of information - * into the jail. - */ - - memset(xp, 0, sizeof(struct xprison) * len); - free(xp); + struct xprison *xp = jls->last; + unsigned char *data, *next, *end; + + if(xp == NULL) + { + xp = jls->data; + } + else + { + switch(xp->pr_version) + { + case 1: + case 2: + xp = xp + 1; + break; + case 3: + data = (unsigned char*)(xp + 1); + data += (xp->pr_ip4s * sizeof(struct in_addr)); + data += (xp->pr_ip6s * sizeof(struct in6_addr)); + xp = (struct xprison*)data; + break; + default: + errx(1, "unknown jail structure"); + break; + } + } + + if(xp == NULL) + return NULL; + + next = (unsigned char*)(xp + 1); + end = ((unsigned char*)jls->data) + jls->length; + if (next > end) + return NULL; + + if(xp->pr_version != XPRISON_VERSION) + errx(1, "kernel and userland out of sync"); + + jls->last = xp; + return xp; } -struct xprison* find_jail(const char* str, size_t len, struct xprison* xp) +void +jails_done(jails *jls) { - int jid; - size_t i; - char* e; - - if(len == 0 || xp == NULL) - return NULL; - - jid = strtol(str, &e, 10); - - /* If it was all a number ... */ - if(!*e) - { - if(jid <= 0) - errx(1, "invalid jail id: %s", str); - - /* Validate the number */ - for(i = 0; i < len; i++) - { - if(jid == xp[i].pr_id) - return &(xp[i]); - } - } - - for(i = 0; i < len; i++) - { - if(strcmp(xp[i].pr_host, str) == 0) - return &(xp[i]); - } + memset(jls->data, 0, jls->length); + free(jls->data); + jls->data = NULL; + jls->length = 0; + jls->last = NULL; +} - return NULL; +struct xprison* +jails_find(jails *jls, const char* str) +{ + struct xprison *xp; + char *e; + int jid; + + jid = strtol(str, &e, 10); + jls->last = NULL; + + for(;;) + { + xp = jails_next(jls); + if(xp == NULL) + return NULL; + + /* If it was all a number ... */ + if(!*e) + { + if(jid <= 0) + errx(1, "invalid jail id: %s", str); + if(jid == xp->pr_id) + return xp; + } + + /* A host name? */ + else + { + if(strcmp(xp->pr_host, str) == 0) + return xp; + } + } + + /* Not reached */ } int translate_jail_name(const char* str) { - struct xprison* sxp = NULL; - struct xprison* xp = NULL; - size_t len; - int jid = -1; - - len = get_jail_sysctl(&sxp); - if(sxp) - { - xp = find_jail(str, len, sxp); - if(xp != NULL) - jid = xp->pr_id; + struct xprison* xp; + int jid = -1; + jails jls; - free(sxp); - } + jails_load(&jls); + xp = jails_find(&jls, str); + if(xp != NULL) + jid = xp->pr_id; + jails_done(&jls); - return jid; + return jid; } int kvm_prepare_jail(struct xprison* xp) diff --git a/srcx/util.h b/srcx/util.h index c98dad1..cc359b1 100644 --- a/srcx/util.h +++ b/srcx/util.h @@ -44,11 +44,16 @@ struct xprison; int translate_jail_name(const char* str); int running_in_jail(); -size_t get_jail_sysctl(struct xprison** xp); -void free_jail_sysctl(size_t len, struct xprison* xp); +typedef struct jails { + void *data; + size_t length; + struct xprison *last; +} jails; -int kvm_prepare_jail(struct xprison* xp); -struct xprison* find_jail(const char* str, size_t len, struct xprison* xp); +void jails_load(jails *jls); +struct xprison* jails_next(jails *jls); +struct xprison* jails_find(jails *jls, const char *str); +void jails_done(jails *jls); #define JAIL_RUN_CONSOLE 0x00000001 /* Output stuff to the jail console if available */ #define JAIL_RUN_STDOUT 0x00000002 /* Output to stdout */ |