summaryrefslogtreecommitdiff
path: root/srcx/util.c
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2004-05-19 17:27:00 +0000
committerStef Walter <stef@memberwebs.com>2004-05-19 17:27:00 +0000
commite70562b7b93e79372e230738038c62cf80436088 (patch)
treecd06dcfec1089712026e33643547c46d85d7820a /srcx/util.c
parent571095097eb025a6f1a4fbc24737084a1e367a9f (diff)
Proper preparing of kvm for jail
Diffstat (limited to 'srcx/util.c')
-rw-r--r--srcx/util.c657
1 files changed, 347 insertions, 310 deletions
diff --git a/srcx/util.c b/srcx/util.c
index 31ee3bd..137ca24 100644
--- a/srcx/util.c
+++ b/srcx/util.c
@@ -61,149 +61,178 @@ 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");
+ if(sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1)
+ 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)
+ if(sysctlbyname("security.jail.list", xp, &len, NULL, 0) == -1)
{
- free(xp);
- goto retry;
+ 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);
+void free_jail_sysctl(size_t len, struct xprison* xp)
+{
+ 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);
}
-int translate_jail_name(const char* str)
+struct xprison* find_jail(const char* str, size_t len, struct xprison* xp)
{
- struct xprison* xp = NULL;
- size_t len, i;
- char* e;
- int jid = -1;
+ int jid;
+ size_t i;
+ char* e;
+
+ if(len == 0 || xp == NULL)
+ return NULL;
- len = get_jail_sysctl(&xp);
- if(len == 0)
- goto done;
+ jid = strtol(str, &e, 10);
- jid = strtol(str, &e, 10);
+ /* If it was all a number ... */
+ if(!*e)
+ {
+ if(jid <= 0)
+ errx(1, "invalid jail id: %s", str);
- /* 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]);
+ }
+ }
- /* Validate the number */
for(i = 0; i < len; i++)
{
- if(jid == xp[i].pr_id)
- goto done;
+ if(strcmp(xp[i].pr_host, str) == 0)
+ return &(xp[i]);
}
- jid = -1;
- }
+ return NULL;
+}
- jid = -1;
+int translate_jail_name(const char* str)
+{
+ struct xprison* sxp = NULL;
+ struct xprison* xp = NULL;
+ size_t len;
+ int jid = -1;
- for(i = 0; i < len; i++)
- {
- if(strcmp(xp[i].pr_host, str) == 0)
+ len = get_jail_sysctl(&sxp);
+ if(sxp)
{
- jid = xp[i].pr_id;
- break;
- }
- }
+ xp = find_jail(str, sxp);
+ if(xp != NULL)
+ jid = xp->pr_id;
-done:
- if(xp)
- free(xp);
+ free(sxp);
+ }
- return jid;
+ return jid;
}
-kvm_t* open_kvm_handle(const char* jail, char* errbuf)
+int kvm_prepare_jail(struct xprison* xp)
{
- /*
- * 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;
- }
+ /*
+ * 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;
+ char* path;
+ int nodir = 0;
+ int nonull = 0;
+
+ path = (char*)alloca(strlen(_PATH_DEVNULL) + 2 + strlen(xp->pr_path));
- else if(errno == ENOENT)
+ strcpy(path, xp->pr_path);
+ strcat(path, _PATH_DEVNULL);
+
+ if(stat(path, &sb) == -1)
{
- nonull = 1;
+ if(errno == ENOTDIR)
+ {
+ nodir = 1;
+ nonull = 1;
+ }
+
+ else if(errno == ENOENT)
+ {
+ nonull = 1;
+ }
+
+ else
+ {
+ err(1, "couldn't stat file: %s", path);
+ }
}
- else
+ if(nodir)
{
- err(1, "%s%scouldn't stat file: %s", jail ? jail : "",
- jail ? ": " : "", _PATH_DEVNULL);
- }
- }
+ strcpy(path, xp->pr_path);
+ strcat(path, _PATH_DEV);
- if(nodir)
- {
- warnx("%s%sthe %s directory doesn't exist in jail. creating...",
- jail ? jail : "", jail ? ": " : "", _PATH_DEV);
+ warnx("the %s directory doesn't exist. creating...", path);
- 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);
- nonull = 0;
+ if(mkdir(path, 0) == -1 ||
+ chmod(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1)
+ {
+ warn("couldn't create %s directory", path);
+ return -1;
+ }
}
- }
- if(nonull)
- {
- mode_t mode = 0666 | S_IFCHR;
- dev_t dev = makedev(2, 2);
+ if(nonull)
+ {
+ mode_t mode = 0666 | S_IFCHR;
+ dev_t dev = makedev(2, 2);
+
+ strcpy(path, xp->pr_path);
+ strcat(path, _PATH_DEVNULL);
- warnx("%s%sthe %s device doesn't exist in jail. creating...",
- jail ? jail : "", jail ? ": " : "", _PATH_DEVNULL);
+ warnx("the %s device doesn't exist in jail. creating...", path);
- if(mknod(_PATH_DEVNULL, mode, dev) == -1)
- {
- warn("%s%scouldn't create %s device",
- jail ? jail : "", jail ? ": " : "", _PATH_DEVNULL);
+ if(mknod(path, mode, dev) == -1)
+ {
+ warn("couldn't create %s device", path);
+ return -1;
+ }
}
- }
- return kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf);
+ return 0;
}
/*
@@ -215,119 +244,120 @@ kvm_t* open_kvm_handle(const char* jail, 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;
+ int result = -1;
- kd = open_kvm_handle(NULL, errbuf);
- if(kd == NULL)
- errx(1, "couldn't connect to kernel: %s", errbuf);
+ kd = kvm_open(_PATH_DEVNULL, _PATH_DEVNULL, NULL, O_RDONLY, NULL);
+ if(kd == NULL)
+ return -1;
- 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);
- result = (kp->ki_flag & P_JAILED) ? 1 : 0;
- kvm_close(kd);
+ if(kp == NULL)
+ result = -1;
+ else
+ 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;
+ struct stat sb;
- if(stat(cmd, &sb) == -1)
- {
- if(errno == EACCES || errno == ELOOP || errno == ENAMETOOLONG ||
- errno == ENOENT || errno == ENOTDIR)
+ if(stat(cmd, &sb) == -1)
{
- warn("%s%scan't execute in jail: %s", jail ? jail : "",
- jail ? ": " : "", cmd);
- return 0;
- }
+ 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);
- }
+ 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 : "",
+ if(!(sb.st_mode & S_IFREG))
+ {
+ warnx("%s%snot a regular file: %s", jail ? jail : "",
jail ? ": " : "", cmd);
- return 0;
- }
+ return 0;
+ }
- if(sb.st_uid != 0)
- {
- warnx("%s%snot owned by root: %s", jail ? jail : "",
+ if(sb.st_uid != 0)
+ {
+ warnx("%s%snot owned by root: %s", jail ? jail : "",
jail ? ": " : "", cmd);
- return 0;
- }
+ return 0;
+ }
- return 1;
+ return 1;
}
int run_overlay_command(const char* jail, const char* cmd, char* env[],
char* args[])
{
- if(args)
- execve(cmd, args, env);
- else
- execle(cmd, cmd, NULL, env);
+ if(args)
+ execve(cmd, args, env);
+ else
+ execle(cmd, cmd, NULL, env);
- warn("%s%serror executing: %s: %s", jail ? jail : "",
+ warn("%s%serror executing: %s: %s", jail ? jail : "",
jail ? ": " : "", cmd);
- return 0;
+ return 0;
}
int run_simple_command(const char* jail, const char* cmd, char* env[],
char* args[], int opts)
{
- pid_t pid;
- int status = 0;
+ pid_t pid;
+ int status = 0;
- if(opts & JAIL_RUN_NOFORK)
- return run_overlay_command(jail, cmd, env, args);
+ 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;
+ 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);
+ /* This is the child here */
+ case 0:
+ if(args)
+ execve(cmd, args, env);
+ else
+ execle(cmd, cmd, NULL, env);
- exit(errno);
- break;
+ exit(errno);
+ break;
- /* This is the parent process */
- default:
+ /* 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");
+ /* 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;
- }
+ /* Return any status codes */
+ if(WEXITSTATUS(status) != 0)
+ {
+ warnx("%s%serror executing: %s: %s", jail ? jail : "",
+ jail ? ": " : "", cmd, strerror(WEXITSTATUS(status)));
+ return 0;
+ }
- break;
- }
+ break;
+ }
- return 1;
+ return 1;
}
/* read & write ends of a pipe */
@@ -342,155 +372,162 @@ int run_simple_command(const char* jail, const char* cmd, char* env[],
int run_dup_command(const char* jail, const char* cmd, char* env[],
char* args[], int opts)
{
- int outpipe[2];
- pid_t pid;
-
- /*
- * 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:
+ int outpipe[2];
+ pid_t pid;
+
+ /*
+ * 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())
{
- /* Fix up our end of the pipe */
- if(dup2(outpipe[WRITE_END], STDOUT) < 0 ||
- dup2(outpipe[WRITE_END], STDERR) < 0)
- exit(errno);
+ case -1:
+ err(1, "couldn't fork child process");
+ break;
- /* 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);
+ /* 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;
- if(select(FD_SETSIZE, &readmask, NULL, NULL, &timeout) == -1)
- err(1, "couldn't select");
- if(FD_ISSET(outpipe[READ_END], &readmask))
+ /* And this is the parent */
+ default:
{
- /* 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);
+ int console = -1;
+ int ret;
+ int status = 0;
+ int waited = 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);
+ }
+ }
+
+ /* Or if there's an error or end of file */
+ if(ret == -1 && errno != EAGAIN || ret == 0)
+ break;
+
+ /* If the processes exited then break out */
+ if(waitpid(pid, &status, WNOHANG) == pid)
+ {
+ waited = 1;
+ break;
+ }
+ }
+
+ if(!waited)
+ waitpid(pid, &status, 0);
+
+ /* 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)
- write(console, buff, ret);
- }
+ close(console);
}
-
- /* 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;
}
- break;
- }
- return 1;
+ 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);
}