version 1.5, 2012/06/26 11:02:30 |
version 1.6, 2012/06/30 14:35:09 |
|
|
#include <sys/ioctl.h> |
#include <sys/ioctl.h> |
#include <sys/syscall.h> |
#include <sys/syscall.h> |
#include <sys/socket.h> |
#include <sys/socket.h> |
|
#include <sys/wait.h> |
|
|
#include <dev/systrace.h> |
#include <dev/systrace.h> |
|
|
#include <errno.h> |
#include <errno.h> |
#include <fcntl.h> |
#include <fcntl.h> |
#include <limits.h> |
#include <limits.h> |
|
#include <signal.h> |
#include <stdarg.h> |
#include <stdarg.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
|
|
}; |
}; |
|
|
struct ssh_sandbox { |
struct ssh_sandbox { |
int child_sock; |
|
int parent_sock; |
|
int systrace_fd; |
int systrace_fd; |
pid_t child_pid; |
pid_t child_pid; |
|
void (*osigchld)(int); |
}; |
}; |
|
|
struct ssh_sandbox * |
struct ssh_sandbox * |
ssh_sandbox_init(void) |
ssh_sandbox_init(void) |
{ |
{ |
struct ssh_sandbox *box; |
struct ssh_sandbox *box; |
int s[2]; |
|
|
|
debug3("%s: preparing systrace sandbox", __func__); |
debug3("%s: preparing systrace sandbox", __func__); |
box = xcalloc(1, sizeof(*box)); |
box = xcalloc(1, sizeof(*box)); |
if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == -1) |
|
fatal("%s: socketpair: %s", __func__, strerror(errno)); |
|
box->child_sock = s[0]; |
|
box->parent_sock = s[1]; |
|
box->systrace_fd = -1; |
box->systrace_fd = -1; |
box->child_pid = 0; |
box->child_pid = 0; |
|
box->osigchld = signal(SIGCHLD, SIG_IGN); |
|
|
return box; |
return box; |
} |
} |
|
|
void |
void |
ssh_sandbox_child(struct ssh_sandbox *box) |
ssh_sandbox_child(struct ssh_sandbox *box) |
{ |
{ |
char whatever = 0; |
|
|
|
close(box->parent_sock); |
|
/* Signal parent that we are ready */ |
|
debug3("%s: ready", __func__); |
debug3("%s: ready", __func__); |
if (atomicio(vwrite, box->child_sock, &whatever, 1) != 1) |
signal(SIGCHLD, box->osigchld); |
fatal("%s: write: %s", __func__, strerror(errno)); |
if (kill(getpid(), SIGSTOP) != 0) |
/* Wait for parent to signal for us to go */ |
fatal("%s: kill(%d, SIGSTOP)", __func__, getpid()); |
if (atomicio(read, box->child_sock, &whatever, 1) != 1) |
|
fatal("%s: read: %s", __func__, strerror(errno)); |
|
debug3("%s: started", __func__); |
debug3("%s: started", __func__); |
close(box->child_sock); |
|
} |
} |
|
|
static void |
static void |
ssh_sandbox_parent(struct ssh_sandbox *box, pid_t child_pid, |
ssh_sandbox_parent(struct ssh_sandbox *box, pid_t child_pid, |
const struct sandbox_policy *allowed_syscalls) |
const struct sandbox_policy *allowed_syscalls) |
{ |
{ |
int dev_systrace, i, j, found; |
int dev_systrace, i, j, found, status; |
char whatever = 0; |
pid_t pid; |
struct systrace_policy policy; |
struct systrace_policy policy; |
|
|
|
/* Wait for the child to send itself a SIGSTOP */ |
debug3("%s: wait for child %ld", __func__, (long)child_pid); |
debug3("%s: wait for child %ld", __func__, (long)child_pid); |
|
do { |
|
pid = waitpid(child_pid, &status, WUNTRACED); |
|
} while (pid == -1 && errno == EINTR); |
|
signal(SIGCHLD, box->osigchld); |
|
if (!WIFSTOPPED(status)) { |
|
if (WIFSIGNALED(status)) |
|
fatal("%s: child terminated with signal %d", |
|
__func__, WTERMSIG(status)); |
|
if (WIFEXITED(status)) |
|
fatal("%s: child exited with status %d", |
|
__func__, WEXITSTATUS(status)); |
|
fatal("%s: child not stopped", __func__); |
|
} |
|
debug3("%s: child %ld stopped", __func__, (long)child_pid); |
box->child_pid = child_pid; |
box->child_pid = child_pid; |
close(box->child_sock); |
|
/* Wait for child to signal that it is ready */ |
|
if (atomicio(read, box->parent_sock, &whatever, 1) != 1) |
|
fatal("%s: read: %s", __func__, strerror(errno)); |
|
debug3("%s: child %ld ready", __func__, (long)child_pid); |
|
|
|
/* Set up systracing of child */ |
/* Set up systracing of child */ |
if ((dev_systrace = open("/dev/systrace", O_RDONLY)) == -1) |
if ((dev_systrace = open("/dev/systrace", O_RDONLY)) == -1) |
|
|
|
|
/* Signal the child to start running */ |
/* Signal the child to start running */ |
debug3("%s: start child %ld", __func__, (long)child_pid); |
debug3("%s: start child %ld", __func__, (long)child_pid); |
if (atomicio(vwrite, box->parent_sock, &whatever, 1) != 1) |
if (kill(box->child_pid, SIGCONT) != 0) |
fatal("%s: write: %s", __func__, strerror(errno)); |
fatal("%s: kill(%d, SIGCONT)", __func__, box->child_pid); |
close(box->parent_sock); |
|
} |
} |
|
|
void |
void |