Bundle libseccomp 2.3.1
[linux-seccomp.git] / libseccomp / src / arch.c
CommitLineData
8befd5cc
MG
1/**
2 * Enhanced Seccomp Architecture/Machine Specific Code
3 *
4 * Copyright (c) 2012 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 <elf.h>
23#include <errno.h>
24#include <stdlib.h>
25#include <string.h>
26#include <asm/bitsperlong.h>
27#include <linux/audit.h>
28#include <stdbool.h>
29
30#include <seccomp.h>
31
32#include "arch.h"
33#include "arch-x86.h"
34#include "arch-x86_64.h"
35#include "arch-x32.h"
36#include "arch-arm.h"
37#include "arch-aarch64.h"
38#include "arch-mips.h"
39#include "arch-mips64.h"
40#include "arch-mips64n32.h"
41#include "arch-ppc.h"
42#include "arch-ppc64.h"
43#include "arch-s390.h"
44#include "arch-s390x.h"
45#include "db.h"
46#include "system.h"
47
48#define default_arg_count_max 6
49
50#define default_arg_offset(x) (offsetof(struct seccomp_data, args[x]))
51
52#if __i386__
53const struct arch_def *arch_def_native = &arch_def_x86;
54#elif __x86_64__
55#ifdef __ILP32__
56const struct arch_def *arch_def_native = &arch_def_x32;
57#else
58const struct arch_def *arch_def_native = &arch_def_x86_64;
59#endif /* __ILP32__ */
60#elif __arm__
61const struct arch_def *arch_def_native = &arch_def_arm;
62#elif __aarch64__
63const struct arch_def *arch_def_native = &arch_def_aarch64;
64#elif __mips__ && _MIPS_SIM == _MIPS_SIM_ABI32
65#if __MIPSEB__
66const struct arch_def *arch_def_native = &arch_def_mips;
67#elif __MIPSEL__
68const struct arch_def *arch_def_native = &arch_def_mipsel;
69#endif /* _MIPS_SIM_ABI32 */
70#elif __mips__ && _MIPS_SIM == _MIPS_SIM_ABI64
71#if __MIPSEB__
72const struct arch_def *arch_def_native = &arch_def_mips64;
73#elif __MIPSEL__
74const struct arch_def *arch_def_native = &arch_def_mipsel64;
75#endif /* _MIPS_SIM_ABI64 */
76#elif __mips__ && _MIPS_SIM == _MIPS_SIM_NABI32
77#if __MIPSEB__
78const struct arch_def *arch_def_native = &arch_def_mips64n32;
79#elif __MIPSEL__
80const struct arch_def *arch_def_native = &arch_def_mipsel64n32;
81#endif /* _MIPS_SIM_NABI32 */
82#elif __PPC64__
83#ifdef __BIG_ENDIAN__
84const struct arch_def *arch_def_native = &arch_def_ppc64;
85#else
86const struct arch_def *arch_def_native = &arch_def_ppc64le;
87#endif
88#elif __PPC__
89const struct arch_def *arch_def_native = &arch_def_ppc;
90#elif __s390x__ /* s390x must be checked before s390 */
91const struct arch_def *arch_def_native = &arch_def_s390x;
92#elif __s390__
93const struct arch_def *arch_def_native = &arch_def_s390;
94#else
95#error the arch code needs to know about your machine type
96#endif /* machine type guess */
97
98/**
99 * Validate the architecture token
100 * @param arch the architecture token
101 *
102 * Verify the given architecture token; return zero if valid, -EINVAL if not.
103 *
104 */
105int arch_valid(uint32_t arch)
106{
107 return (arch_def_lookup(arch) ? 0 : -EINVAL);
108}
109
110/**
111 * Lookup the architecture definition
112 * @param token the architecure token
113 *
114 * Return the matching architecture definition, returns NULL on failure.
115 *
116 */
117const struct arch_def *arch_def_lookup(uint32_t token)
118{
119 switch (token) {
120 case SCMP_ARCH_X86:
121 return &arch_def_x86;
122 case SCMP_ARCH_X86_64:
123 return &arch_def_x86_64;
124 case SCMP_ARCH_X32:
125 return &arch_def_x32;
126 case SCMP_ARCH_ARM:
127 return &arch_def_arm;
128 case SCMP_ARCH_AARCH64:
129 return &arch_def_aarch64;
130 case SCMP_ARCH_MIPS:
131 return &arch_def_mips;
132 case SCMP_ARCH_MIPSEL:
133 return &arch_def_mipsel;
134 case SCMP_ARCH_MIPS64:
135 return &arch_def_mips64;
136 case SCMP_ARCH_MIPSEL64:
137 return &arch_def_mipsel64;
138 case SCMP_ARCH_MIPS64N32:
139 return &arch_def_mips64n32;
140 case SCMP_ARCH_MIPSEL64N32:
141 return &arch_def_mipsel64n32;
142 case SCMP_ARCH_PPC:
143 return &arch_def_ppc;
144 case SCMP_ARCH_PPC64:
145 return &arch_def_ppc64;
146 case SCMP_ARCH_PPC64LE:
147 return &arch_def_ppc64le;
148 case SCMP_ARCH_S390:
149 return &arch_def_s390;
150 case SCMP_ARCH_S390X:
151 return &arch_def_s390x;
152 }
153
154 return NULL;
155}
156
157/**
158 * Lookup the architecture definition by name
159 * @param arch_name the architecure name
160 *
161 * Return the matching architecture definition, returns NULL on failure.
162 *
163 */
164const struct arch_def *arch_def_lookup_name(const char *arch_name)
165{
166 if (strcmp(arch_name, "x86") == 0)
167 return &arch_def_x86;
168 else if (strcmp(arch_name, "x86_64") == 0)
169 return &arch_def_x86_64;
170 else if (strcmp(arch_name, "x32") == 0)
171 return &arch_def_x32;
172 else if (strcmp(arch_name, "arm") == 0)
173 return &arch_def_arm;
174 else if (strcmp(arch_name, "aarch64") == 0)
175 return &arch_def_aarch64;
176 else if (strcmp(arch_name, "mips") == 0)
177 return &arch_def_mips;
178 else if (strcmp(arch_name, "mipsel") == 0)
179 return &arch_def_mipsel;
180 else if (strcmp(arch_name, "mips64") == 0)
181 return &arch_def_mips64;
182 else if (strcmp(arch_name, "mipsel64") == 0)
183 return &arch_def_mipsel64;
184 else if (strcmp(arch_name, "mips64n32") == 0)
185 return &arch_def_mips64n32;
186 else if (strcmp(arch_name, "mipsel64n32") == 0)
187 return &arch_def_mipsel64n32;
188 else if (strcmp(arch_name, "ppc") == 0)
189 return &arch_def_ppc;
190 else if (strcmp(arch_name, "ppc64") == 0)
191 return &arch_def_ppc64;
192 else if (strcmp(arch_name, "ppc64le") == 0)
193 return &arch_def_ppc64le;
194 else if (strcmp(arch_name, "s390") == 0)
195 return &arch_def_s390;
196 else if (strcmp(arch_name, "s390x") == 0)
197 return &arch_def_s390x;
198
199 return NULL;
200}
201
202/**
203 * Determine the maximum number of syscall arguments
204 * @param arch the architecture definition
205 *
206 * Determine the maximum number of syscall arguments for the given architecture.
207 * Returns the number of arguments on success, negative values on failure.
208 *
209 */
210int arch_arg_count_max(const struct arch_def *arch)
211{
212 return (arch_valid(arch->token) == 0 ? default_arg_count_max : -EDOM);
213}
214
215/**
216 * Determine the argument offset for the lower 32 bits
217 * @param arch the architecture definition
218 * @param arg the argument number
219 *
220 * Determine the correct offset for the low 32 bits of the given argument based
221 * on the architecture definition. Returns the offset on success, negative
222 * values on failure.
223 *
224 */
225int arch_arg_offset_lo(const struct arch_def *arch, unsigned int arg)
226{
227 if (arch_valid(arch->token) < 0)
228 return -EDOM;
229
230 switch (arch->endian) {
231 case ARCH_ENDIAN_LITTLE:
232 return default_arg_offset(arg);
233 break;
234 case ARCH_ENDIAN_BIG:
235 return default_arg_offset(arg) + 4;
236 break;
237 default:
238 return -EDOM;
239 }
240}
241
242/**
243 * Determine the argument offset for the high 32 bits
244 * @param arch the architecture definition
245 * @param arg the argument number
246 *
247 * Determine the correct offset for the high 32 bits of the given argument
248 * based on the architecture definition. Returns the offset on success,
249 * negative values on failure.
250 *
251 */
252int arch_arg_offset_hi(const struct arch_def *arch, unsigned int arg)
253{
254 if (arch_valid(arch->token) < 0 || arch->size != ARCH_SIZE_64)
255 return -EDOM;
256
257 switch (arch->endian) {
258 case ARCH_ENDIAN_LITTLE:
259 return default_arg_offset(arg) + 4;
260 break;
261 case ARCH_ENDIAN_BIG:
262 return default_arg_offset(arg);
263 break;
264 default:
265 return -EDOM;
266 }
267}
268
269/**
270 * Determine the argument offset
271 * @param arch the architecture definition
272 * @param arg the argument number
273 *
274 * Determine the correct offset for the given argument based on the
275 * architecture definition. Returns the offset on success, negative values on
276 * failure.
277 *
278 */
279int arch_arg_offset(const struct arch_def *arch, unsigned int arg)
280{
281 return arch_arg_offset_lo(arch, arg);
282}
283
284/**
285 * Resolve a syscall name to a number
286 * @param arch the architecture definition
287 * @param name the syscall name
288 *
289 * Resolve the given syscall name to the syscall number based on the given
290 * architecture. Returns the syscall number on success, including negative
291 * pseudo syscall numbers; returns __NR_SCMP_ERROR on failure.
292 *
293 */
294int arch_syscall_resolve_name(const struct arch_def *arch, const char *name)
295{
296 if (arch->syscall_resolve_name)
297 return (*arch->syscall_resolve_name)(name);
298
299 return __NR_SCMP_ERROR;
300}
301
302/**
303 * Resolve a syscall number to a name
304 * @param arch the architecture definition
305 * @param num the syscall number
306 *
307 * Resolve the given syscall number to the syscall name based on the given
308 * architecture. Returns a pointer to the syscall name string on success,
309 * including pseudo syscall names; returns NULL on failure.
310 *
311 */
312const char *arch_syscall_resolve_num(const struct arch_def *arch, int num)
313{
314 if (arch->syscall_resolve_num)
315 return (*arch->syscall_resolve_num)(num);
316
317 return NULL;
318}
319
320/**
321 * Translate the syscall number
322 * @param arch the architecture definition
323 * @param syscall the syscall number
324 *
325 * Translate the syscall number, in the context of the native architecure, to
326 * the provided architecure. Returns zero on success, negative values on
327 * failure.
328 *
329 */
330int arch_syscall_translate(const struct arch_def *arch, int *syscall)
331{
332 int sc_num;
333 const char *sc_name;
334
335 if (arch->token != arch_def_native->token) {
336 sc_name = arch_syscall_resolve_num(arch_def_native, *syscall);
337 if (sc_name == NULL)
338 return -EFAULT;
339
340 sc_num = arch_syscall_resolve_name(arch, sc_name);
341 if (sc_num == __NR_SCMP_ERROR)
342 return -EFAULT;
343
344 *syscall = sc_num;
345 }
346
347 return 0;
348}
349
350/**
351 * Rewrite a syscall value to match the architecture
352 * @param arch the architecture definition
353 * @param syscall the syscall number
354 *
355 * Syscalls can vary across different architectures so this function rewrites
356 * the syscall into the correct value for the specified architecture. Returns
357 * zero on success, -EDOM if the syscall is not defined for @arch, and negative
358 * values on failure.
359 *
360 */
361int arch_syscall_rewrite(const struct arch_def *arch, int *syscall)
362{
363 int sys = *syscall;
364
365 if (sys >= 0) {
366 /* we shouldn't be here - no rewrite needed */
367 return 0;
368 } else if (sys < 0 && sys > -100) {
369 /* reserved values */
370 return -EINVAL;
371 } else if (sys <= -100 && sys > -10000) {
372 /* rewritable syscalls */
373 if (arch->syscall_rewrite)
374 (*arch->syscall_rewrite)(syscall);
375 }
376
377 /* syscalls not defined on this architecture */
378 if ((*syscall) < 0)
379 return -EDOM;
380 return 0;
381}
382
383/**
384 * Add a new rule to the specified filter
385 * @param col the filter collection
386 * @param db the seccomp filter db
387 * @param strict the strict flag
388 * @param action the filter action
389 * @param syscall the syscall number
390 * @param chain_len the number of argument filters in the argument filter chain
391 * @param chain the argument filter chain
392 *
393 * This function adds a new argument/comparison/value to the seccomp filter for
394 * a syscall; multiple arguments can be specified and they will be chained
395 * together (essentially AND'd together) in the filter. When the strict flag
396 * is true the function will fail if the exact rule can not be added to the
397 * filter, if the strict flag is false the function will not fail if the
398 * function needs to adjust the rule due to architecture specifics. Returns
399 * zero on success, negative values on failure.
400 *
401 */
402int arch_filter_rule_add(struct db_filter_col *col, struct db_filter *db,
403 bool strict, uint32_t action, int syscall,
404 unsigned int chain_len, struct db_api_arg *chain)
405{
406 int rc;
407 size_t chain_size = sizeof(*chain) * chain_len;
408 struct db_api_rule_list *rule, *rule_tail;
409
410 /* ensure we aren't using any reserved syscall values */
411 if (syscall < 0 && syscall > -100)
412 return -EINVAL;
413
414 /* translate the syscall */
415 rc = arch_syscall_translate(db->arch, &syscall);
416 if (rc < 0)
417 return rc;
418
419 /* copy of the chain for each filter in the collection */
420 rule = malloc(sizeof(*rule));
421 if (rule == NULL)
422 return -ENOMEM;
423 rule->args = malloc(chain_size);
424 if (rule->args == NULL) {
425 free(rule);
426 return -ENOMEM;
427 }
428 rule->action = action;
429 rule->syscall = syscall;
430 rule->args_cnt = chain_len;
431 memcpy(rule->args, chain, chain_size);
432 rule->prev = NULL;
433 rule->next = NULL;
434
435 /* add the new rule to the existing filter */
436 if (db->arch->rule_add == NULL) {
437 /* negative syscalls require a db->arch->rule_add() function */
438 if (syscall < 0 && strict) {
439 rc = -EDOM;
440 goto rule_add_failure;
441 }
442 rc = db_rule_add(db, rule);
443 } else
444 rc = (db->arch->rule_add)(col, db, strict, rule);
445 if (rc == 0) {
446 /* insert the chain to the end of the filter's rule list */
447 rule_tail = rule;
448 while (rule_tail->next)
449 rule_tail = rule_tail->next;
450 if (db->rules != NULL) {
451 rule->prev = db->rules->prev;
452 rule_tail->next = db->rules;
453 db->rules->prev->next = rule;
454 db->rules->prev = rule_tail;
455 } else {
456 rule->prev = rule_tail;
457 rule_tail->next = rule;
458 db->rules = rule;
459 }
460 } else
461 goto rule_add_failure;
462
463 return 0;
464
465rule_add_failure:
466 do {
467 rule_tail = rule;
468 rule = rule->next;
469 free(rule_tail->args);
470 free(rule_tail);
471 } while (rule);
472 return rc;
473}
This page took 0.033023 seconds and 4 git commands to generate.