summaryrefslogtreecommitdiff
path: root/linux_priv.c
diff options
context:
space:
mode:
authorStanisław Pitucha <viraptor@gmail.com>2018-07-08 21:01:34 +1000
committerdormando <dormando@rydia.net>2019-08-28 14:36:03 -0700
commitec34cb718b64dccb91ba440846eafa97aa5ca5db (patch)
tree4108c0b7d2689294bf0dff421a36c9b512e418a4 /linux_priv.c
parent05693047c81a7ace8111d5e541d47f74b1d884a7 (diff)
downloadmemcached-ec34cb718b64dccb91ba440846eafa97aa5ca5db.tar.gz
Add a handler for seccomp crashes
When seccomp causes a crash, use a SIGSYS action and handle it to print out an error. Most functions are not allowed at that point (no buffered output, no ?printf functions, no abort, ...), so the implementation is as minimal as possible. Print out a message with the syscall number and exit the process (all threads).
Diffstat (limited to 'linux_priv.c')
-rw-r--r--linux_priv.c50
1 files changed, 49 insertions, 1 deletions
diff --git a/linux_priv.c b/linux_priv.c
index cc9aef3..c591caf 100644
--- a/linux_priv.c
+++ b/linux_priv.c
@@ -3,10 +3,58 @@
#include <errno.h>
#include <stdlib.h>
#include <sys/ioctl.h>
+#include <signal.h>
+#include <string.h>
#include "memcached.h"
+static char *kill_msg;
+// Make sure to preserve the ??? position in the string, or correct the offsets
+// in the syssig handler.
+#define KILL_MSG_STR "Seccomp policy failure. Caught syscall ???. This is " \
+ "either an exploit attempt, or your system is not supported yet.\n"
+
+static void handle_syssig(int signum, siginfo_t *si, void *thread_context) {
+#if defined(si_syscall)
+ int syscall_no = si->si_syscall;
+#else
+ // If system has no support for si_syscal, the information may not be
+ // precise.
+ int syscall_no = si->si_value.sival_int;
+#endif
+
+ // Replace the characters in the kill message with the syscall number. We
+ // can't safely printf (even write is not really valid, but we're crashing
+ // anyway).
+
+ kill_msg[39] = (syscall_no / 100) % 10 + '0';
+ kill_msg[40] = (syscall_no / 10) % 10 + '0';
+ kill_msg[41] = syscall_no % 10 + '0';
+ if (write(2, kill_msg, strlen(kill_msg)) == -1) {
+ // An error occurred, but we can't do anything about it here. This check
+ // is mostly to avoid the "ignoring return value of 'write'" error on
+ // distributions with broken gcc (no "ignore via cast to void" support).
+ }
+
+ // We can't use the nice exit() version because it causes at_exit handlers
+ // to be looked up and run. We can't take any locks while handling the
+ // signal, so _exit() is the only thing to do safely.
+ _exit(EXIT_FAILURE);
+}
+
+static const struct sigaction act = {
+ .sa_sigaction = handle_syssig,
+ .sa_flags = SA_SIGINFO,
+};
+
+void setup_privilege_violations_handler(void) {
+ kill_msg = malloc(strlen(KILL_MSG_STR)+1);
+ strcpy(kill_msg, KILL_MSG_STR);
+
+ sigaction(SIGSYS, &act, NULL);
+}
+
// If anything crosses the policy, kill the process.
-#define DENY_ACTION SCMP_ACT_KILL
+#define DENY_ACTION SCMP_ACT_TRAP
void drop_privileges(void) {
scmp_filter_ctx ctx = seccomp_init(DENY_ACTION);