Bundle libseccomp 2.3.1
[linux-seccomp.git] / libseccomp / src / api.c
1 /**
2 * Seccomp Library API
3 *
4 * Copyright (c) 2012,2013 Red Hat <pmoore@redhat.com>
5 * Author: Paul Moore <paul@paul-moore.com>
6 */
7
8 /*
9 * This library is free software; you can redistribute it and/or modify it
10 * under the terms of version 2.1 of the GNU Lesser General Public License as
11 * published by the Free Software Foundation.
12 *
13 * This library is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, see <http://www.gnu.org/licenses>.
20 */
21
22 #include <endian.h>
23 #include <errno.h>
24 #include <inttypes.h>
25 #include <unistd.h>
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdbool.h>
30
31 #include <seccomp.h>
32
33 #include "arch.h"
34 #include "db.h"
35 #include "gen_pfc.h"
36 #include "gen_bpf.h"
37 #include "system.h"
38
39 #define API __attribute__((visibility("default")))
40
41 const struct scmp_version library_version = {
42 .major = SCMP_VER_MAJOR,
43 .minor = SCMP_VER_MINOR,
44 .micro = SCMP_VER_MICRO,
45 };
46
47 /**
48 * Validate a filter context
49 * @param ctx the filter context
50 *
51 * Attempt to validate the provided filter context. Returns zero if the
52 * context is valid, negative values on failure.
53 *
54 */
55 static int _ctx_valid(const scmp_filter_ctx *ctx)
56 {
57 return db_col_valid((struct db_filter_col *)ctx);
58 }
59
60 /**
61 * Validate a syscall number
62 * @param syscall the syscall number
63 *
64 * Attempt to perform basic syscall number validation. Returns zero of the
65 * syscall appears valid, negative values on failure.
66 *
67 */
68 static int _syscall_valid(int syscall)
69 {
70 if (syscall <= -1 && syscall >= -99)
71 return -EINVAL;
72 return 0;
73 }
74
75 /* NOTE - function header comment in include/seccomp.h */
76 API const struct scmp_version *seccomp_version(void)
77 {
78 return &library_version;
79 }
80
81 /* NOTE - function header comment in include/seccomp.h */
82 API scmp_filter_ctx seccomp_init(uint32_t def_action)
83 {
84 if (db_action_valid(def_action) < 0)
85 return NULL;
86
87 return db_col_init(def_action);
88 }
89
90 /* NOTE - function header comment in include/seccomp.h */
91 API int seccomp_reset(scmp_filter_ctx ctx, uint32_t def_action)
92 {
93 struct db_filter_col *col = (struct db_filter_col *)ctx;
94
95 if (ctx == NULL || db_action_valid(def_action) < 0)
96 return -EINVAL;
97
98 return db_col_reset(col, def_action);
99 }
100
101 /* NOTE - function header comment in include/seccomp.h */
102 API void seccomp_release(scmp_filter_ctx ctx)
103 {
104 db_col_release((struct db_filter_col *)ctx);
105 }
106
107 /* NOTE - function header comment in include/seccomp.h */
108 API int seccomp_merge(scmp_filter_ctx ctx_dst,
109 scmp_filter_ctx ctx_src)
110 {
111 struct db_filter_col *col_dst = (struct db_filter_col *)ctx_dst;
112 struct db_filter_col *col_src = (struct db_filter_col *)ctx_src;
113
114 if (db_col_valid(col_dst) || db_col_valid(col_src))
115 return -EINVAL;
116
117 /* NOTE: only the default action, NNP, and TSYNC settings must match */
118 if ((col_dst->attr.act_default != col_src->attr.act_default) ||
119 (col_dst->attr.nnp_enable != col_src->attr.nnp_enable) ||
120 (col_dst->attr.tsync_enable != col_src->attr.tsync_enable))
121 return -EINVAL;
122
123 return db_col_merge(col_dst, col_src);
124 }
125
126 /* NOTE - function header comment in include/seccomp.h */
127 API uint32_t seccomp_arch_resolve_name(const char *arch_name)
128 {
129 const struct arch_def *arch;
130
131 if (arch_name == NULL)
132 return 0;
133
134 arch = arch_def_lookup_name(arch_name);
135 if (arch == NULL)
136 return 0;
137
138 return arch->token;
139 }
140
141 /* NOTE - function header comment in include/seccomp.h */
142 API uint32_t seccomp_arch_native(void)
143 {
144 return arch_def_native->token;
145 }
146
147 /* NOTE - function header comment in include/seccomp.h */
148 API int seccomp_arch_exist(const scmp_filter_ctx ctx,
149 uint32_t arch_token)
150 {
151 struct db_filter_col *col = (struct db_filter_col *)ctx;
152
153 if (arch_token == 0)
154 arch_token = arch_def_native->token;
155
156 if (arch_valid(arch_token))
157 return -EINVAL;
158
159 return (db_col_arch_exist(col, arch_token) ? 0 : -EEXIST);
160 }
161
162 /* NOTE - function header comment in include/seccomp.h */
163 API int seccomp_arch_add(scmp_filter_ctx ctx, uint32_t arch_token)
164 {
165 const struct arch_def *arch;
166 struct db_filter_col *col = (struct db_filter_col *)ctx;
167
168 if (arch_token == 0)
169 arch_token = arch_def_native->token;
170
171 if (arch_valid(arch_token))
172 return -EINVAL;
173 if (db_col_arch_exist(col, arch_token))
174 return -EEXIST;
175
176 arch = arch_def_lookup(arch_token);
177 if (arch == NULL)
178 return -EFAULT;
179 return db_col_db_new(col, arch);
180 }
181
182 /* NOTE - function header comment in include/seccomp.h */
183 API int seccomp_arch_remove(scmp_filter_ctx ctx, uint32_t arch_token)
184 {
185 struct db_filter_col *col = (struct db_filter_col *)ctx;
186
187 if (arch_token == 0)
188 arch_token = arch_def_native->token;
189
190 if (arch_valid(arch_token))
191 return -EINVAL;
192 if (db_col_arch_exist(col, arch_token) != -EEXIST)
193 return -EEXIST;
194
195 return db_col_db_remove(col, arch_token);
196 }
197
198 /* NOTE - function header comment in include/seccomp.h */
199 API int seccomp_load(const scmp_filter_ctx ctx)
200 {
201 struct db_filter_col *col;
202
203 if (_ctx_valid(ctx))
204 return -EINVAL;
205 col = (struct db_filter_col *)ctx;
206
207 return sys_filter_load(col);
208 }
209
210 /* NOTE - function header comment in include/seccomp.h */
211 API int seccomp_attr_get(const scmp_filter_ctx ctx,
212 enum scmp_filter_attr attr, uint32_t *value)
213 {
214 if (_ctx_valid(ctx))
215 return -EINVAL;
216
217 return db_col_attr_get((const struct db_filter_col *)ctx, attr, value);
218 }
219
220 /* NOTE - function header comment in include/seccomp.h */
221 API int seccomp_attr_set(scmp_filter_ctx ctx,
222 enum scmp_filter_attr attr, uint32_t value)
223 {
224 if (_ctx_valid(ctx))
225 return -EINVAL;
226
227 return db_col_attr_set((struct db_filter_col *)ctx, attr, value);
228 }
229
230 /* NOTE - function header comment in include/seccomp.h */
231 API char *seccomp_syscall_resolve_num_arch(uint32_t arch_token, int num)
232 {
233 const struct arch_def *arch;
234 const char *name;
235
236 if (arch_token == 0)
237 arch_token = arch_def_native->token;
238 if (arch_valid(arch_token))
239 return NULL;
240 arch = arch_def_lookup(arch_token);
241 if (arch == NULL)
242 return NULL;
243
244 name = arch_syscall_resolve_num(arch, num);
245 if (name == NULL)
246 return NULL;
247
248 return strdup(name);
249 }
250
251 /* NOTE - function header comment in include/seccomp.h */
252 API int seccomp_syscall_resolve_name_arch(uint32_t arch_token, const char *name)
253 {
254 const struct arch_def *arch;
255
256 if (name == NULL)
257 return __NR_SCMP_ERROR;
258
259 if (arch_token == 0)
260 arch_token = arch_def_native->token;
261 if (arch_valid(arch_token))
262 return __NR_SCMP_ERROR;
263 arch = arch_def_lookup(arch_token);
264 if (arch == NULL)
265 return __NR_SCMP_ERROR;
266
267 return arch_syscall_resolve_name(arch, name);
268 }
269
270 /* NOTE - function header comment in include/seccomp.h */
271 API int seccomp_syscall_resolve_name_rewrite(uint32_t arch_token,
272 const char *name)
273 {
274 int rc;
275 int syscall;
276 const struct arch_def *arch;
277
278 if (name == NULL)
279 return __NR_SCMP_ERROR;
280
281 if (arch_token == 0)
282 arch_token = arch_def_native->token;
283 if (arch_valid(arch_token))
284 return __NR_SCMP_ERROR;
285 arch = arch_def_lookup(arch_token);
286 if (arch == NULL)
287 return __NR_SCMP_ERROR;
288
289 syscall = arch_syscall_resolve_name(arch, name);
290 if (syscall == __NR_SCMP_ERROR)
291 return __NR_SCMP_ERROR;
292 rc = arch_syscall_rewrite(arch, &syscall);
293 if (rc == -EDOM)
294 /* if we can't rewrite the syscall, just pass it through */
295 return syscall;
296 else if (rc < 0)
297 return __NR_SCMP_ERROR;
298
299 return syscall;
300 }
301
302 /* NOTE - function header comment in include/seccomp.h */
303 API int seccomp_syscall_resolve_name(const char *name)
304 {
305 return seccomp_syscall_resolve_name_arch(SCMP_ARCH_NATIVE, name);
306 }
307
308 /* NOTE - function header comment in include/seccomp.h */
309 API int seccomp_syscall_priority(scmp_filter_ctx ctx,
310 int syscall, uint8_t priority)
311 {
312 struct db_filter_col *col = (struct db_filter_col *)ctx;
313
314 if (db_col_valid(col) || _syscall_valid(syscall))
315 return -EINVAL;
316
317 return db_col_syscall_priority(col, syscall, priority);
318 }
319
320 /* NOTE - function header comment in include/seccomp.h */
321 API int seccomp_rule_add_array(scmp_filter_ctx ctx,
322 uint32_t action, int syscall,
323 unsigned int arg_cnt,
324 const struct scmp_arg_cmp *arg_array)
325 {
326 int rc;
327 struct db_filter_col *col = (struct db_filter_col *)ctx;
328
329 if (arg_cnt > ARG_COUNT_MAX)
330 return -EINVAL;
331 if (arg_cnt > 0 && arg_array == NULL)
332 return -EINVAL;
333
334 if (db_col_valid(col) || _syscall_valid(syscall))
335 return -EINVAL;
336
337 rc = db_action_valid(action);
338 if (rc < 0)
339 return rc;
340 if (action == col->attr.act_default)
341 return -EPERM;
342
343 return db_col_rule_add(col, 0, action, syscall, arg_cnt, arg_array);
344 }
345
346 /* NOTE - function header comment in include/seccomp.h */
347 API int seccomp_rule_add(scmp_filter_ctx ctx,
348 uint32_t action, int syscall,
349 unsigned int arg_cnt, ...)
350 {
351 int rc;
352 int iter;
353 struct scmp_arg_cmp arg_array[ARG_COUNT_MAX];
354 va_list arg_list;
355
356 /* arg_cnt is unsigned, so no need to check the lower bound */
357 if (arg_cnt > ARG_COUNT_MAX)
358 return -EINVAL;
359
360 va_start(arg_list, arg_cnt);
361 for (iter = 0; iter < arg_cnt; ++iter)
362 arg_array[iter] = va_arg(arg_list, struct scmp_arg_cmp);
363 rc = seccomp_rule_add_array(ctx, action, syscall, arg_cnt, arg_array);
364 va_end(arg_list);
365
366 return rc;
367 }
368
369 /* NOTE - function header comment in include/seccomp.h */
370 API int seccomp_rule_add_exact_array(scmp_filter_ctx ctx,
371 uint32_t action, int syscall,
372 unsigned int arg_cnt,
373 const struct scmp_arg_cmp *arg_array)
374 {
375 int rc;
376 struct db_filter_col *col = (struct db_filter_col *)ctx;
377
378 if (arg_cnt > ARG_COUNT_MAX)
379 return -EINVAL;
380 if (arg_cnt > 0 && arg_array == NULL)
381 return -EINVAL;
382
383 if (db_col_valid(col) || _syscall_valid(syscall))
384 return -EINVAL;
385
386 rc = db_action_valid(action);
387 if (rc < 0)
388 return rc;
389 if (action == col->attr.act_default)
390 return -EPERM;
391
392 if (col->filter_cnt > 1)
393 return -EOPNOTSUPP;
394
395 return db_col_rule_add(col, 1, action, syscall, arg_cnt, arg_array);
396 }
397
398 /* NOTE - function header comment in include/seccomp.h */
399 API int seccomp_rule_add_exact(scmp_filter_ctx ctx,
400 uint32_t action, int syscall,
401 unsigned int arg_cnt, ...)
402 {
403 int rc;
404 int iter;
405 struct scmp_arg_cmp arg_array[ARG_COUNT_MAX];
406 va_list arg_list;
407
408 /* arg_cnt is unsigned, so no need to check the lower bound */
409 if (arg_cnt > ARG_COUNT_MAX)
410 return -EINVAL;
411
412 va_start(arg_list, arg_cnt);
413 for (iter = 0; iter < arg_cnt; ++iter)
414 arg_array[iter] = va_arg(arg_list, struct scmp_arg_cmp);
415 rc = seccomp_rule_add_exact_array(ctx,
416 action, syscall, arg_cnt, arg_array);
417 va_end(arg_list);
418
419 return rc;
420 }
421
422 /* NOTE - function header comment in include/seccomp.h */
423 API int seccomp_export_pfc(const scmp_filter_ctx ctx, int fd)
424 {
425 if (_ctx_valid(ctx))
426 return -EINVAL;
427
428 return gen_pfc_generate((struct db_filter_col *)ctx, fd);
429 }
430
431 /* NOTE - function header comment in include/seccomp.h */
432 API int seccomp_export_bpf(const scmp_filter_ctx ctx, int fd)
433 {
434 int rc;
435 struct bpf_program *program;
436
437 if (_ctx_valid(ctx))
438 return -EINVAL;
439
440 program = gen_bpf_generate((struct db_filter_col *)ctx);
441 if (program == NULL)
442 return -ENOMEM;
443 rc = write(fd, program->blks, BPF_PGM_SIZE(program));
444 gen_bpf_release(program);
445 if (rc < 0)
446 return -errno;
447
448 return 0;
449 }
This page took 0.03485 seconds and 4 git commands to generate.