Bundle libseccomp 2.3.1
[linux-seccomp.git] / libseccomp / src / arch.c
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__
53 const struct arch_def *arch_def_native = &arch_def_x86;
54 #elif __x86_64__
55 #ifdef __ILP32__
56 const struct arch_def *arch_def_native = &arch_def_x32;
57 #else
58 const struct arch_def *arch_def_native = &arch_def_x86_64;
59 #endif /* __ILP32__ */
60 #elif __arm__
61 const struct arch_def *arch_def_native = &arch_def_arm;
62 #elif __aarch64__
63 const struct arch_def *arch_def_native = &arch_def_aarch64;
64 #elif __mips__ && _MIPS_SIM == _MIPS_SIM_ABI32
65 #if __MIPSEB__
66 const struct arch_def *arch_def_native = &arch_def_mips;
67 #elif __MIPSEL__
68 const 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__
72 const struct arch_def *arch_def_native = &arch_def_mips64;
73 #elif __MIPSEL__
74 const 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__
78 const struct arch_def *arch_def_native = &arch_def_mips64n32;
79 #elif __MIPSEL__
80 const struct arch_def *arch_def_native = &arch_def_mipsel64n32;
81 #endif /* _MIPS_SIM_NABI32 */
82 #elif __PPC64__
83 #ifdef __BIG_ENDIAN__
84 const struct arch_def *arch_def_native = &arch_def_ppc64;
85 #else
86 const struct arch_def *arch_def_native = &arch_def_ppc64le;
87 #endif
88 #elif __PPC__
89 const struct arch_def *arch_def_native = &arch_def_ppc;
90 #elif __s390x__ /* s390x must be checked before s390 */
91 const struct arch_def *arch_def_native = &arch_def_s390x;
92 #elif __s390__
93 const 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 */
105 int 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 */
117 const 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 */
164 const 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 */
210 int 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 */
225 int 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 */
252 int 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 */
279 int 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 */
294 int 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 */
312 const 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 */
330 int 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 */
361 int 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 */
402 int 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
465 rule_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.032896 seconds and 4 git commands to generate.