Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/817997/?format=api
{ "id": 817997, "url": "http://patchwork.ozlabs.org/api/patches/817997/?format=api", "web_url": "http://patchwork.ozlabs.org/project/lede/patch/20170924225633.23094-1-sojkam1@fel.cvut.cz/", "project": { "id": 54, "url": "http://patchwork.ozlabs.org/api/projects/54/?format=api", "name": "LEDE development", "link_name": "lede", "list_id": "lede-dev.lists.infradead.org", "list_email": "lede-dev@lists.infradead.org", "web_url": "http://lede-project.org/", "scm_url": "", "webscm_url": "http://git.lede-project.org/", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20170924225633.23094-1-sojkam1@fel.cvut.cz>", "list_archive_url": null, "date": "2017-09-24T22:56:33", "name": "[LEDE-DEV,procd,v2,10/17] seccomp: Log seccomp violations with utrace", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": false, "hash": "30a8e6107c4b705cfb06bb87ce0d406c5ae91eaa", "submitter": { "id": 14651, "url": "http://patchwork.ozlabs.org/api/people/14651/?format=api", "name": "Michal Sojka", "email": "sojkam1@fel.cvut.cz" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/lede/patch/20170924225633.23094-1-sojkam1@fel.cvut.cz/mbox/", "series": [ { "id": 4851, "url": "http://patchwork.ozlabs.org/api/series/4851/?format=api", "web_url": "http://patchwork.ozlabs.org/project/lede/list/?series=4851", "date": "2017-09-24T22:56:33", "name": null, "version": 2, "mbox": "http://patchwork.ozlabs.org/series/4851/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/817997/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/817997/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<lede-dev-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org", "Authentication-Results": [ "ozlabs.org; spf=none (mailfrom)\n\tsmtp.mailfrom=lists.infradead.org (client-ip=65.50.211.133;\n\thelo=bombadil.infradead.org;\n\tenvelope-from=lede-dev-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org;\n\treceiver=<UNKNOWN>)", "ozlabs.org; dkim=pass (2048-bit key;\n\tunprotected) header.d=lists.infradead.org\n\theader.i=@lists.infradead.org header.b=\"qXEQTM2i\"; \n\tdkim-atps=neutral" ], "Received": [ "from bombadil.infradead.org (bombadil.infradead.org\n\t[65.50.211.133])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3y0jKD4wx3z9t3t\n\tfor <incoming@patchwork.ozlabs.org>;\n\tMon, 25 Sep 2017 08:57:20 +1000 (AEST)", "from localhost ([127.0.0.1] helo=bombadil.infradead.org)\n\tby bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux))\n\tid 1dwFpn-0004xG-0C; Sun, 24 Sep 2017 22:57:11 +0000", "from smtpx.feld.cvut.cz ([147.32.192.33])\n\tby bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux))\n\tid 1dwFpj-0004kI-5F\n\tfor lede-dev@lists.infradead.org; Sun, 24 Sep 2017 22:57:09 +0000", "from localhost (unknown [192.168.200.7])\n\tby smtpx.feld.cvut.cz (Postfix) with ESMTP id 123F8DC338;\n\tMon, 25 Sep 2017 00:56:46 +0200 (CEST)", "from smtpx.feld.cvut.cz ([192.168.200.6])\n\tby localhost (styx.feld.cvut.cz [192.168.200.7]) (amavisd-new,\n\tport 10054)\n\twith ESMTP id 17RUaaJITY5M; Mon, 25 Sep 2017 00:56:43 +0200 (CEST)", "from imap.feld.cvut.cz (imap.feld.cvut.cz [147.32.192.34])\n\tby smtpx.feld.cvut.cz (Postfix) with ESMTP id 5AF29DC27C;\n\tMon, 25 Sep 2017 00:56:43 +0200 (CEST)", "from wsh by steelpick.2x.cz with local (Exim 4.89)\n\t(envelope-from <sojkam1@fel.cvut.cz>)\n\tid 1dwFpL-00061D-2j; Mon, 25 Sep 2017 00:56:43 +0200" ], "DKIM-Signature": "v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;\n\td=lists.infradead.org; s=bombadil.20170209; h=Sender:\n\tContent-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe:\n\tList-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Subject:References:\n\tIn-Reply-To:Message-Id:Date:To:From:Reply-To:Content-ID:Content-Description:\n\tResent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:\n\tList-Owner; bh=fK+w4gkTsDm8aG/H+Uv/dLHx5mZz1SUeMlrP/HO3N9U=;\n\tb=qXEQTM2iz4KGZG\n\tobT14vhIHy51VTY4JrKVCwYfge+3iR6Rs/YmAz0pAoKW9e6B30WcrSGcjSyGH7zrFQxwiXcYR4yuX\n\toyfSHwwPHGbeiT/GVS8pkFYFlX6SkEL1+U9I2Wwf7W9/8GhnuzuAmqEvXA8Sq7Yl/zjojFtEucFWS\n\tVe1zVjB7OGU+ZyFb99JCU6+KynbJAQju17XrqKZNk5ymf19wV7vhyCOyh2TIQbJRXg/yh/uYbE33r\n\tYWI4cvBkvUQ+zfmGb3XX/2mpHI4D59DDoULR8tDxlikg/3bERYnfWMFYw2cVza0hTi0Z3Kd/NFaka\n\tJqyq957qeLvi9eOEjKSw==;", "X-Virus-Scanned": "IMAP STYX AMAVIS", "From": "Michal Sojka <sojkam1@fel.cvut.cz>", "To": "lede-dev@lists.infradead.org,\n\tJohn Crispin <john@phrozen.org>", "Date": "Mon, 25 Sep 2017 00:56:33 +0200", "Message-Id": "<20170924225633.23094-1-sojkam1@fel.cvut.cz>", "X-Mailer": "git-send-email 2.14.1", "In-Reply-To": "<87mv5j9086.fsf@steelpick.2x.cz>", "References": "<87mv5j9086.fsf@steelpick.2x.cz>", "X-CRM114-Version": "20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 ", "X-CRM114-CacheID": "sfid-20170924_155707_553162_382E505E ", "X-CRM114-Status": "GOOD ( 18.86 )", "X-Spam-Score": "-4.2 (----)", "X-Spam-Report": "SpamAssassin version 3.4.1 on bombadil.infradead.org summary:\n\tContent analysis details: (-4.2 points)\n\tpts rule name description\n\t---- ----------------------\n\t--------------------------------------------------\n\t-2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/,\n\tmedium trust [147.32.192.33 listed in list.dnswl.org]\n\t-0.0 RP_MATCHES_RCVD Envelope sender domain matches handover relay\n\tdomain\n\t-1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1%\n\t[score: 0.0000]", "Subject": "[LEDE-DEV] [PATCH procd v2 10/17] seccomp: Log seccomp violations\n\twith utrace", "X-BeenThere": "lede-dev@lists.infradead.org", "X-Mailman-Version": "2.1.21", "Precedence": "list", "List-Id": "<lede-dev.lists.infradead.org>", "List-Unsubscribe": "<http://lists.infradead.org/mailman/options/lede-dev>,\n\t<mailto:lede-dev-request@lists.infradead.org?subject=unsubscribe>", "List-Archive": "<http://lists.infradead.org/pipermail/lede-dev/>", "List-Post": "<mailto:lede-dev@lists.infradead.org>", "List-Help": "<mailto:lede-dev-request@lists.infradead.org?subject=help>", "List-Subscribe": "<http://lists.infradead.org/mailman/listinfo/lede-dev>,\n\t<mailto:lede-dev-request@lists.infradead.org?subject=subscribe>", "Cc": "Michal Sojka <sojkam1@fel.cvut.cz>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"us-ascii\"", "Content-Transfer-Encoding": "7bit", "Sender": "\"Lede-dev\" <lede-dev-bounces@lists.infradead.org>", "Errors-To": "lede-dev-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org" }, "content": "Older kernel version shipped by LEDE/OpenWrt contained patch\ntarget/linux/generic/patches-3.18/999-seccomp_log.patch that logged\nseccomp violations. For some reason, newer kernels do not have this\npatch. Without this kind of logging, it is very hard to setup seccomp\nwhitelist properly, so this commit modifies utrace to serve as a\nlogger for seccomp violations.\n\nWith this patch, when utrace is executed via seccomp-trace symlink, it\ndoes not trace normal syscalls but only seccomp violations and logs\nthem to syslog. For example:\n\n seccomp-trace: uci[3955] tried to call non-whitelisted syscall: ftruncate64 (see /etc/seccomp/myservice.json)\n\nCompared to the kernel-based logging, this approach gives users more\ninformation - which json whitelist needs to be extended. This is\nespecially useful for services, which fork many diverse children such\nas shell scripts.\n\nSigned-off-by: Michal Sojka <sojkam1@fel.cvut.cz>\n---\n jail/seccomp-bpf.h | 1 +\n jail/seccomp.c | 4 +-\n trace/trace.c | 143 +++++++++++++++++++++++++++++++++++++++++++----------\n 3 files changed, 121 insertions(+), 27 deletions(-)", "diff": "diff --git a/jail/seccomp-bpf.h b/jail/seccomp-bpf.h\nindex 82c0669..fc3ffe7 100644\n--- a/jail/seccomp-bpf.h\n+++ b/jail/seccomp-bpf.h\n@@ -41,6 +41,7 @@\n #define SECCOMP_RET_TRAP\t0x00030000U /* disallow and force a SIGSYS */\n #define SECCOMP_RET_ERRNO\t0x00050000U /* returns an errno */\n #define SECCOMP_RET_LOG\t\t0x00070000U\n+#define SECCOMP_RET_TRACE\t0x7ff00000U /* pass to a tracer or disallow */\n #define SECCOMP_RET_ALLOW\t0x7fff0000U /* allow */\n #define SECCOMP_RET_ERROR(x)\t(SECCOMP_RET_ERRNO | ((x) & 0x0000ffffU))\n #define SECCOMP_RET_LOGGER(x)\t(SECCOMP_RET_LOG | ((x) & 0x0000ffffU))\ndiff --git a/jail/seccomp.c b/jail/seccomp.c\nindex dcd19ec..1a2bb27 100644\n--- a/jail/seccomp.c\n+++ b/jail/seccomp.c\n@@ -118,8 +118,8 @@ int install_syscall_filter(const char *argv, const char *file)\n \t}\n \n \tif (default_policy)\n-\t\t/* return -1 and set errno */\n-\t\tset_filter(&filter[idx], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_LOGGER(default_policy));\n+\t\t/* notify tracer; without tracer return -1 and set errno to ENOSYS */\n+\t\tset_filter(&filter[idx], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_TRACE);\n \telse\n \t\t/* kill the process */\n \t\tset_filter(&filter[idx], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_KILL);\ndiff --git a/trace/trace.c b/trace/trace.c\nindex 9d3cd0a..5189cfb 100644\n--- a/trace/trace.c\n+++ b/trace/trace.c\n@@ -12,8 +12,10 @@\n */\n \n #define _GNU_SOURCE\n+#include <fcntl.h>\n #include <stddef.h>\n #include <sys/ptrace.h>\n+#include <sys/stat.h>\n #include <sys/types.h>\n #include <sys/user.h>\n #include <sys/wait.h>\n@@ -49,18 +51,33 @@\n # endif\n #define reg_syscall_nr\t(EF_REG2 / 4)\n #elif defined(__arm__)\n+#include <asm/ptrace.h>\t\t/* for PTRACE_SET_SYSCALL */\n #define reg_syscall_nr\t_offsetof(struct user, regs.uregs[7])\n+# if defined(__ARM_EABI__)\n+# define reg_retval_nr\t_offsetof(struct user, regs.uregs[0])\n+# endif\n #else\n #error tracing is not supported on this architecture\n #endif\n \n+enum mode {\n+\tUTRACE,\n+\tSECCOMP_TRACE,\n+} mode = UTRACE;\n+\n+#define PROC_NAME(mode) (mode == UTRACE ? \"utrace\" : \"seccomp-trace\")\n+\n #define INFO(fmt, ...) do { \\\n-\tfprintf(stderr, \"utrace: \"fmt, ## __VA_ARGS__); \\\n+\tfprintf(stderr, \"%s: \"fmt, PROC_NAME(mode), ## __VA_ARGS__); \\\n } while (0)\n \n #define ERROR(fmt, ...) do { \\\n-\tsyslog(LOG_ERR, \"utrace: \"fmt, ## __VA_ARGS__); \\\n-\tfprintf(stderr, \"utrace: \"fmt, ## __VA_ARGS__); \\\n+\tsyslog(LOG_ERR, \"%s: \"fmt, PROC_NAME(mode), ## __VA_ARGS__); \\\n+\tfprintf(stderr, \"%s: \"fmt, PROC_NAME(mode), ## __VA_ARGS__); \\\n+} while (0)\n+\n+#define LOGERR(fmt, ...) do { \\\n+\tsyslog(LOG_ERR, \"%s: \"fmt, PROC_NAME(mode), ## __VA_ARGS__); \\\n } while (0)\n \n struct tracee {\n@@ -70,9 +87,12 @@ struct tracee {\n \n static struct tracee tracer;\n static int *syscall_count;\n+static int violation_count;\n static struct blob_buf b;\n static int syscall_max;\n static int debug;\n+char *json = NULL;\n+int ptrace_restart;\n \n static int max_syscall = ARRAY_SIZE(syscall_names);\n \n@@ -102,11 +122,13 @@ static void print_syscalls(int policy, const char *json)\n \tvoid *c;\n \tint i;\n \n-\tset_syscall(\"rt_sigaction\", 1);\n-\tset_syscall(\"sigreturn\", 1);\n-\tset_syscall(\"rt_sigreturn\", 1);\n-\tset_syscall(\"exit_group\", 1);\n-\tset_syscall(\"exit\", 1);\n+\tif (mode == UTRACE) {\n+\t\tset_syscall(\"rt_sigaction\", 1);\n+\t\tset_syscall(\"sigreturn\", 1);\n+\t\tset_syscall(\"rt_sigreturn\", 1);\n+\t\tset_syscall(\"exit_group\", 1);\n+\t\tset_syscall(\"exit\", 1);\n+\t}\n \n \tstruct syscall sorted[ARRAY_SIZE(syscall_names)];\n \n@@ -151,6 +173,30 @@ static void print_syscalls(int policy, const char *json)\n \n }\n \n+static void report_seccomp_vialation(pid_t pid, unsigned syscall)\n+{\n+\tchar buf[200];\n+\tsnprintf(buf, sizeof(buf), \"/proc/%d/cmdline\", pid);\n+\tint f = open(buf, O_RDONLY);\n+\tint r = read(f, buf, sizeof(buf) - 1);\n+\tif (r >= 0)\n+\t\tbuf[r] = 0;\n+\telse\n+\t\tstrcpy(buf, \"unknown?\");\n+\tclose(f);\n+\n+\tif (violation_count < INT_MAX)\n+\t\tviolation_count++;\n+\tif (syscall < ARRAY_SIZE(syscall_names)) {\n+\t\tsyscall_count[syscall]++;\n+\t\tLOGERR(\"%s[%u] tried to call non-whitelisted syscall: %s (see %s)\\n\",\n+\t\t buf, pid, syscall_names[syscall], json);\n+\t} else {\n+\t\tLOGERR(\"%s[%u] tried to call non-whitelisted syscall: %d (see %s)\\n\",\n+\t\t buf, pid, syscall, json);\n+\t}\n+}\n+\n static void tracer_cb(struct uloop_process *c, int ret)\n {\n \tstruct tracee *tracee = container_of(c, struct tracee, proc);\n@@ -180,12 +226,21 @@ static void tracer_cb(struct uloop_process *c, int ret)\n \n \t\t\tptrace(PTRACE_GETEVENTMSG, c->pid, 0, &child->proc.pid);\n \t\t\tchild->proc.cb = tracer_cb;\n-\t\t\tptrace(PTRACE_SYSCALL, child->proc.pid, 0, 0);\n+\t\t\tptrace(ptrace_restart, child->proc.pid, 0, 0);\n \t\t\tuloop_process_add(&child->proc);\n \t\t\tif (debug)\n \t\t\t\tfprintf(stderr, \"Tracing new child %d\\n\", child->proc.pid);\n \t\t} else if ((ret >> 16) == PTRACE_EVENT_STOP) {\n \t\t\t/* Nothing special to do here */\n+\t\t} else if ((ret >> 8) == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8))) {\n+\t\t\tint syscall = ptrace(PTRACE_PEEKUSER, c->pid, reg_syscall_nr);\n+#if defined(__arm__)\n+\t\t\tptrace(PTRACE_SET_SYSCALL, c->pid, 0, -1);\n+\t\t\tptrace(PTRACE_POKEUSER, c->pid, reg_retval_nr, -ENOSYS);\n+#else\n+\t\t\tptrace(PTRACE_POKEUSER, c->pid, reg_syscall_nr, -1);\n+#endif\n+\t\t\treport_seccomp_vialation(c->pid, syscall);\n \t\t} else {\n \t\t\tinject_signal = WSTOPSIG(ret);\n \t\t\tif (debug)\n@@ -203,16 +258,20 @@ static void tracer_cb(struct uloop_process *c, int ret)\n \t\treturn;\n \t}\n \n-\tptrace(PTRACE_SYSCALL, c->pid, 0, inject_signal);\n+\tptrace(ptrace_restart, c->pid, 0, inject_signal);\n \tuloop_process_add(c);\n }\n \n int main(int argc, char **argv, char **envp)\n {\n-\tchar *json = NULL;\n \tint status, ch, policy = EPERM;\n \tpid_t child;\n \n+\t/* When invoked via seccomp-trace symlink, work as seccomp\n+\t * violation logger rather than as syscall tracer */\n+\tif (strstr(argv[0], \"seccomp-trace\"))\n+\t\tmode = SECCOMP_TRACE;\n+\n \twhile ((ch = getopt(argc, argv, \"f:p:\")) != -1) {\n \t\tswitch (ch) {\n \t\tcase 'f':\n@@ -224,6 +283,9 @@ int main(int argc, char **argv, char **envp)\n \t\t}\n \t}\n \n+\tif (!json)\n+\t\tjson = getenv(\"SECCOMP_FILE\");\n+\n \targc -= optind;\n \targv += optind;\n \n@@ -239,7 +301,9 @@ int main(int argc, char **argv, char **envp)\n \tif (child == 0) {\n \t\tchar **_argv = calloc(argc + 1, sizeof(char *));\n \t\tchar **_envp;\n-\t\tchar *preload = \"LD_PRELOAD=/lib/libpreload-trace.so\";\n+\t\tchar *preload = NULL;\n+\t\tconst char *old_preload = getenv(\"LD_PRELOAD\");\n+\t\tint newenv = 0;\n \t\tint envc = 0;\n \t\tint ret;\n \n@@ -248,9 +312,23 @@ int main(int argc, char **argv, char **envp)\n \t\twhile (envp[envc++])\n \t\t\t;\n \n-\t\t_envp = calloc(envc + 1, sizeof(char *));\n-\t\tmemcpy(&_envp[1], envp, envc * sizeof(char *));\n-\t\t*_envp = preload;\n+\t\t_envp = calloc(envc + 2, sizeof(char *));\n+\t\tswitch (mode) {\n+\t\tcase UTRACE:\n+\t\t\tpreload = \"/lib/libpreload-trace.so\";\n+\t\t\tnewenv = 1;\n+\t\t\tbreak;\n+\t\tcase SECCOMP_TRACE:\n+\t\t\tpreload = \"/lib/libpreload-seccomp.so\";\n+\t\t\tnewenv = 2;\n+\t\t\tasprintf(&_envp[1], \"SECCOMP_FILE=%s\", json ? json : \"\");\n+\t\t\tkill(getpid(), SIGSTOP);\n+\t\t\tbreak;\n+\t\t}\n+\t\tasprintf(&_envp[0], \"LD_PRELOAD=%s%s%s\", preload,\n+\t\t\t old_preload ? \":\" : \"\",\n+\t\t\t old_preload ? old_preload : \"\");\n+\t\tmemcpy(&_envp[newenv], envp, envc * sizeof(char *));\n \n \t\tret = execve(_argv[0], _argv, _envp);\n \t\tERROR(\"failed to exec %s: %s\\n\", _argv[0], strerror(errno));\n@@ -271,12 +349,19 @@ int main(int argc, char **argv, char **envp)\n \t\treturn -1;\n \t}\n \n-\tptrace(PTRACE_SEIZE, child, 0,\n-\t PTRACE_O_TRACESYSGOOD |\n-\t PTRACE_O_TRACEFORK |\n-\t PTRACE_O_TRACEVFORK |\n-\t PTRACE_O_TRACECLONE);\n-\tptrace(PTRACE_SYSCALL, child, 0, SIGCONT);\n+\tint ptrace_options = PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE;\n+\tswitch (mode) {\n+\tcase UTRACE:\n+\t\tptrace_options |= PTRACE_O_TRACESYSGOOD;\n+\t\tptrace_restart = PTRACE_SYSCALL;\n+\t\tbreak;\n+\tcase SECCOMP_TRACE:\n+\t\tptrace_options |= PTRACE_O_TRACESECCOMP;\n+\t\tptrace_restart = PTRACE_CONT;\n+\t\tbreak;\n+\t}\n+\tptrace(PTRACE_SEIZE, child, 0, ptrace_options);\n+\tptrace(ptrace_restart, child, 0, SIGCONT);\n \n \tuloop_init();\n \ttracer.proc.pid = child;\n@@ -285,11 +370,19 @@ int main(int argc, char **argv, char **envp)\n \tuloop_run();\n \tuloop_done();\n \n-\tif (!json)\n-\t\tif (asprintf(&json, \"/tmp/%s.%u.json\", basename(*argv), child) < 0)\n-\t\t\tERROR(\"failed to allocate output path: %s\\n\", strerror(errno));\n \n+\tswitch (mode) {\n+\tcase UTRACE:\n+\t\tif (!json)\n+\t\t\tif (asprintf(&json, \"/tmp/%s.%u.json\", basename(*argv), child) < 0)\n+\t\t\t\tERROR(\"failed to allocate output path: %s\\n\", strerror(errno));\n+\t\tbreak;\n+\tcase SECCOMP_TRACE:\n+\t\tif (!violation_count)\n+\t\t\treturn 0;\n+\t\tasprintf(&json, \"/tmp/%s.%u.violations.json\", basename(*argv), child);\n+\t\tbreak;\n+\t}\n \tprint_syscalls(policy, json);\n-\n \treturn 0;\n }\n", "prefixes": [ "LEDE-DEV", "procd", "v2", "10/17" ] }