From 25e8461cbe56a3f035df145d9d762b65aa3eedb7 Mon Sep 17 00:00:00 2001
From: Jorge Gomes <jorge@lip.pt>
Date: Mon, 13 Feb 2017 20:37:17 +0000
Subject: [PATCH] fix event.c for seccomp and ptrace

---
 src/tracee/event.c | 129 ++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 88 insertions(+), 41 deletions(-)

diff --git src/tracee/event.c src/tracee/event.c
index bafc3c5..64166f6 100644
--- src/tracee/event.c
+++ src/tracee/event.c
@@ -20,6 +20,7 @@
  * 02110-1301 USA.
  */
 
+#include <stdio.h>
 #include <sched.h>      /* CLONE_*,  */
 #include <sys/types.h>  /* pid_t, */
 #include <sys/ptrace.h> /* ptrace(1), PTRACE_*, */
@@ -47,6 +48,7 @@
 #include "attribute.h"
 #include "compat.h"
 
+
 /**
  * Start @tracee->exe with the given @argv[].  This function
  * returns -errno if an error occurred, otherwise 0.
@@ -205,6 +207,27 @@ static void print_talloc_hierarchy(int signum, siginfo_t *siginfo UNUSED, void *
 static int last_exit_status = -1;
 
 /**
+ * Check if kernel >= 4.8
+ */
+bool is_kernel_4_8(void) {
+	struct utsname utsname;
+        int status;
+        static bool version_48 = false;
+        static int major = 0;
+        static int minor = 0;
+        if (! major) {
+		status = uname(&utsname);
+		if (status < 0)
+			return false;
+		sscanf(utsname.release, "%d.%d", &major, &minor);
+		if (major >= 4)
+			if (minor >= 8)
+				version_48 = true;
+	}
+	return version_48;
+}
+
+/**
  * Check if this instance of PRoot can *technically* handle @tracee.
  */
 static void check_architecture(Tracee *tracee)
@@ -362,6 +385,7 @@ int event_loop()
 int handle_tracee_event(Tracee *tracee, int tracee_status)
 {
 	static bool seccomp_detected = false;
+        static bool seccomp_enabled = false;
 	pid_t pid = tracee->pid;
 	long status;
 	int signal;
@@ -432,6 +456,7 @@ int handle_tracee_event(Tracee *tracee, int tracee_status)
 			status = ptrace(PTRACE_SETOPTIONS, tracee->pid, NULL,
 					default_ptrace_options | PTRACE_O_TRACESECCOMP);
 			if (status < 0) {
+				seccomp_enabled = false;
 				/* ... otherwise use default options only.  */
 				status = ptrace(PTRACE_SETOPTIONS, tracee->pid, NULL,
 						default_ptrace_options);
@@ -440,8 +465,71 @@ int handle_tracee_event(Tracee *tracee, int tracee_status)
 					exit(EXIT_FAILURE);
 				}
 			}
+                        else { 
+				if (getenv("PROOT_NO_SECCOMP") == NULL)
+					seccomp_enabled = true;
+			}
 		}
 			/* Fall through. */
+		case SIGTRAP | PTRACE_EVENT_SECCOMP2 << 8:
+		case SIGTRAP | PTRACE_EVENT_SECCOMP << 8:
+
+			if (is_kernel_4_8()) { 
+	                	if (seccomp_enabled) {
+					if (!seccomp_detected) {
+						VERBOSE(tracee, 1, "ptrace acceleration (seccomp mode 2) enabled");
+						tracee->seccomp = ENABLED;
+						seccomp_detected = true;
+					}
+	
+					unsigned long flags = 0;
+					status = ptrace(PTRACE_GETEVENTMSG, tracee->pid, NULL, &flags);
+					if (status < 0)
+						break;
+           	             	}
+			}
+			else if (signal == (SIGTRAP | PTRACE_EVENT_SECCOMP2 << 8) ||
+                                 signal == (SIGTRAP | PTRACE_EVENT_SECCOMP << 8)) {
+				unsigned long flags = 0;
+
+				signal = 0;
+
+                	        if (!seccomp_detected) {
+                        	        VERBOSE(tracee, 1, "ptrace acceleration (seccomp mode 2) enabled");
+                                	tracee->seccomp = ENABLED;
+         	                	seccomp_detected = true;
+                	        }
+
+                        	/* Use the common ptrace flow if seccomp was
+				 * explicitely disabled for this tracee.  */
+        	                if (tracee->seccomp != ENABLED)
+                	                break;
+
+                        	status = ptrace(PTRACE_GETEVENTMSG, tracee->pid, NULL, &flags);
+                        	if (status < 0)
+                                	break;
+
+                        	/* Use the common ptrace flow when
+				 * sysexit has to be handled.  */
+                        	if ((flags & FILTER_SYSEXIT) != 0) {
+                                	tracee->restart_how = PTRACE_SYSCALL;
+                                	break;
+                        	}
+
+                        	/* Otherwise, handle the sysenter
+                        	 * stage right now.  */
+                        	tracee->restart_how = PTRACE_CONT;
+                        	translate_syscall(tracee);
+
+                        	/* This syscall has disabled seccomp, so move
+                        	 * the ptrace flow back to the common path to
+                       		 * ensure its sysexit will be handled.  */
+                        	if (tracee->seccomp == DISABLING)
+                                	tracee->restart_how = PTRACE_SYSCALL;
+                        	break;
+                	}
+
+			/* Fall through. */
 		case SIGTRAP | 0x80:
 			signal = 0;
 
@@ -490,47 +578,6 @@ int handle_tracee_event(Tracee *tracee, int tracee_status)
 			}
 			break;
 
-		case SIGTRAP | PTRACE_EVENT_SECCOMP2 << 8:
-		case SIGTRAP | PTRACE_EVENT_SECCOMP << 8: {
-			unsigned long flags = 0;
-
-			signal = 0;
-
-			if (!seccomp_detected) {
-				VERBOSE(tracee, 1, "ptrace acceleration (seccomp mode 2) enabled");
-				tracee->seccomp = ENABLED;
-				seccomp_detected = true;
-			}
-
-			/* Use the common ptrace flow if seccomp was
-			 * explicitely disabled for this tracee.  */
-			if (tracee->seccomp != ENABLED)
-				break;
-
-			status = ptrace(PTRACE_GETEVENTMSG, tracee->pid, NULL, &flags);
-			if (status < 0)
-				break;
-
-			/* Use the common ptrace flow when
-			 * sysexit has to be handled.  */
-			if ((flags & FILTER_SYSEXIT) != 0) {
-				tracee->restart_how = PTRACE_SYSCALL;
-				break;
-			}
-
-			/* Otherwise, handle the sysenter
-			 * stage right now.  */
-			tracee->restart_how = PTRACE_CONT;
-			translate_syscall(tracee);
-
-			/* This syscall has disabled seccomp, so move
-			 * the ptrace flow back to the common path to
-			 * ensure its sysexit will be handled.  */
-			if (tracee->seccomp == DISABLING)
-				tracee->restart_how = PTRACE_SYSCALL;
-			break;
-		}
-
 		case SIGTRAP | PTRACE_EVENT_VFORK << 8:
 			signal = 0;
 			(void) new_child(tracee, CLONE_VFORK);
