• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/procd/jail/seccomp-oci.c

  1 /*
  2  * parse and setup OCI seccomp filter
  3  * Copyright (c) 2020 Daniel Golle <daniel@makrotopia.org>
  4  * seccomp example with syscall reporting
  5  * Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org>
  6  * Authors:
  7  *  Kees Cook <keescook@chromium.org>
  8  *  Will Drewry <wad@chromium.org>
  9  *
 10  * Use of this source code is governed by a BSD-style license that can be
 11  * found in the LICENSE file.
 12  */
 13 #define _GNU_SOURCE 1
 14 #include <stddef.h>
 15 #include <stdlib.h>
 16 #include <unistd.h>
 17 
 18 #include <libubox/utils.h>
 19 #include <libubox/blobmsg.h>
 20 #include <libubox/blobmsg_json.h>
 21 
 22 #include "log.h"
 23 #include "seccomp-bpf.h"
 24 #include "seccomp-oci.h"
 25 #include "../syscall-names.h"
 26 #include "seccomp-syscalls-helpers.h"
 27 
 28 static uint32_t resolve_action(char *actname)
 29 {
 30         if (!strcmp(actname, "SCMP_ACT_KILL"))
 31                 return SECCOMP_RET_KILL;
 32         else if (!strcmp(actname, "SCMP_ACT_KILL_PROCESS"))
 33                 return SECCOMP_RET_KILLPROCESS;
 34         else if (!strcmp(actname, "SCMP_ACT_TRAP"))
 35                 return SECCOMP_RET_TRAP;
 36         else if (!strcmp(actname, "SCMP_ACT_ERRNO"))
 37                 return SECCOMP_RET_ERRNO;
 38         else if (!strcmp(actname, "SCMP_ACT_ERROR"))
 39                 return SECCOMP_RET_ERRNO;
 40         else if (!strcmp(actname, "SCMP_ACT_TRACE"))
 41                 return SECCOMP_RET_TRACE;
 42         else if (!strcmp(actname, "SCMP_ACT_ALLOW"))
 43                 return SECCOMP_RET_ALLOW;
 44         else if (!strcmp(actname, "SCMP_ACT_LOG"))
 45                 return SECCOMP_RET_LOGALLOW;
 46         else {
 47                 ERROR("unknown seccomp action %s\n", actname);
 48                 return SECCOMP_RET_KILL;
 49         }
 50 }
 51 
 52 static uint32_t resolve_architecture(char *archname)
 53 {
 54         if (!archname)
 55                 return 0;
 56 
 57         if (!strcmp(archname, "SCMP_ARCH_X86"))
 58                 return AUDIT_ARCH_I386;
 59         else if (!strcmp(archname, "SCMP_ARCH_X86_64"))
 60                 return AUDIT_ARCH_X86_64;
 61         else if (!strcmp(archname, "SCMP_ARCH_X32"))
 62                 /*
 63                  * return AUDIT_ARCH_X86_64;
 64                  * 32-bit userland on 64-bit kernel is not supported yet
 65                  */
 66                 return 0;
 67         else if (!strcmp(archname, "SCMP_ARCH_ARM"))
 68                 return AUDIT_ARCH_ARM;
 69         else if (!strcmp(archname, "SCMP_ARCH_AARCH64"))
 70                 return AUDIT_ARCH_AARCH64;
 71         else if (!strcmp(archname, "SCMP_ARCH_MIPS"))
 72                 return AUDIT_ARCH_MIPS;
 73         else if (!strcmp(archname, "SCMP_ARCH_MIPS64"))
 74                 return AUDIT_ARCH_MIPS64;
 75         else if (!strcmp(archname, "SCMP_ARCH_MIPS64N32"))
 76                 return AUDIT_ARCH_MIPS64N32;
 77         else if (!strcmp(archname, "SCMP_ARCH_MIPSEL"))
 78                 return AUDIT_ARCH_MIPSEL;
 79         else if (!strcmp(archname, "SCMP_ARCH_MIPSEL64"))
 80                 return AUDIT_ARCH_MIPSEL64;
 81         else if (!strcmp(archname, "SCMP_ARCH_MIPSEL64N32"))
 82                 return AUDIT_ARCH_MIPSEL64N32;
 83         else if (!strcmp(archname, "SCMP_ARCH_PPC"))
 84                 return AUDIT_ARCH_PPC;
 85         else if (!strcmp(archname, "SCMP_ARCH_PPC64"))
 86                 return AUDIT_ARCH_PPC64;
 87         else if (!strcmp(archname, "SCMP_ARCH_PPC64LE"))
 88                 return AUDIT_ARCH_PPC64LE;
 89         else if (!strcmp(archname, "SCMP_ARCH_S390"))
 90                 return AUDIT_ARCH_S390;
 91         else if (!strcmp(archname, "SCMP_ARCH_S390X"))
 92                 return AUDIT_ARCH_S390X;
 93         else if (!strcmp(archname, "SCMP_ARCH_PARISC"))
 94                 return AUDIT_ARCH_PARISC;
 95         else if (!strcmp(archname, "SCMP_ARCH_PARISC64"))
 96                 return AUDIT_ARCH_PARISC64;
 97         else {
 98                 ERROR("unknown seccomp architecture %s\n", archname);
 99                 return 0;
100         }
101 }
102 
103 enum {
104         OCI_LINUX_SECCOMP_DEFAULTACTION,
105         OCI_LINUX_SECCOMP_ARCHITECTURES,
106         OCI_LINUX_SECCOMP_FLAGS,
107         OCI_LINUX_SECCOMP_SYSCALLS,
108         __OCI_LINUX_SECCOMP_MAX,
109 };
110 
111 static const struct blobmsg_policy oci_linux_seccomp_policy[] = {
112         [OCI_LINUX_SECCOMP_DEFAULTACTION] = { "defaultAction", BLOBMSG_TYPE_STRING },
113         [OCI_LINUX_SECCOMP_ARCHITECTURES] = { "architectures", BLOBMSG_TYPE_ARRAY },
114         [OCI_LINUX_SECCOMP_FLAGS] = { "flags", BLOBMSG_TYPE_ARRAY },
115         [OCI_LINUX_SECCOMP_SYSCALLS] = { "syscalls", BLOBMSG_TYPE_ARRAY },
116 };
117 
118 enum {
119         OCI_LINUX_SECCOMP_SYSCALLS_NAMES,
120         OCI_LINUX_SECCOMP_SYSCALLS_ACTION,
121         OCI_LINUX_SECCOMP_SYSCALLS_ERRNORET,
122         OCI_LINUX_SECCOMP_SYSCALLS_ARGS,
123         __OCI_LINUX_SECCOMP_SYSCALLS_MAX
124 };
125 
126 static const struct blobmsg_policy oci_linux_seccomp_syscalls_policy[] = {
127         [OCI_LINUX_SECCOMP_SYSCALLS_NAMES] = { "names", BLOBMSG_TYPE_ARRAY },
128         [OCI_LINUX_SECCOMP_SYSCALLS_ERRNORET] = { "errnoRet", BLOBMSG_TYPE_INT32 },
129         [OCI_LINUX_SECCOMP_SYSCALLS_ARGS] = { "args", BLOBMSG_TYPE_ARRAY },
130         [OCI_LINUX_SECCOMP_SYSCALLS_ACTION] = { "action", BLOBMSG_TYPE_STRING },
131 };
132 
133 enum {
134         OCI_LINUX_SECCOMP_SYSCALLS_ARGS_INDEX,
135         OCI_LINUX_SECCOMP_SYSCALLS_ARGS_VALUE,
136         OCI_LINUX_SECCOMP_SYSCALLS_ARGS_VALUETWO,
137         OCI_LINUX_SECCOMP_SYSCALLS_ARGS_OP,
138         __OCI_LINUX_SECCOMP_SYSCALLS_ARGS_MAX
139 };
140 
141 static const struct blobmsg_policy oci_linux_seccomp_syscalls_args_policy[] = {
142         [OCI_LINUX_SECCOMP_SYSCALLS_ARGS_INDEX] = { "index", BLOBMSG_TYPE_INT32 },
143         [OCI_LINUX_SECCOMP_SYSCALLS_ARGS_VALUE] = { "value", BLOBMSG_TYPE_INT64 },
144         [OCI_LINUX_SECCOMP_SYSCALLS_ARGS_VALUETWO] = { "valueTwo", BLOBMSG_TYPE_INT64 },
145         [OCI_LINUX_SECCOMP_SYSCALLS_ARGS_OP] = { "op", BLOBMSG_TYPE_STRING },
146 };
147 
148 struct sock_fprog *parseOCIlinuxseccomp(struct blob_attr *msg)
149 {
150         struct blob_attr *tb[__OCI_LINUX_SECCOMP_MAX];
151         struct blob_attr *tbn[__OCI_LINUX_SECCOMP_SYSCALLS_MAX];
152         struct blob_attr *tba[__OCI_LINUX_SECCOMP_SYSCALLS_ARGS_MAX];
153         struct blob_attr *cur, *curn, *curarg;
154         int rem, remn, remargs, sc;
155         struct sock_filter *filter;
156         struct sock_fprog *prog;
157         int sz = 5, idx = 0;
158         uint32_t default_policy = 0;
159         uint32_t seccomp_arch;
160         bool arch_matched;
161 
162         blobmsg_parse(oci_linux_seccomp_policy, __OCI_LINUX_SECCOMP_MAX, tb, blobmsg_data(msg), blobmsg_len(msg));
163 
164         if (!tb[OCI_LINUX_SECCOMP_DEFAULTACTION]) {
165                 ERROR("seccomp: no default action set\n");
166                 return NULL;
167         }
168 
169         default_policy = resolve_action(blobmsg_get_string(tb[OCI_LINUX_SECCOMP_DEFAULTACTION]));
170 
171         /* verify architecture while ignoring the x86_64 anomaly for now */
172         if (tb[OCI_LINUX_SECCOMP_ARCHITECTURES]) {
173                 arch_matched = false;
174                 blobmsg_for_each_attr(cur, tb[OCI_LINUX_SECCOMP_ARCHITECTURES], rem) {
175                         seccomp_arch = resolve_architecture(blobmsg_get_string(cur));
176                         if (ARCH_NR == seccomp_arch) {
177                                 arch_matched = true;
178                                 break;
179                         }
180                 }
181                 if (!arch_matched) {
182                         ERROR("seccomp architecture doesn't match system\n");
183                         return NULL;
184                 }
185         }
186 
187         blobmsg_for_each_attr(cur, tb[OCI_LINUX_SECCOMP_SYSCALLS], rem) {
188                 blobmsg_parse(oci_linux_seccomp_syscalls_policy, __OCI_LINUX_SECCOMP_SYSCALLS_MAX, tbn, blobmsg_data(cur), blobmsg_len(cur));
189                 blobmsg_for_each_attr(curn, tbn[OCI_LINUX_SECCOMP_SYSCALLS_NAMES], remn)
190                         sz += 2;
191 
192                 if (tbn[OCI_LINUX_SECCOMP_SYSCALLS_ARGS])
193                         blobmsg_for_each_attr(curarg, tbn[OCI_LINUX_SECCOMP_SYSCALLS_ARGS], remargs)
194                                 sz++;
195         }
196 
197         prog = malloc(sizeof(struct sock_fprog));
198         if (!prog)
199                 return NULL;
200 
201         filter = calloc(sz, sizeof(struct sock_filter));
202         if (!filter) {
203                 ERROR("failed to allocate memory for seccomp filter\n");
204                 goto errout2;
205         }
206 
207         /* validate arch */
208         set_filter(&filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, arch_nr);
209         set_filter(&filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 1, 0, ARCH_NR);
210         set_filter(&filter[idx++], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_KILL);
211 
212         /* get syscall */
213         set_filter(&filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr);
214 
215         blobmsg_for_each_attr(cur, tb[OCI_LINUX_SECCOMP_SYSCALLS], rem) {
216                 uint32_t action;
217                 blobmsg_parse(oci_linux_seccomp_syscalls_policy, __OCI_LINUX_SECCOMP_SYSCALLS_MAX, tbn, blobmsg_data(cur), blobmsg_len(cur));
218                 action = resolve_action(blobmsg_get_string(tbn[OCI_LINUX_SECCOMP_SYSCALLS_ACTION]));
219                 if (tbn[OCI_LINUX_SECCOMP_SYSCALLS_ERRNORET]) {
220                         if (action != SECCOMP_RET_ERRNO)
221                                 goto errout1;
222 
223                         action = SECCOMP_RET_ERROR(blobmsg_get_u32(tbn[OCI_LINUX_SECCOMP_SYSCALLS_ERRNORET]));
224                 } else if (action == SECCOMP_RET_ERRNO)
225                         action = SECCOMP_RET_ERROR(EPERM);
226 
227                 blobmsg_for_each_attr(curn, tbn[OCI_LINUX_SECCOMP_SYSCALLS_NAMES], remn) {
228                         sc = find_syscall(blobmsg_get_string(curn));
229                         if (sc == -1) {
230                                 DEBUG("unknown syscall '%s'\n", blobmsg_get_string(curn));
231                                 /* TODO: support run.oci.seccomp_fail_unknown_syscall=1 annotation */
232                                 continue;
233                         }
234 
235                         /* add rule to filter */
236                         set_filter(&filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 1, sc);
237                         set_filter(&filter[idx++], BPF_RET + BPF_K, 0, 0, action);
238 
239                 }
240                 blobmsg_for_each_attr(curn, tbn[OCI_LINUX_SECCOMP_SYSCALLS_ARGS], remn) {
241                         blobmsg_parse(oci_linux_seccomp_syscalls_args_policy, __OCI_LINUX_SECCOMP_SYSCALLS_ARGS_MAX, tba, blobmsg_data(curn), blobmsg_len(curn));
242                         /* ToDo: process args */
243                 }
244         }
245 
246         set_filter(&filter[idx], BPF_RET + BPF_K, 0, 0, default_policy);
247 
248         prog->len = (unsigned short) idx + 1;
249         prog->filter = filter;
250 
251         return prog;
252 
253 errout1:
254         free(prog->filter);
255 errout2:
256         free(prog);
257         return NULL;
258 }
259 
260 
261 int applyOCIlinuxseccomp(struct sock_fprog *prog)
262 {
263         if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
264                 ERROR("prctl(PR_SET_NO_NEW_PRIVS) failed: %m\n");
265                 goto errout;
266         }
267 
268         if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, prog)) {
269                 ERROR("prctl(PR_SET_SECCOMP) failed: %m\n");
270                 goto errout;
271         }
272         free(prog);
273 
274         return 0;
275 
276 errout:
277         free(prog->filter);
278         free(prog);
279         return errno;
280 }
281 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt