Fix error reporting when sandboxed process is signaled.

BUG=None
TEST=Unittests pass.
TEST=security_Minijail_seccomp passes on leon.
TEST=/usr/bin/yes; killall yes; echo $? prints 143.
TEST=minijail0 -- /usr/bin/yes; killall yes; echo $? prints 143 (not 253).
TEST=minijail0 -S /dev/null -- /usr/bin/yes; echo $? prints 253.

Change-Id: I62f779da9b5b3a61f6aff4c9855e5b73669c9efe
Reviewed-on: https://chromium-review.googlesource.com/195627
Reviewed-by: Nam Nguyen <namnguyen@chromium.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Tested-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
Commit-Queue: Jorge Lucangeli Obes <jorgelo@chromium.org>
diff --git a/libminijail.c b/libminijail.c
index c764f81..fee657d 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -1198,10 +1198,25 @@
 		return -errno;
 
 	if (!WIFEXITED(st)) {
-		if (WIFSIGNALED(st))
+		int error_status = st;
+		if (WIFSIGNALED(st)) {
+			int signum = WTERMSIG(st);
 			warn("child process %d received signal %d",
-			     j->initpid, WTERMSIG(st));
-		return MINIJAIL_ERR_JAIL;
+			     j->initpid, signum);
+			/*
+			 * We return MINIJAIL_ERR_JAIL if the process received
+			 * SIGSYS, which happens when a syscall is blocked by
+			 * seccomp filters.
+			 * If not, we do what bash(1) does:
+			 * $? = 128 + signum
+			 */
+			if (signum == SIGSYS) {
+				error_status = MINIJAIL_ERR_JAIL;
+			} else {
+				error_status = 128 + signum;
+			}
+		}
+		return error_status;
 	}
 
 	int exit_status = WEXITSTATUS(st);
diff --git a/syscall_filter_unittest.c b/syscall_filter_unittest.c
index 68551f3..fb903c5 100644
--- a/syscall_filter_unittest.c
+++ b/syscall_filter_unittest.c
@@ -518,6 +518,8 @@
 			__NR_rt_sigreturn);
 	EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7,
 			__NR_exit);
+	EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9, BPF_RET+BPF_K,
+			SECCOMP_RET_KILL);
 
 	free(actual.filter);
 	fclose(policy);
@@ -549,6 +551,8 @@
 			__NR_rt_sigreturn);
 	EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7,
 			__NR_exit);
+	EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9, BPF_RET+BPF_K,
+			SECCOMP_RET_KILL);
 
 	free(actual.filter);
 	fclose(policy);