aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2012-03-05 01:57:19 -0500
committerMike Frysinger <vapier@gentoo.org>2012-03-06 14:00:33 -0500
commit19c9819364989b4831917c880af9a977beb5ce83 (patch)
tree773b8b330002e46e288d7ec198ca204118b5d929
parentlibsandbox: add likely/unlikely support (diff)
downloadsandbox-19c9819364989b4831917c880af9a977beb5ce83.tar.gz
sandbox-19c9819364989b4831917c880af9a977beb5ce83.tar.bz2
sandbox-19c9819364989b4831917c880af9a977beb5ce83.zip
libsandbox: set syscall error rather than killing on violations
If we kill the app, then the syscall that we flagged as a violation will complete, and our entire purpose has failed -- to prevent modifications to the protected paths. Instead, set the syscall number to an invalid one, continue the syscall, then set the syscall return value (which will become the errno) after the syscall finishes. This way the bad syscall isn't actually executed, and we let the app continue to run like normal. URL: http://bugs.gentoo.org/406543 Reported-by: Marijn Schouten <hkbst@gentoo.org> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
-rw-r--r--libsandbox/trace.c28
-rw-r--r--libsandbox/trace/linux/arch.c14
-rw-r--r--libsandbox/trace/linux/bfin.c10
-rw-r--r--libsandbox/trace/linux/common.c1
-rw-r--r--libsandbox/trace/linux/hppa.c10
-rw-r--r--libsandbox/trace/linux/i386.c10
-rw-r--r--libsandbox/trace/linux/x86_64.c10
7 files changed, 65 insertions, 18 deletions
diff --git a/libsandbox/trace.c b/libsandbox/trace.c
index 45bb5d4..5ccab87 100644
--- a/libsandbox/trace.c
+++ b/libsandbox/trace.c
@@ -76,6 +76,11 @@ static long do_peekuser(long offset)
return do_ptrace(PTRACE_PEEKUSER, (void *)offset, NULL);
}
+static long do_pokeuser(long offset, long val)
+{
+ return do_ptrace(PTRACE_POKEUSER, (void *)offset, (void *)val);
+}
+
static long do_peekdata(long offset)
{
return do_ptrace(PTRACE_PEEKDATA, (void *)offset, NULL);
@@ -384,6 +389,9 @@ static bool trace_check_syscall(const struct syscall_entry *se, void *regs)
#ifndef trace_get_regs
# define trace_get_regs(regs) do_ptrace(PTRACE_GETREGS, NULL, regs)
#endif
+#ifndef trace_set_regs
+# define trace_set_regs(regs) do_ptrace(PTRACE_SETREGS, NULL, regs)
+#endif
/* Some arches (like sparc) don't implement PTRACE_PEEK* ...
* more asshats !
*/
@@ -394,13 +402,14 @@ static bool trace_check_syscall(const struct syscall_entry *se, void *regs)
static void trace_loop(void)
{
trace_regs regs;
- bool before_syscall;
+ bool before_syscall, fake_syscall_ret;
long ret;
int nr, exec_state;
const struct syscall_entry *se, *tbl_at_fork;
exec_state = 0;
before_syscall = true;
+ fake_syscall_ret = false;
tbl_at_fork = NULL;
do {
ret = do_ptrace(PTRACE_SYSCALL, NULL, NULL);
@@ -431,14 +440,21 @@ static void trace_loop(void)
_SB_DEBUG("%s:%i", se ? se->name : "IDK", nr);
if (!trace_check_syscall(se, &regs)) {
if (is_env_on(ENV_SANDBOX_DEBUG))
- SB_EINFO("trace_loop", " destroying after %s\n",
+ SB_EINFO("trace_loop", " forcing EPERM after %s\n",
se->name);
- do_ptrace(PTRACE_KILL, NULL, NULL);
- exit(1);
+ trace_set_sysnum(&regs, -1);
+ fake_syscall_ret = true;
}
} else {
int err;
- ret = trace_result(&regs, &err);
+
+ if (unlikely(fake_syscall_ret)) {
+ ret = -1;
+ err = EPERM;
+ trace_set_ret(&regs, err);
+ fake_syscall_ret = false;
+ } else
+ ret = trace_result(&regs, &err);
__SB_DEBUG(" = %li", ret);
if (err) {
@@ -480,7 +496,7 @@ void trace_main(const char *filename, char *const argv[])
}
trace_pid = fork();
- if (trace_pid == -1) {
+ if (unlikely(trace_pid == -1)) {
SB_EERROR("ISE:trace_main ", "vfork() failed: %s\n",
strerror(errno));
sb_abort();
diff --git a/libsandbox/trace/linux/arch.c b/libsandbox/trace/linux/arch.c
index de86109..df2fe5b 100644
--- a/libsandbox/trace/linux/arch.c
+++ b/libsandbox/trace/linux/arch.c
@@ -20,4 +20,18 @@
#ifdef SB_NO_TRACE_ARCH
# warning "trace: sorry, no support for your architecture"
# define SB_NO_TRACE
+#else
+# ifdef trace_sysnum_puser
+
+static int trace_sysnum(void)
+{
+ return do_peekuser(trace_sysnum_puser);
+}
+
+static void trace_set_sysnum(void *vregs, long nr)
+{
+ do_pokeuser(trace_sysnum_puser, nr);
+}
+
+# endif
#endif
diff --git a/libsandbox/trace/linux/bfin.c b/libsandbox/trace/linux/bfin.c
index 4188034..60a8ef8 100644
--- a/libsandbox/trace/linux/bfin.c
+++ b/libsandbox/trace/linux/bfin.c
@@ -1,7 +1,4 @@
-static int trace_sysnum(void)
-{
- return do_peekuser(PT_ORIG_P0);
-}
+#define trace_sysnum_puser PT_ORIG_P0
static long trace_raw_ret(void *vregs)
{
@@ -9,6 +6,11 @@ static long trace_raw_ret(void *vregs)
return regs->r0;
}
+static void trace_set_ret(void *vregs, int err)
+{
+ do_pokeuser(PT_R0, -err);
+}
+
static unsigned long trace_arg(void *vregs, int num)
{
trace_regs *regs = vregs;
diff --git a/libsandbox/trace/linux/common.c b/libsandbox/trace/linux/common.c
index 287af0a..de74caf 100644
--- a/libsandbox/trace/linux/common.c
+++ b/libsandbox/trace/linux/common.c
@@ -1,4 +1,5 @@
static long do_peekuser(long offset);
+static long do_pokeuser(long offset, long val);
static int trace_errno(long err)
{
diff --git a/libsandbox/trace/linux/hppa.c b/libsandbox/trace/linux/hppa.c
index d98310f..b7fab1c 100644
--- a/libsandbox/trace/linux/hppa.c
+++ b/libsandbox/trace/linux/hppa.c
@@ -1,7 +1,4 @@
-static int trace_sysnum(void)
-{
- return do_peekuser(20 * 4); /* PT_GR20 */
-}
+#define trace_sysnum_puser (20 * 4) /* PT_GR20 */
static long trace_raw_ret(void *vregs)
{
@@ -9,6 +6,11 @@ static long trace_raw_ret(void *vregs)
return regs->gr[28];
}
+static void trace_set_ret(void *vregs, int err)
+{
+ do_pokeuser(28 * 4 /* PT_GR28 */, -err);
+}
+
static unsigned long trace_arg(void *vregs, int num)
{
trace_regs *regs = vregs;
diff --git a/libsandbox/trace/linux/i386.c b/libsandbox/trace/linux/i386.c
index 7508e25..9a3f590 100644
--- a/libsandbox/trace/linux/i386.c
+++ b/libsandbox/trace/linux/i386.c
@@ -1,7 +1,4 @@
-static int trace_sysnum(void)
-{
- return do_peekuser(4 * ORIG_EAX);
-}
+#define trace_sysnum_puser (4 * ORIG_EAX)
static long trace_raw_ret(void *vregs)
{
@@ -9,6 +6,11 @@ static long trace_raw_ret(void *vregs)
return regs->eax;
}
+static void trace_set_ret(void *vregs, int err)
+{
+ do_pokeuser(EAX, -err);
+}
+
static unsigned long trace_arg(void *vregs, int num)
{
trace_regs *regs = vregs;
diff --git a/libsandbox/trace/linux/x86_64.c b/libsandbox/trace/linux/x86_64.c
index b864801..0110302 100644
--- a/libsandbox/trace/linux/x86_64.c
+++ b/libsandbox/trace/linux/x86_64.c
@@ -47,6 +47,16 @@ static long trace_raw_ret(void *vregs)
return pers_is_32() ? (int)regs->rax : regs->rax;
}
+static void trace_set_sysnum(void *vregs, long nr)
+{
+ do_pokeuser(8 * ORIG_RAX, nr);
+}
+
+static void trace_set_ret(void *vregs, int err)
+{
+ do_pokeuser(8 * RAX, -err);
+}
+
static unsigned long trace_arg(void *vregs, int num)
{
trace_regs *regs = vregs;