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/util.c | 662 ++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 358 insertions(+), 304 deletions(-) (limited to 'srcx/util.c') 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); } -- cgit v1.2.3