]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/seccomp.c
fix the expansion of libexecdir when not explicitly passed to configure
[mirror_lxc.git] / src / lxc / seccomp.c
CommitLineData
8f2c3a70
SH
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
250b1eec 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
8f2c3a70
SH
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>
f2363e38 30
769872f9 31#include "config.h"
8f2c3a70 32#include "lxcseccomp.h"
8f2c3a70
SH
33#include "log.h"
34
35lxc_log_define(lxc_seccomp, lxc);
36
50798138
SH
37static 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
2b0ae718 60#if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
50798138
SH
61static 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
71static 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
93static 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}
2b0ae718 113#endif
50798138
SH
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 */
129static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
130{
2b0ae718 131#if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
50798138
SH
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;
2b0ae718 194#ifdef SCMP_ARCH_ARM
50798138
SH
195 else if (strcmp(line, "[arm]") == 0 ||
196 strcmp(line, "[ARM]") == 0)
197 arch = SCMP_ARCH_ARM;
2b0ae718 198#endif
50798138
SH
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) {
52036991
SH
238 WARN("Seccomp: failed to resolve syscall: %s (returned %d)",
239 line, nr);
240 WARN("This syscall will NOT be blacklisted");
241 continue;
50798138
SH
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
259bad_arch:
260 ERROR("Unsupported arch: %s", line);
261bad_rule:
262 if (ctx)
263 seccomp_release(ctx);
264 return -1;
265#else
266 return -1;
267#endif
268}
269
8f2c3a70
SH
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 */
278static 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);
50798138 284 if (ret != 1 || (version != 1 && version != 2)) {
8f2c3a70
SH
285 ERROR("invalid version");
286 return -1;
287 }
288 if (!fgets(line, 1024, f)) {
289 ERROR("invalid config file");
290 return -1;
291 }
50798138 292 if (version == 1 && !strstr(line, "whitelist")) {
8f2c3a70
SH
293 ERROR("only whitelist policy is supported");
294 return -1;
295 }
50798138 296
8f2c3a70
SH
297 if (strstr(line, "debug")) {
298 ERROR("debug not yet implemented");
299 return -1;
300 }
50798138
SH
301
302 if (version == 1)
303 return parse_config_v1(f, conf);
304 return parse_config_v2(f, line, conf);
8f2c3a70
SH
305}
306
307int lxc_read_seccomp_config(struct lxc_conf *conf)
308{
309 FILE *f;
310 int ret;
311
769872f9
SH
312 if (!conf->seccomp)
313 return 0;
314
315#if HAVE_SCMP_FILTER_CTX
316 /* XXX for debug, pass in SCMP_ACT_TRAP */
50798138 317 conf->seccomp_ctx = seccomp_init(SCMP_ACT_KILL);
769872f9
SH
318 ret = !conf->seccomp_ctx;
319#else
50798138 320 ret = seccomp_init(SCMP_ACT_KILL) < 0;
769872f9
SH
321#endif
322 if (ret) {
8f2c3a70
SH
323 ERROR("failed initializing seccomp");
324 return -1;
325 }
8f2c3a70
SH
326
327 /* turn of no-new-privs. We don't want it in lxc, and it breaks
328 * with apparmor */
769872f9
SH
329 if (seccomp_attr_set(
330#if HAVE_SCMP_FILTER_CTX
331 conf->seccomp_ctx,
332#endif
333 SCMP_FLTATR_CTL_NNP, 0)) {
959aee9c 334 ERROR("failed to turn off n-new-privs");
8f2c3a70
SH
335 return -1;
336 }
337
338 f = fopen(conf->seccomp, "r");
339 if (!f) {
959aee9c 340 SYSERROR("failed to open seccomp policy file %s", conf->seccomp);
8f2c3a70
SH
341 return -1;
342 }
343 ret = parse_config(f, conf);
344 fclose(f);
345 return ret;
346}
347
348int lxc_seccomp_load(struct lxc_conf *conf)
349{
350 int ret;
351 if (!conf->seccomp)
352 return 0;
769872f9
SH
353 ret = seccomp_load(
354#if HAVE_SCMP_FILTER_CTX
355 conf->seccomp_ctx
356#endif
357 );
8f2c3a70
SH
358 if (ret < 0) {
359 ERROR("Error loading the seccomp policy");
360 return -1;
361 }
362 return 0;
363}
769872f9
SH
364
365void 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}