From 298e1a85181102bde3aed73f73a34fe81f7de66a Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Wed, 19 May 2004 16:35:30 +0000 Subject: Create /dev/null before opening kernel interfaces if it doesn't exist --- srcx/jkill.c | 477 +++++++++++++++++++++--------------------- srcx/jps.c | 198 +++++++++--------- srcx/jstart.c | 150 ++++++------- srcx/util.c | 662 +++++++++++++++++++++++++++++++--------------------------- srcx/util.h | 4 +- 5 files changed, 778 insertions(+), 713 deletions(-) (limited to 'srcx') diff --git a/srcx/jkill.c b/srcx/jkill.c index 7125350..4311ed8 100644 --- a/srcx/jkill.c +++ b/srcx/jkill.c @@ -63,7 +63,7 @@ #endif /* The timeout to wait between kills */ -#define DEFAULT_TIMEOUT 3 +#define DEFAULT_TIMEOUT 3 int g_timeout = DEFAULT_TIMEOUT; int g_quiet = 0; /* Supress warnings */ @@ -84,15 +84,15 @@ static void usage_jail(const char* name); int main(int argc, char* argv[]) { - int r, jid; - int ret = 0; - pid_t child; + int r, jid; + int ret = 0; + pid_t child; /* * When running in a jail we do things slightly * differently, and accept different args */ - if(running_in_jail()) + if(running_in_jail()) { parse_jail_opts(argc, argv); @@ -103,8 +103,8 @@ int main(int argc, char* argv[]) if(daemon(0, 1) == -1) err(1, "couldn't disconnect from console"); - r = kill_jail(argv[0]); - exit(r); + r = kill_jail(argv[0]); + exit(r); } else @@ -114,54 +114,54 @@ int main(int argc, char* argv[]) argc -= optind; argv += optind; - /* For each jail */ - for(; argc > 0; argc--, argv++) - { - jid = translate_jail_name(argv[0]); - if(jid == -1) - { - warnx("unknown jail host name: %s", argv[0]); - ret = 1; - continue; - } - - /* - * We fork and the child goes into the jail and - * does the dirty work. Unless in debug mode where + /* For each jail */ + for(; argc > 0; argc--, argv++) + { + jid = translate_jail_name(argv[0]); + if(jid == -1) + { + warnx("unknown jail host name: %s", argv[0]); + ret = 1; + continue; + } + + /* + * We fork and the child goes into the jail and + * does the dirty work. Unless in debug mode where * we just do one jail. - */ + */ #ifdef _DEBUG - switch((child = fork())) - { - /* Error condition */ - case -1: - err(1, "couldn't fork child process"); - break; - - /* The child */ - case 0: + switch((child = fork())) + { + /* Error condition */ + case -1: + err(1, "couldn't fork child process"); + break; + + /* The child */ + case 0: #endif if(jail_attach(jid) == -1) err(1, "couldn't attach to jail"); - r = kill_jail(argv[0]); - exit(r); + r = kill_jail(argv[0]); + exit(r); #ifdef _DEBUG - break; + break; - /* The parent */ - default: - if(waitpid(child, &r, 0) == -1) - err(1, "error waiting for child process"); + /* The parent */ + default: + if(waitpid(child, &r, 0) == -1) + err(1, "error waiting for child process"); - if(WEXITSTATUS(r) != 0) - ret = WEXITSTATUS(r); - break; - }; + if(WEXITSTATUS(r) != 0) + ret = WEXITSTATUS(r); + break; + }; #endif - argc--; - argv++; + argc--; + argv++; } return ret; @@ -181,7 +181,7 @@ static void parse_jail_opts(int argc, char* argv[]) g_verbose = 1; g_force = 1; g_usescripts = 1; - g_restart = 0; + g_restart = 0; } else if(strcmp(argv[0], "reboot")) @@ -202,25 +202,25 @@ static void parse_jail_opts(int argc, char* argv[]) return; } - while((ch = getopt(argc, argv, "dk:lnqp")) != -1) - { - switch(ch) - { - case 'd': + while((ch = getopt(argc, argv, "dk:lnqp")) != -1) + { + switch(ch) + { + case 'd': case 'k': case 'l': case 'n': case 'q': case 'p': warnx("the '-%c' option is not supported from inside a jail", (char)ch); - break; + break; - case '?': - default: - usage_jail(t); + case '?': + default: + usage_jail(t); break; - } - } + } + } argc -= optind; argv += optind; @@ -233,224 +233,223 @@ static void parse_host_opts(int argc, char* argv[]) { int ch; - while((ch = getopt(argc, argv, "fhkqrt:v")) != -1) - { - switch(ch) - { - case 'f': - g_force = 1; - break; - - case 'h': - /* dummy for compatibility with killjail */ - warnx("the '-h' option has been depreciated"); - break; - - case 'k': - g_usescripts = 0; - break; - - case 'q': - g_quiet = 1; - g_verbose = 0; - break; - - case 'r': - g_restart = 1; - break; - - /* Timeout to use between kills */ - case 't': - g_timeout = atoi(optarg); - if(g_timeout <= 0) - errx(2, "invalid timeout argument: %s", optarg); - break; - - case 'v': - g_verbose = 1; - g_quiet = 0; - break; - - case '?': - default: - usage(); + while((ch = getopt(argc, argv, "fhkqrt:v")) != -1) + { + switch(ch) + { + case 'f': + g_force = 1; break; - } - } - if(!g_usescripts && g_restart) - usage(); + case 'h': + /* dummy for compatibility with killjail */ + warnx("the '-h' option has been depreciated"); + break; + + case 'k': + g_usescripts = 0; + break; - argc -= optind; - argv += optind; + case 'q': + g_quiet = 1; + g_verbose = 0; + break; + + case 'r': + g_restart = 1; + break; + + /* Timeout to use between kills */ + case 't': + g_timeout = atoi(optarg); + if(g_timeout <= 0) + errx(2, "invalid timeout argument: %s", optarg); + break; + + case 'v': + g_verbose = 1; + g_quiet = 0; + break; + + case '?': + default: + usage(); + break; + } + } + + if(!g_usescripts && g_restart) + usage(); + + argc -= optind; + argv += optind; if(argc <= 0) usage(); } #define SHUTDOWN_SCRIPT "/etc/rc.shutdown" -static char* SHUTDOWN_ARGS[] = { _PATH_BSHELL, SHUTDOWN_SCRIPT }; +static char* SHUTDOWN_ARGS[] = { _PATH_BSHELL, SHUTDOWN_SCRIPT }; #define START_SCRIPT "/etc/rc" -static char* START_ARGS[] = { _PATH_BSHELL, START_SCRIPT }; +static char* START_ARGS[] = { _PATH_BSHELL, START_SCRIPT }; static int kill_jail(const char* jail) { - kvm_t* kd = NULL; - char errbuf[_POSIX2_LINE_MAX]; - int pass = 0; - int timeout = 0; - int ret = 0; - int cmdargs = JAIL_RUN_CONSOLE; - - /* Open the kernel interface */ - kd = kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, _PATH_DEVNULL, - O_RDONLY, errbuf); - if(kd == NULL) - errx(1, "couldn't connect to kernel: %s", errbuf); - - if(g_verbose) - cmdargs |= JAIL_RUN_STDERR; - - /* - * Multiple passes are used to do different things. - * Each time the jails processes are listed. - */ - while(1) - { - while(timeout > 0) - { - sleep(1); - timeout--; - - if(!check_running_processes(kd)) - goto done; - } - - switch(pass) - { - /* First pass is an orderly shutdown */ - case 0: - - /* Check if we have an executable shutdown script */ - if(g_usescripts && check_jail_command(jail, SHUTDOWN_SCRIPT)) - run_jail_command(jail, SHUTDOWN_ARGS[0], SHUTDOWN_ARGS, cmdargs); - - break; - - /* Okay now quit all processes in jail */ - case 1: - kill_jail_processes(kd, SIGTERM); - timeout = g_timeout; - break; - - /* ... and again ... */ - case 2: - kill_jail_processes(kd, SIGTERM); - timeout = g_timeout; - break; - - /* Okay now we force kill the processes if necessary */ - case 3: - - if(g_force) - { - /* If we get here, jailer looks like it's really irresponsive */ - if(!g_quiet) - warnx("%s: jail won't stop. forcing jail termination...", jail); - - kill_jail_processes(kd, SIGKILL); - timeout = g_timeout; - } - - break; - - case 4: - - /* And if that didn't do it, well then give up */ - if(!g_quiet) - warnx("%s: couldn't stop jail, processes wouldn't die", jail); - - ret = 1; - goto done; - } - - pass++; - - if(!check_running_processes(kd)) - goto done; - } + kvm_t* kd = NULL; + char errbuf[_POSIX2_LINE_MAX]; + int pass = 0; + int timeout = 0; + int ret = 0; + int cmdargs = JAIL_RUN_CONSOLE; + + /* Open the kernel interface */ + kd = open_kvm_handle(jail, errbuf); + if(kd == NULL) + errx(1, "couldn't connect to kernel: %s", errbuf); + + if(g_verbose) + cmdargs |= JAIL_RUN_STDERR; + + /* + * Multiple passes are used to do different things. + * Each time the jails processes are listed. + */ + while(1) + { + while(timeout > 0) + { + sleep(1); + timeout--; + + if(!check_running_processes(kd)) + goto done; + } + + switch(pass) + { + /* First pass is an orderly shutdown */ + case 0: + + /* Check if we have an executable shutdown script */ + if(g_usescripts && check_jail_command(jail, SHUTDOWN_SCRIPT)) + run_jail_command(jail, SHUTDOWN_ARGS[0], SHUTDOWN_ARGS, cmdargs); + + break; + + /* Okay now quit all processes in jail */ + case 1: + kill_jail_processes(kd, SIGTERM); + timeout = g_timeout; + break; + + /* ... and again ... */ + case 2: + kill_jail_processes(kd, SIGTERM); + timeout = g_timeout; + break; + + /* Okay now we force kill the processes if necessary */ + case 3: + + if(g_force) + { + /* If we get here, jailer looks like it's really irresponsive */ + if(!g_quiet) + warnx("%s: jail won't stop. forcing jail termination...", jail); + + kill_jail_processes(kd, SIGKILL); + timeout = g_timeout; + } + + break; + + case 4: + + /* And if that didn't do it, well then give up */ + if(!g_quiet) + warnx("%s: couldn't stop jail, processes wouldn't die", jail); + + ret = 1; + goto done; + } + + pass++; + + if(!check_running_processes(kd)) + goto done; + } done: - if(g_restart) - { - /* Check if we have an executable shutdown script */ - if(check_jail_command(jail, START_SCRIPT)) - run_jail_command(jail, START_ARGS[0], START_ARGS, cmdargs); - } + if(g_restart) + { + /* Check if we have an executable shutdown script */ + if(check_jail_command(jail, START_SCRIPT)) + run_jail_command(jail, START_ARGS[0], START_ARGS, cmdargs); + } - if(kd != NULL) - kvm_close(kd); + if(kd != NULL) + kvm_close(kd); - return ret; + return ret; } static void kill_jail_processes(kvm_t* kd, int sig) { - struct kinfo_proc* kp; - int nentries, i; - pid_t cur; - - cur = getpid(); - - /* Get a process listing */ - if((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == 0) - errx(1, "couldn't list processes: %s", kvm_geterr(kd)); - - /* Okay now loop and look at each process' jail */ - for(i = 0; i < nentries; i++) - { - if(kp[i].ki_pid == cur) - continue; - - if(kill(kp[i].ki_pid, sig) == -1) - { - if(errno != ESRCH) - errx(1, "couldn't signal process: %d", (int)kp[i].ki_pid); - } - } + struct kinfo_proc* kp; + int nentries, i; + pid_t cur; + + cur = getpid(); + + /* Get a process listing */ + if((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == 0) + errx(1, "couldn't list processes: %s", kvm_geterr(kd)); + + /* Okay now loop and look at each process' jail */ + for(i = 0; i < nentries; i++) + { + if(kp[i].ki_pid == cur) + continue; + + if(kill(kp[i].ki_pid, sig) == -1) + { + if(errno != ESRCH) + errx(1, "couldn't signal process: %d", (int)kp[i].ki_pid); + } + } } static int check_running_processes(kvm_t* kd) { - struct kinfo_proc* kp; - int nentries, i; - pid_t cur; + struct kinfo_proc* kp; + int nentries, i; + pid_t cur; - cur = getpid(); + cur = getpid(); - /* Get a process listing */ - if((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == 0) - errx(1, "couldn't list processes: %s", kvm_geterr(kd)); + /* Get a process listing */ + if((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == 0) + errx(1, "couldn't list processes: %s", kvm_geterr(kd)); - if(nentries != 1) - return 1; + if(nentries != 1) + return 1; - /* Okay now loop and look at each process' jail */ - for(i = 0; i < nentries; i++) - { - if(kp[i].ki_pid != cur) - return 1; - } + /* Okay now loop and look at each process' jail */ + for(i = 0; i < nentries; i++) + { + if(kp[i].ki_pid != cur) + return 1; + } - return 0; + return 0; } static void usage() { - fprintf(stderr, "usage: jkill [-fkqv] [-t timeout] jail ...\n"); - fprintf(stderr, " jkill -r [-fqv] [-t timeout] jail ...\n"); - exit(2); + fprintf(stderr, "usage: jkill [-fkqv] [-t timeout] jail ...\n"); + fprintf(stderr, " jkill -r [-fqv] [-t timeout] jail ...\n"); + exit(2); } static void usage_jail(const char* name) diff --git a/srcx/jps.c b/srcx/jps.c index c34aa41..6f8e4db 100644 --- a/srcx/jps.c +++ b/srcx/jps.c @@ -61,117 +61,125 @@ static void run_jail_ps(int argc, char* argv[]); int main(int argc, char* argv[]) { - int ch = 0; - int simple = 0; - int jid = 0; - - while((ch = getopt(argc, argv, "i")) != -1) - { - switch(ch) - { - case 'i': - simple = 1; - break; - - case '?': - default: - usage(); - } - } - - argc -= optind; - argv += optind; - - /* Make sure we have a jail name or id */ - if(argc == 0) - usage(); - - if(running_in_jail()) - errx(1, "can't run from inside jail"); - - /* Translate the jail name into an id if neccessary */ - jid = translate_jail_name(argv[0]); - if(jid == -1) - errx(1, "unknown jail host name: %s", argv[0]); - - argc--; - argv++; - - /* Go into the jail */ - if(jail_attach(jid) == -1) - err(1, "couldn't attach to jail"); - - if(simple) - { - if(argc > 0) - usage(); - - print_jail_ids(); - } - - else - { - /* This function never returns */ - run_jail_ps(argc, argv); - } - - return 0; + int ch = 0; + int simple = 0; + int jid = 0; + + while((ch = getopt(argc, argv, "i")) != -1) + { + switch(ch) + { + case 'i': + simple = 1; + break; + + case '?': + default: + usage(); + } + } + + argc -= optind; + argv += optind; + + /* Make sure we have a jail name or id */ + if(argc == 0) + usage(); + + if(running_in_jail()) + errx(1, "can't run from inside jail"); + + /* Translate the jail name into an id if neccessary */ + jid = translate_jail_name(argv[0]); + if(jid == -1) + errx(1, "unknown jail host name: %s", argv[0]); + + argc--; + argv++; + + /* Go into the jail */ + if(jail_attach(jid) == -1) + err(1, "couldn't attach to jail"); + + if(simple) + { + if(argc > 0) + usage(); + + print_jail_ids(); + } + + else + { + /* This function never returns */ + run_jail_ps(argc, argv); + } + + return 0; } static void usage() { - fprintf(stderr, "usage: jps [-i] jail [ ps_options ... ]\n"); - exit(2); + fprintf(stderr, "usage: jps [-i] jail [ ps_options ... ]\n"); + exit(2); } static void run_jail_ps(int argc, char* argv[]) { - char** args; - int i; + char errbuf[_POSIX2_LINE_MAX]; + char** args; + kvm_t kd; + int i; - if(!check_jail_command(NULL, "/bin/ps")) - exit(1); + if(!check_jail_command(NULL, "/bin/ps")) + exit(1); - /* - * TODO: We need to purge down the environment here. - * If the jail is in any way malicious or compromised - * then it could have replaced /bin/ps which we run... - */ + /* Make sure we can use kvm functionality here */ + kd = open_kvm_handle(NULL, errbuf); + if(kd == NULL) + errx(1, "couldn't connect to kernel: %s", errbuf); - args = (char**)alloca(sizeof(char*) * (argc + 2)); - args[0] = "ps"; + kvm_close(kd); - for(i = 0; i < argc; i++) - args[i + 1] = argv[i]; + /* + * TODO: We need to purge down the environment here. + * If the jail is in any way malicious or compromised + * then it could have replaced /bin/ps which we run... + */ - args[i + 1] = NULL; + args = (char**)alloca(sizeof(char*) * (argc + 2)); + args[0] = "ps"; - run_jail_command(NULL, "/bin/ps", args, JAIL_RUN_NOFORK); + for(i = 0; i < argc; i++) + args[i + 1] = argv[i]; + + args[i + 1] = NULL; + + run_jail_command(NULL, "/bin/ps", args, JAIL_RUN_NOFORK); } static void print_jail_ids() { - kvm_t* kd; - int nentries, i; - struct kinfo_proc* kp; - char errbuf[_POSIX2_LINE_MAX]; - - /* Open kernel interface */ - kd = kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf); - if(kd == NULL) - errx(1, "couldn't connect to kernel: %s", errbuf); - - /* Get all processes and print the pids */ - if((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == 0) - errx(1, "couldn't list processes: %s", kvm_geterr(kd)); - - for(i = 0; i < nentries; i++) - { - if(kp[i].ki_pid != getpid()) - printf("%d ", (int)(kp[i].ki_pid)); - } - - fputc('\n', stdout); - kvm_close(kd); + kvm_t* kd; + int nentries, i; + struct kinfo_proc* kp; + char errbuf[_POSIX2_LINE_MAX]; + + /* Open kernel interface */ + kd = open_kvm_handle(NULL, errbuf); + if(kd == NULL) + errx(1, "couldn't connect to kernel: %s", errbuf); + + /* Get all processes and print the pids */ + if((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == 0) + errx(1, "couldn't list processes: %s", kvm_geterr(kd)); + + for(i = 0; i < nentries; i++) + { + if(kp[i].ki_pid != getpid()) + printf("%d ", (int)(kp[i].ki_pid)); + } + + fputc('\n', stdout); + kvm_close(kd); } - diff --git a/srcx/jstart.c b/srcx/jstart.c index 288b444..770d41f 100644 --- a/srcx/jstart.c +++ b/srcx/jstart.c @@ -61,89 +61,91 @@ #endif #define START_SCRIPT "/etc/rc" -static char* START_ARGS[] = { _PATH_BSHELL, START_SCRIPT }; +static char* START_ARGS[] = { _PATH_BSHELL, START_SCRIPT }; static void usage(); int main(int argc, char* argv[]) { - int ch, jid; - struct jail j; - int printjid = 0; - struct in_addr in; - - while((ch = getopt(argc, argv, "i")) != -1) - { - switch(ch) - { - case 'i': - printjid = 1; - break; - - case '?': - default: - usage(); - } - } - - argc -= optind; - argv += optind; - - if(argc < 3) - usage(); - - if(getuid() != 0) - errx(1, "must be run as root"); - - if(chdir(argv[0]) != 0) - err(1, "couldn't change to jail directory: %s", argv[0]); - - if(inet_aton(argv[2], &in) != 1) - errx(1, "invalid ip address: %s", argv[2]); - - memset(&j, 0, sizeof(j)); - j.version = 0; - j.path = argv[0]; - j.hostname = argv[1]; - j.ip_number = ntohl(in.s_addr); - - /* Here's where we actually go into the jail */ - jid = jail(&j); - if(jid == -1) - err(1, "couldn't create jail"); - - if(printjid) - { - printf("%d\n", jid); - fflush(stdout); - } - - argc -= 3; - argv += 3; - - if(argc == 0) - { - if(!check_jail_command(NULL, START_SCRIPT)) - exit(1); - - run_jail_command(NULL, START_ARGS[0], START_ARGS, JAIL_RUN_CONSOLE | JAIL_RUN_STDOUT); - } - - else - { - if(!check_jail_command(NULL, argv[0])) - exit(1); - - run_jail_command(NULL, argv[0], argv, JAIL_RUN_CONSOLE | JAIL_RUN_STDOUT); - } - - return 0; + int ch, jid; + struct jail j; + int printjid = 0; + struct in_addr in; + + while((ch = getopt(argc, argv, "i")) != -1) + { + switch(ch) + { + case 'i': + printjid = 1; + break; + + case '?': + default: + usage(); + } + } + + argc -= optind; + argv += optind; + + if(argc < 3) + usage(); + + if(getuid() != 0) + errx(1, "must be run as root"); + + if(chdir(argv[0]) != 0) + err(1, "couldn't change to jail directory: %s", argv[0]); + + if(inet_aton(argv[2], &in) != 1) + errx(1, "invalid ip address: %s", argv[2]); + + memset(&j, 0, sizeof(j)); + j.version = 0; + j.path = argv[0]; + j.hostname = argv[1]; + j.ip_number = ntohl(in.s_addr); + + /* Here's where we actually go into the jail */ + jid = jail(&j); + if(jid == -1) + err(1, "couldn't create jail"); + + if(printjid) + { + printf("%d\n", jid); + fflush(stdout); + } + + argc -= 3; + argv += 3; + + if(argc == 0) + { + if(!check_jail_command(NULL, START_SCRIPT)) + exit(1); + + run_jail_command(NULL, START_ARGS[0], START_ARGS, + JAIL_RUN_CONSOLE | JAIL_RUN_STDOUT); + } + + else + { + if(!check_jail_command(NULL, argv[0])) + exit(1); + + run_jail_command(NULL, argv[0], argv, + JAIL_RUN_CONSOLE | JAIL_RUN_STDOUT); + } + + return 0; } static void usage() { - fprintf(stderr, "usage: jstart [-i] path hostname ip-number [command ...]\n"); - exit(2); + fprintf(stderr, "usage: jstart [-i] path hostname ip-number [command ...]\n"); + exit(2); } diff --git a/srcx/util.c b/srcx/util.c index 1911d2f..8d5e145 100644 --- a/srcx/util.c +++ b/srcx/util.c @@ -61,95 +61,149 @@ extern char** environ; size_t get_jail_sysctl(struct xprison** ret) { - struct xprison* xp; - size_t len; - *ret = NULL; + struct xprison* xp; + size_t len; + *ret = NULL; if(sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1) - err(1, "couldn't list jails"); + err(1, "couldn't list jails"); retry: - if(len <= 0) - return 0; + if(len <= 0) + return 0; - xp = calloc(len, 1); - if(xp == NULL) - err(1, "out of memory"); + 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; - } + if(sysctlbyname("security.jail.list", xp, &len, NULL, 0) == -1) + { + if(errno == ENOMEM) + { + free(xp); + goto retry; + } - err(1, "couldn't list jails"); - } + 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"); + if(len < sizeof(*xp) || len % sizeof(*xp) || xp->pr_version != XPRISON_VERSION) + errx(1, "kernel and userland out of sync"); - *ret = xp; - return len / sizeof(*xp); + *ret = xp; + return len / sizeof(*xp); } int translate_jail_name(const char* str) { - struct xprison* xp = NULL; - size_t len, i; - char* e; - int jid = -1; - - len = get_jail_sysctl(&xp); - if(len == 0) - goto done; - - 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) - goto done; - } - - jid = -1; - } - - jid = -1; - - for(i = 0; i < len; i++) - { - if(strcmp(xp[i].pr_host, str) == 0) - { - jid = xp[i].pr_id; - break; - } - } + struct xprison* xp = NULL; + size_t len, i; + char* e; + int jid = -1; + + len = get_jail_sysctl(&xp); + if(len == 0) + goto done; + + 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) + goto done; + } + + jid = -1; + } + + jid = -1; + + for(i = 0; i < len; i++) + { + if(strcmp(xp[i].pr_host, str) == 0) + { + jid = xp[i].pr_id; + break; + } + } done: - if(xp) - free(xp); + if(xp) + free(xp); - return jid; + return jid; } -kvm_t open_kvm_handle(char* errbuf) +kvm_t open_kvm_handle(char* jail, char* errbuf) { - /* - * Basically the kvm routines won't work in - * a jail unless there's a /dev/null device - * for us to use as the file name. If it's - * missing we have to create it - */ + /* + * Basically the kvm routines won't work in a jail unless there's + * a /dev/null device for us to use as the file names. If it's + * missing we have to create it. + */ + + struct stat sb; + int nodir = 0; + int nonull = 0; + + if(stat(_PATH_DEVNULL, &sb) == -1) + { + if(errno == ENOTDIR) + { + nodir = 1; + nonull = 1; + } + + else if(errno == ENOENT) + { + nonull = 1; + } + + else + { + err(1, "%s%scouldn't stat file: %s", jail ? jail : "", + jail ? ": " : "", _PATH_DEVNULL); + } + } + + if(nodir) + { + warnx("%s%sthe %s directory doesn't exist in jail. creating...", + jail ? jail : "", jail ? ": " : "", _PATH_DEV); + + if(mkdir(_PATH_DEV, 0) == -1 || + chmod(_PATH_DEV, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) + { + warn("%s%scouldn't create %s directory", + jail ? jail : "", jail ? ": " : "", _PATH_DEV); + nofile = 0; + } + } + + if(nofile) + { + mode_t mode = 0666 | S_IFCHR; + dev_t dev = makedev(2, 2); + + warnx("%s%sthe %s device doesn't exist in jail. creating...", + jail ? jail : "", jail ? ": " : "", _PATH_DEVNULL); + + if(mknod(_PATH_DEVNULL, mode, dev) == -1) + { + warn("%s%scouldn't create %s device", + jail ? jail : "", jail ? ": " : "", _PATH_DEVNULL); + } + } + + return kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf); } /* @@ -161,119 +215,119 @@ kvm_t open_kvm_handle(char* errbuf) int running_in_jail() { - int count; - kvm_t* kd = 0; - struct kinfo_proc* kp; - char errbuf[_POSIX2_LINE_MAX]; - int result = -1; + int count; + kvm_t* kd = 0; + struct kinfo_proc* kp; + char errbuf[_POSIX2_LINE_MAX]; + int result = -1; - kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); - if(kd == NULL) - errx(1, "couldn't connect to kernel: %s", errbuf); + kd = open_kvm_handle(NULL, errbuf); + if(kd == NULL) + errx(1, "couldn't connect to kernel: %s", errbuf); - kp = kvm_getprocs(kd, KERN_PROC_PID, getpid(), &count); - if(kp == NULL) - errx(1, "couldn't list processes: %s", kvm_geterr(kd)); + kp = kvm_getprocs(kd, KERN_PROC_PID, getpid(), &count); + if(kp == NULL) + errx(1, "couldn't list processes: %s", kvm_geterr(kd)); - result = (kp->ki_flag & P_JAILED) ? 1 : 0; - kvm_close(kd); + result = (kp->ki_flag & P_JAILED) ? 1 : 0; + kvm_close(kd); - return result; + return result; } int check_jail_command(const char* jail, const char* cmd) { - struct stat sb; - - if(stat(cmd, &sb) == -1) - { - if(errno == EACCES || errno == ELOOP || errno == ENAMETOOLONG || - errno == ENOENT || errno == ENOTDIR) - { - warn("%s%scan't execute in jail: %s", jail ? jail : "", - jail ? ": " : "", cmd); - return 0; - } - - err(1, "%s%scouldn't stat file: %s", jail ? jail : "", - jail ? ": " : "", cmd); - } - - if(!(sb.st_mode & S_IFREG)) - { - warnx("%s%snot a regular file: %s", jail ? jail : "", - jail ? ": " : "", cmd); - return 0; - } - - if(sb.st_uid != 0) - { - warnx("%s%snot owned by root: %s", jail ? jail : "", - jail ? ": " : "", cmd); - return 0; - } - - return 1; + struct stat sb; + + if(stat(cmd, &sb) == -1) + { + if(errno == EACCES || errno == ELOOP || errno == ENAMETOOLONG || + errno == ENOENT || errno == ENOTDIR) + { + warn("%s%scan't execute in jail: %s", jail ? jail : "", + jail ? ": " : "", cmd); + return 0; + } + + err(1, "%s%scouldn't stat file: %s", jail ? jail : "", + jail ? ": " : "", cmd); + } + + if(!(sb.st_mode & S_IFREG)) + { + warnx("%s%snot a regular file: %s", jail ? jail : "", + jail ? ": " : "", cmd); + return 0; + } + + if(sb.st_uid != 0) + { + warnx("%s%snot owned by root: %s", jail ? jail : "", + jail ? ": " : "", cmd); + return 0; + } + + return 1; } int run_overlay_command(const char* jail, const char* cmd, char* env[], - char* args[]) + char* args[]) { - if(args) - execve(cmd, args, env); - else - execle(cmd, cmd, NULL, env); - - warn("%s%serror executing: %s: %s", jail ? jail : "", - jail ? ": " : "", cmd); - return 0; + if(args) + execve(cmd, args, env); + else + execle(cmd, cmd, NULL, env); + + warn("%s%serror executing: %s: %s", jail ? jail : "", + jail ? ": " : "", cmd); + return 0; } int run_simple_command(const char* jail, const char* cmd, char* env[], - char* args[], int opts) + char* args[], int opts) { - pid_t pid; - int status = 0; - - if(opts & JAIL_RUN_NOFORK) - return run_overlay_command(jail, cmd, env, args); - - switch((pid = fork())) - { - case -1: - err(1, "couldn't fork child process"); - break; - - /* This is the child here */ - case 0: - if(args) - execve(cmd, args, env); - else - execle(cmd, cmd, NULL, env); - - exit(errno); - break; - - /* This is the parent process */ - default: - - /* If the processes exited then break out */ - if(waitpid(pid, &status, 0) == -1) - err(1, "couldn't wait on child process"); - - /* Return any status codes */ - if(WEXITSTATUS(status) != 0) - { - warnx("%s%serror executing: %s: %s", jail ? jail : "", - jail ? ": " : "", cmd, strerror(WEXITSTATUS(status))); - return 0; - } - - break; - } - - return 1; + pid_t pid; + int status = 0; + + if(opts & JAIL_RUN_NOFORK) + return run_overlay_command(jail, cmd, env, args); + + switch((pid = fork())) + { + case -1: + err(1, "couldn't fork child process"); + break; + + /* This is the child here */ + case 0: + if(args) + execve(cmd, args, env); + else + execle(cmd, cmd, NULL, env); + + exit(errno); + break; + + /* This is the parent process */ + default: + + /* If the processes exited then break out */ + if(waitpid(pid, &status, 0) == -1) + err(1, "couldn't wait on child process"); + + /* Return any status codes */ + if(WEXITSTATUS(status) != 0) + { + warnx("%s%serror executing: %s: %s", jail ? jail : "", + jail ? ": " : "", cmd, strerror(WEXITSTATUS(status))); + return 0; + } + + break; + } + + return 1; } /* read & write ends of a pipe */ @@ -286,157 +340,157 @@ int run_simple_command(const char* jail, const char* cmd, char* env[], #define STDERR 2 int run_dup_command(const char* jail, const char* cmd, char* env[], - char* args[], int opts) + char* args[], int opts) { - int outpipe[2]; - pid_t pid; + int outpipe[2]; + pid_t pid; - /* - * Special function to duplicate output of a command to two + /* + * Special function to duplicate output of a command to two * files. * * NOTE: Yes, I know this may seem like overkill, but system, * popen and all those guys would hang with certain rc scripts. * Those which opened a daemon in the background ('&') but still * kept their output going to the same stdin/stdout handles. - */ - - /* Create a pipe for the child process */ - if(pipe(outpipe) < 0) - return -1; - - switch(pid = fork()) - { - case -1: - err(1, "couldn't fork child process"); - break; - - /* This is the child here */ - case 0: - { - /* Fix up our end of the pipe */ - if(dup2(outpipe[WRITE_END], STDOUT) < 0 || - dup2(outpipe[WRITE_END], STDERR) < 0) - exit(errno); - - /* Okay, now run whatever command it was */ - if(args) - execve(cmd, args, env); - else - execle(cmd, cmd, NULL, env); - - /* In case it returns then have to do this to get - children to disconnect from stdout */ - fflush(stdout); - fclose(stdout); - close(outpipe[WRITE_END]); - - exit(errno); - } - break; - - - /* And this is the parent */ - default: - { - int console = -1; - int ret; - int status = 0; - fd_set readmask; - char buff[256]; - struct timeval timeout = { 0, 10000 }; - - FD_ZERO(&readmask); - - /* Open the console file and write the header */ - if(opts & JAIL_RUN_CONSOLE) - console = open(_PATH_CONSOLE, O_WRONLY | O_APPEND); - - /* No blocking on the child processes pipe */ - fcntl(outpipe[READ_END], F_SETFL, fcntl(outpipe[READ_END], F_GETFL, 0) | O_NONBLOCK); - - /* Loop until the process dies or no more output */ - while(1) - { - FD_SET(outpipe[READ_END], &readmask); - - if(select(FD_SETSIZE, &readmask, NULL, NULL, &timeout) == -1) - err(1, "couldn't select"); - - if(FD_ISSET(outpipe[READ_END], &readmask)) - { - /* Read text */ - while((ret = read(outpipe[READ_END], buff, 256)) > 0) - { - if(opts & JAIL_RUN_STDOUT) - write(STDOUT, buff, ret); - - if(opts & JAIL_RUN_STDERR) - write(STDERR, buff, ret); - - if(console != -1) - write(console, buff, ret); - } - } - - /* If the processes exited then break out */ - if(waitpid(pid, &status, WNOHANG) == pid) - break; - - /* Or if there's an error or end of file */ - if(ret == -1 && errno != EAGAIN || ret == 0) - break; - } - - /* Return any status codes */ - if(WEXITSTATUS(status) != 0) - { - warnx("%s%serror executing: %s: %s", jail ? jail : "", - jail ? ": " : "", cmd, strerror(WEXITSTATUS(status))); - return 0; - } - - /* Clean up */ - close(outpipe[READ_END]); - - if(console != -1) - close(console); - } - break; - } - - return 1; + */ + + /* Create a pipe for the child process */ + if(pipe(outpipe) < 0) + return -1; + + switch(pid = fork()) + { + case -1: + err(1, "couldn't fork child process"); + break; + + /* This is the child here */ + case 0: + { + /* Fix up our end of the pipe */ + if(dup2(outpipe[WRITE_END], STDOUT) < 0 || + dup2(outpipe[WRITE_END], STDERR) < 0) + exit(errno); + + /* Okay, now run whatever command it was */ + if(args) + execve(cmd, args, env); + else + execle(cmd, cmd, NULL, env); + + /* In case it returns then have to do this to get + children to disconnect from stdout */ + fflush(stdout); + fclose(stdout); + close(outpipe[WRITE_END]); + + exit(errno); + } + break; + + + /* And this is the parent */ + default: + { + int console = -1; + int ret; + int status = 0; + fd_set readmask; + char buff[256]; + struct timeval timeout = { 0, 10000 }; + + FD_ZERO(&readmask); + + /* Open the console file and write the header */ + if(opts & JAIL_RUN_CONSOLE) + console = open(_PATH_CONSOLE, O_WRONLY | O_APPEND); + + /* No blocking on the child processes pipe */ + fcntl(outpipe[READ_END], F_SETFL, fcntl(outpipe[READ_END], F_GETFL, 0) | O_NONBLOCK); + + /* Loop until the process dies or no more output */ + while(1) + { + FD_SET(outpipe[READ_END], &readmask); + + if(select(FD_SETSIZE, &readmask, NULL, NULL, &timeout) == -1) + err(1, "couldn't select"); + + if(FD_ISSET(outpipe[READ_END], &readmask)) + { + /* Read text */ + while((ret = read(outpipe[READ_END], buff, 256)) > 0) + { + if(opts & JAIL_RUN_STDOUT) + write(STDOUT, buff, ret); + + if(opts & JAIL_RUN_STDERR) + write(STDERR, buff, ret); + + if(console != -1) + write(console, buff, ret); + } + } + + /* If the processes exited then break out */ + if(waitpid(pid, &status, WNOHANG) == pid) + break; + + /* Or if there's an error or end of file */ + if(ret == -1 && errno != EAGAIN || ret == 0) + break; + } + + /* Return any status codes */ + if(WEXITSTATUS(status) != 0) + { + warnx("%s%serror executing: %s: %s", jail ? jail : "", + jail ? ": " : "", cmd, strerror(WEXITSTATUS(status))); + return 0; + } + + /* Clean up */ + close(outpipe[READ_END]); + + if(console != -1) + close(console); + } + break; + } + + return 1; } int run_jail_command(const char* jail, const char* cmd, char* args[], int opts) { - char* env[5]; - char* t; - int j; - - memset(env, 0, sizeof(env)); - -#define MAKE_ENV_VAR(n) \ - t = getenv(n); \ - if(t != NULL) \ - { \ - env[j] = alloca(strlen(n) + 2 + strlen(t)); \ - sprintf(env[j], "%s=%s", (char*)(n), t); \ - j++; \ - } - - /* Prepare an environment for the cmd */ - env[0] = "PATH=" _PATH_STDPATH; - j = 1; - - MAKE_ENV_VAR("TERM"); - MAKE_ENV_VAR("COLUMNS"); - MAKE_ENV_VAR("LINES"); - - if(opts & JAIL_RUN_OUTPUT) - return run_dup_command(jail, cmd, env, args, opts); - else - return run_simple_command(jail, cmd, env, args, opts); + char* env[5]; + char* t; + int j; + + memset(env, 0, sizeof(env)); + +#define MAKE_ENV_VAR(n) \ + t = getenv(n); \ + if(t != NULL) \ + { \ + env[j] = alloca(strlen(n) + 2 + strlen(t)); \ + sprintf(env[j], "%s=%s", (char*)(n), t); \ + j++; \ + } + + /* Prepare an environment for the cmd */ + env[0] = "PATH=" _PATH_STDPATH; + j = 1; + + MAKE_ENV_VAR("TERM"); + MAKE_ENV_VAR("COLUMNS"); + MAKE_ENV_VAR("LINES"); + + if(opts & JAIL_RUN_OUTPUT) + return run_dup_command(jail, cmd, env, args, opts); + else + return run_simple_command(jail, cmd, env, args, opts); } diff --git a/srcx/util.h b/srcx/util.h index af07e97..d39c1de 100644 --- a/srcx/util.h +++ b/srcx/util.h @@ -42,9 +42,11 @@ struct xprison; int translate_jail_name(const char* str); -size_t get_jail_sysctl(struct xprison** ret); int running_in_jail(); +kvm_t open_kvm_handle(char* jail, char* errbuf); +size_t get_jail_sysctl(struct xprison** ret); + #define JAIL_RUN_CONSOLE 0x00000001 /* Output stuff to the jail console if available */ #define JAIL_RUN_STDOUT 0x00000002 /* Output to stdout */ #define JAIL_RUN_STDERR 0x00000004 /* Output to stderr */ -- cgit v1.2.3