]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/seccomp.c
fix the expansion of libexecdir when not explicitly passed to configure
[mirror_lxc.git] / src / lxc / seccomp.c
1 /*
2 * lxc: linux Container library
3 *
4 * (C) Copyright Canonical, Inc. 2012
5 *
6 * Authors:
7 * Serge Hallyn <serge.hallyn@canonical.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #define _GNU_SOURCE
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <seccomp.h>
28 #include <errno.h>
29 #include <seccomp.h>
30
31 #include "config.h"
32 #include "lxcseccomp.h"
33 #include "log.h"
34
35 lxc_log_define(lxc_seccomp, lxc);
36
37 static int parse_config_v1(FILE *f, struct lxc_conf *conf)
38 {
39 char line[1024];
40 int ret;
41
42 while (fgets(line, 1024, f)) {
43 int nr;
44 ret = sscanf(line, "%d", &nr);
45 if (ret != 1)
46 return -1;
47 ret = seccomp_rule_add(
48 #if HAVE_SCMP_FILTER_CTX
49 conf->seccomp_ctx,
50 #endif
51 SCMP_ACT_ALLOW, nr, 0);
52 if (ret < 0) {
53 ERROR("failed loading allow rule for %d", nr);
54 return ret;
55 }
56 }
57 return 0;
58 }
59
60 #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
61 static void remove_trailing_newlines(char *l)
62 {
63 char *p = l;
64
65 while (*p)
66 p++;
67 while (--p >= l && *p == '\n')
68 *p = '\0';
69 }
70
71 static uint32_t get_v2_default_action(char *line)
72 {
73 uint32_t ret_action = -1;
74
75 while (*line == ' ') line++;
76 // after 'whitelist' or 'blacklist' comes default behavior
77 if (strncmp(line, "kill", 4) == 0)
78 ret_action = SCMP_ACT_KILL;
79 else if (strncmp(line, "errno", 5) == 0) {
80 int e;
81 if (sscanf(line+5, "%d", &e) != 1) {
82 ERROR("Bad errno value in %s", line);
83 return -2;
84 }
85 ret_action = SCMP_ACT_ERRNO(e);
86 } else if (strncmp(line, "allow", 5) == 0)
87 ret_action = SCMP_ACT_ALLOW;
88 else if (strncmp(line, "trap", 4) == 0)
89 ret_action = SCMP_ACT_TRAP;
90 return ret_action;
91 }
92
93 static uint32_t get_and_clear_v2_action(char *line, uint32_t def_action)
94 {
95 char *p = strchr(line, ' ');
96 uint32_t ret;
97
98 if (!p)
99 return def_action;
100 *p = '\0';
101 p++;
102 while (*p == ' ')
103 p++;
104 if (!*p || *p == '#')
105 return def_action;
106 ret = get_v2_default_action(p);
107 switch(ret) {
108 case -2: return -1;
109 case -1: return def_action;
110 default: return ret;
111 }
112 }
113 #endif
114
115 /*
116 * v2 consists of
117 * [x86]
118 * open
119 * read
120 * write
121 * close
122 * # a comment
123 * [x86_64]
124 * open
125 * read
126 * write
127 * close
128 */
129 static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
130 {
131 #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
132 char *p;
133 int ret;
134 scmp_filter_ctx *ctx = NULL;
135 bool blacklist = false;
136 uint32_t default_policy_action = -1, default_rule_action = -1, action;
137 uint32_t arch = SCMP_ARCH_NATIVE;
138
139 if (strncmp(line, "blacklist", 9) == 0)
140 blacklist = true;
141 else if (strncmp(line, "whitelist", 9) != 0) {
142 ERROR("Bad seccomp policy style: %s", line);
143 return -1;
144 }
145
146 if ((p = strchr(line, ' '))) {
147 default_policy_action = get_v2_default_action(p+1);
148 if (default_policy_action == -2)
149 return -1;
150 }
151
152 /* for blacklist, allow any syscall which has no rule */
153 if (blacklist) {
154 if (default_policy_action == -1)
155 default_policy_action = SCMP_ACT_ALLOW;
156 if (default_rule_action == -1)
157 default_rule_action = SCMP_ACT_KILL;
158 } else {
159 if (default_policy_action == -1)
160 default_policy_action = SCMP_ACT_KILL;
161 if (default_rule_action == -1)
162 default_rule_action = SCMP_ACT_ALLOW;
163 }
164
165 if (default_policy_action != SCMP_ACT_KILL) {
166 ret = seccomp_reset(conf->seccomp_ctx, default_policy_action);
167 if (ret != 0) {
168 ERROR("Error re-initializing seccomp");
169 return -1;
170 }
171 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0)) {
172 ERROR("failed to turn off n-new-privs");
173 return -1;
174 }
175 }
176
177 while (fgets(line, 1024, f)) {
178 int nr;
179
180 if (line[0] == '#')
181 continue;
182 if (strlen(line) == 0)
183 continue;
184 remove_trailing_newlines(line);
185 INFO("processing: .%s.", line);
186 if (line[0] == '[') {
187 // read the architecture for next set of rules
188 if (strcmp(line, "[x86]") == 0 ||
189 strcmp(line, "[X86]") == 0)
190 arch = SCMP_ARCH_X86;
191 else if (strcmp(line, "[X86_64]") == 0 ||
192 strcmp(line, "[x86_64]") == 0)
193 arch = SCMP_ARCH_X86_64;
194 #ifdef SCMP_ARCH_ARM
195 else if (strcmp(line, "[arm]") == 0 ||
196 strcmp(line, "[ARM]") == 0)
197 arch = SCMP_ARCH_ARM;
198 #endif
199 else
200 goto bad_arch;
201 if (ctx) {
202 ERROR("Only two arch sections per policy supported");
203 goto bad_arch;
204 }
205 if ((ctx = seccomp_init(default_policy_action)) == NULL) {
206 ERROR("Error initializing seccomp context");
207 return -1;
208 }
209 if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0)) {
210 ERROR("failed to turn off n-new-privs");
211 seccomp_release(ctx);
212 return -1;
213 }
214 ret = seccomp_arch_add(ctx, arch);
215 if (ret == -EEXIST) {
216 seccomp_release(ctx);
217 ctx = NULL;
218 continue;
219 }
220 if (ret != 0) {
221 ERROR("Error %d adding arch: %s", ret, line);
222 goto bad_arch;
223 }
224 if (seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE) != 0) {
225 ERROR("Error removing native arch from %s", line);
226 goto bad_arch;
227 }
228 continue;
229 }
230
231 action = get_and_clear_v2_action(line, default_rule_action);
232 if (action == -1) {
233 ERROR("Failed to interpret action");
234 goto bad_rule;
235 }
236 nr = seccomp_syscall_resolve_name_arch(arch, line);
237 if (nr < 0) {
238 WARN("Seccomp: failed to resolve syscall: %s (returned %d)",
239 line, nr);
240 WARN("This syscall will NOT be blacklisted");
241 continue;
242 }
243 ret = seccomp_rule_add(ctx ? ctx : conf->seccomp_ctx,
244 action, nr, 0);
245 if (ret < 0) {
246 ERROR("failed (%d) loading rule for %s", ret, line);
247 goto bad_rule;
248 }
249 }
250 if (ctx) {
251 if (seccomp_merge(conf->seccomp_ctx, ctx) != 0) {
252 seccomp_release(ctx);
253 ERROR("Error merging seccomp contexts");
254 return -1;
255 }
256 }
257 return 0;
258
259 bad_arch:
260 ERROR("Unsupported arch: %s", line);
261 bad_rule:
262 if (ctx)
263 seccomp_release(ctx);
264 return -1;
265 #else
266 return -1;
267 #endif
268 }
269
270 /*
271 * The first line of the config file has a policy language version
272 * the second line has some directives
273 * then comes policy subject to the directives
274 * right now version must be '1'
275 * the directives must include 'whitelist' (only type of policy currently
276 * supported) and can include 'debug' (though debug is not yet supported).
277 */
278 static int parse_config(FILE *f, struct lxc_conf *conf)
279 {
280 char line[1024];
281 int ret, version;
282
283 ret = fscanf(f, "%d\n", &version);
284 if (ret != 1 || (version != 1 && version != 2)) {
285 ERROR("invalid version");
286 return -1;
287 }
288 if (!fgets(line, 1024, f)) {
289 ERROR("invalid config file");
290 return -1;
291 }
292 if (version == 1 && !strstr(line, "whitelist")) {
293 ERROR("only whitelist policy is supported");
294 return -1;
295 }
296
297 if (strstr(line, "debug")) {
298 ERROR("debug not yet implemented");
299 return -1;
300 }
301
302 if (version == 1)
303 return parse_config_v1(f, conf);
304 return parse_config_v2(f, line, conf);
305 }
306
307 int lxc_read_seccomp_config(struct lxc_conf *conf)
308 {
309 FILE *f;
310 int ret;
311
312 if (!conf->seccomp)
313 return 0;
314
315 #if HAVE_SCMP_FILTER_CTX
316 /* XXX for debug, pass in SCMP_ACT_TRAP */
317 conf->seccomp_ctx = seccomp_init(SCMP_ACT_KILL);
318 ret = !conf->seccomp_ctx;
319 #else
320 ret = seccomp_init(SCMP_ACT_KILL) < 0;
321 #endif
322 if (ret) {
323 ERROR("failed initializing seccomp");
324 return -1;
325 }
326
327 /* turn of no-new-privs. We don't want it in lxc, and it breaks
328 * with apparmor */
329 if (seccomp_attr_set(
330 #if HAVE_SCMP_FILTER_CTX
331 conf->seccomp_ctx,
332 #endif
333 SCMP_FLTATR_CTL_NNP, 0)) {
334 ERROR("failed to turn off n-new-privs");
335 return -1;
336 }
337
338 f = fopen(conf->seccomp, "r");
339 if (!f) {
340 SYSERROR("failed to open seccomp policy file %s", conf->seccomp);
341 return -1;
342 }
343 ret = parse_config(f, conf);
344 fclose(f);
345 return ret;
346 }
347
348 int lxc_seccomp_load(struct lxc_conf *conf)
349 {
350 int ret;
351 if (!conf->seccomp)
352 return 0;
353 ret = seccomp_load(
354 #if HAVE_SCMP_FILTER_CTX
355 conf->seccomp_ctx
356 #endif
357 );
358 if (ret < 0) {
359 ERROR("Error loading the seccomp policy");
360 return -1;
361 }
362 return 0;
363 }
364
365 void lxc_seccomp_free(struct lxc_conf *conf) {
366 if (conf->seccomp) {
367 free(conf->seccomp);
368 conf->seccomp = NULL;
369 }
370 #if HAVE_SCMP_FILTER_CTX
371 if (conf->seccomp_ctx) {
372 seccomp_release(conf->seccomp_ctx);
373 conf->seccomp_ctx = NULL;
374 }
375 #endif
376 }