• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

drakenclimber / libseccomp / 7064690886

01 Dec 2023 08:07PM UTC coverage: 89.523% (-0.5%) from 89.973%
7064690886

push

github

drakenclimber
Revert "tests: Fix wrong syscall-error in test 29"

Revert commit a707ec98cc2c ("tests: Fix wrong syscall-error in test
29").  The reverted commit properly set the syscall number to -10001 in
a call to seccomp_rule_add_exact(), but due to previously unknown
shortcomings in the test, this led to failures.  Revert to the previous
version of test 29.

Note that this reverted version of test 29 is not functioning as
originally designed, but it is largely benign and the functional test
will pass on all architectures.  (It's generating a BPF filter that will
allow all syscalls on x86.)

Fixes: a707ec98cc2c ("tests: Fix wrong syscall-error in test 29")
Signed-off-by: Tom Hromatka <tom.hromatka@oracle.com>

2572 of 2873 relevant lines covered (89.52%)

272267.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.27
/src/system.c
1
/**
2
 * Seccomp System Interfaces
3
 *
4
 * Copyright (c) 2014 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 <stdlib.h>
23
#include <errno.h>
24
#include <sys/prctl.h>
25

26
#define _GNU_SOURCE
27
#include <unistd.h>
28

29
#include "system.h"
30

31
#include <seccomp.h>
32

33
#include "arch.h"
34
#include "db.h"
35
#include "gen_bpf.h"
36
#include "helper.h"
37

38
/* NOTE: the seccomp syscall allowlist is currently disabled for testing
39
 *       purposes, but unless we can verify all of the supported ABIs before
40
 *       our next release we may have to enable the allowlist */
41
#define SYSCALL_ALLOWLIST_ENABLE        0
42

43
/* task global state */
44
struct task_state {
45
        /* seccomp(2) syscall */
46
        int nr_seccomp;
47

48
        /* userspace notification fd */
49
        int notify_fd;
50

51
        /* runtime support flags */
52
        int sup_syscall;
53
        int sup_flag_tsync;
54
        int sup_flag_log;
55
        int sup_action_log;
56
        int sup_kill_process;
57
        int sup_flag_spec_allow;
58
        int sup_flag_new_listener;
59
        int sup_user_notif;
60
        int sup_flag_tsync_esrch;
61
};
62
static struct task_state state = {
63
        .nr_seccomp = -1,
64

65
        .notify_fd = -1,
66

67
        .sup_syscall = -1,
68
        .sup_flag_tsync = -1,
69
        .sup_flag_log = -1,
70
        .sup_action_log = -1,
71
        .sup_kill_process = -1,
72
        .sup_flag_spec_allow = -1,
73
        .sup_flag_new_listener = -1,
74
        .sup_user_notif = -1,
75
        .sup_flag_tsync_esrch = -1,
76
};
77

78
/**
79
 * Reset the task state
80
 *
81
 * This function fully resets the library's global "system task state".
82
 *
83
 */
84
void sys_reset_state(void)
1✔
85
{
86
        state.nr_seccomp = -1;
1✔
87

88
        if (state.notify_fd > 0)
1✔
89
                close(state.notify_fd);
×
90
        state.notify_fd = -1;
1✔
91

92
        state.sup_syscall = -1;
1✔
93
        state.sup_flag_tsync = -1;
1✔
94
        state.sup_flag_log = -1;
1✔
95
        state.sup_action_log = -1;
1✔
96
        state.sup_kill_process = -1;
1✔
97
        state.sup_flag_spec_allow = -1;
1✔
98
        state.sup_flag_new_listener = -1;
1✔
99
        state.sup_user_notif = -1;
1✔
100
        state.sup_flag_tsync_esrch = -1;
1✔
101
}
1✔
102

103
/**
104
 * Check to see if the seccomp() syscall is supported
105
 *
106
 * This function attempts to see if the system supports the seccomp() syscall.
107
 * Unfortunately, there are a few reasons why this check may fail, including
108
 * a previously loaded seccomp filter, so it is hard to say for certain.
109
 * Return one if the syscall is supported, zero otherwise.
110
 *
111
 */
112
int sys_chk_seccomp_syscall(void)
61,670✔
113
{
114
        int rc;
61,670✔
115
        int nr_seccomp;
61,670✔
116

117
        /* NOTE: it is reasonably safe to assume that we should be able to call
118
         *       seccomp() when the caller first starts, but we can't rely on
119
         *       it later so we need to cache our findings for use later */
120
        if (state.sup_syscall >= 0)
61,670✔
121
                return state.sup_syscall;
122

123
#if SYSCALL_ALLOWLIST_ENABLE
124
        /* architecture allowlist */
125
        switch (arch_def_native->token) {
126
        case SCMP_ARCH_X86_64:
127
        case SCMP_ARCH_ARM:
128
        case SCMP_ARCH_AARCH64:
129
        case SCMP_ARCH_PPC64:
130
        case SCMP_ARCH_PPC64LE:
131
        case SCMP_ARCH_S390:
132
        case SCMP_ARCH_S390X:
133
        case SCMP_ARCH_RISCV64:
134
                break;
135
        default:
136
                goto unsupported;
137
        }
138
#endif
139

140
        nr_seccomp = arch_syscall_resolve_name(arch_def_native, "seccomp");
6,853✔
141
        if (nr_seccomp < 0)
6,853✔
142
                goto unsupported;
×
143

144
        /* this is an invalid call because the second argument is non-zero, but
145
         * depending on the errno value of ENOSYS or EINVAL we can guess if the
146
         * seccomp() syscall is supported or not */
147
        rc = syscall(nr_seccomp, SECCOMP_SET_MODE_STRICT, 1, NULL);
6,853✔
148
        if (rc < 0 && errno == EINVAL)
6,853✔
149
                goto supported;
6,853✔
150

151
unsupported:
×
152
        state.sup_syscall = 0;
×
153
        return 0;
×
154
supported:
6,853✔
155
        state.nr_seccomp = nr_seccomp;
6,853✔
156
        state.sup_syscall = 1;
6,853✔
157
        return 1;
6,853✔
158
}
159

160
/**
161
 * Force the seccomp() syscall support setting
162
 * @param enable the intended support state
163
 *
164
 * This function overrides the current seccomp() syscall support setting; this
165
 * is very much a "use at your own risk" function.
166
 *
167
 */
168
void sys_set_seccomp_syscall(bool enable)
723✔
169
{
170
        state.sup_syscall = (enable ? 1 : 0);
723✔
171
}
723✔
172

173
/**
174
 * Check to see if a seccomp action is supported
175
 * @param action the seccomp action
176
 *
177
 * This function checks to see if a seccomp action is supported by the system.
178
 * Return one if the action is supported, zero otherwise.
179
 *
180
 */
181
int sys_chk_seccomp_action(uint32_t action)
79,054✔
182
{
183
        if (action == SCMP_ACT_KILL_PROCESS) {
79,054✔
184
                if (state.sup_kill_process < 0) {
7,208✔
185
                        if (sys_chk_seccomp_syscall() == 1 &&
13,704✔
186
                            syscall(state.nr_seccomp,
6,852✔
187
                                    SECCOMP_GET_ACTION_AVAIL, 0, &action) == 0)
188
                                state.sup_kill_process = 1;
6,852✔
189
                        else
190
                                state.sup_kill_process = 0;
×
191
                }
192

193
                return state.sup_kill_process;
7,208✔
194
        } else if (action == SCMP_ACT_KILL_THREAD) {
71,846✔
195
                return 1;
196
        } else if (action == SCMP_ACT_TRAP) {
63,174✔
197
                return 1;
198
        } else if ((action == SCMP_ACT_ERRNO(action & 0x0000ffff)) &&
62,150✔
199
                   ((action & 0x0000ffff) < MAX_ERRNO)) {
200
                return 1;
201
        } else if (action == SCMP_ACT_TRACE(action & 0x0000ffff)) {
56,929✔
202
                return 1;
203
        } else if (action == SCMP_ACT_LOG) {
56,579✔
204
                if (state.sup_action_log < 0) {
7,553✔
205
                        if (sys_chk_seccomp_syscall() == 1 &&
13,704✔
206
                            syscall(state.nr_seccomp,
6,852✔
207
                                    SECCOMP_GET_ACTION_AVAIL, 0, &action) == 0)
208
                                state.sup_action_log = 1;
6,852✔
209
                        else
210
                                state.sup_action_log = 0;
×
211
                }
212

213
                return state.sup_action_log;
7,553✔
214
        } else if (action == SCMP_ACT_ALLOW) {
49,026✔
215
                return 1;
216
        } else if (action == SCMP_ACT_NOTIFY) {
6,856✔
217
                if (state.sup_user_notif < 0) {
6,852✔
218
                        struct seccomp_notif_sizes sizes;
6,852✔
219
                        if (sys_chk_seccomp_syscall() == 1 &&
13,704✔
220
                            syscall(state.nr_seccomp,
6,852✔
221
                                    SECCOMP_GET_NOTIF_SIZES, 0, &sizes) == 0)
222
                                state.sup_user_notif = 1;
6,852✔
223
                        else
224
                                state.sup_user_notif = 0;
×
225
                }
226

227
                return state.sup_user_notif;
6,852✔
228
        }
229

230
        return 0;
231
}
232

233
/**
234
 * Force a seccomp action support setting
235
 * @param action the seccomp action
236
 * @param enable the intended support state
237
 *
238
 * This function overrides the current seccomp action support setting; this
239
 * is very much a "use at your own risk" function.
240
 */
241
void sys_set_seccomp_action(uint32_t action, bool enable)
2,169✔
242
{
243
        switch (action) {
2,169✔
244
        case SCMP_ACT_LOG:
723✔
245
                state.sup_action_log = (enable ? 1 : 0);
723✔
246
                break;
723✔
247
        case SCMP_ACT_KILL_PROCESS:
723✔
248
                state.sup_kill_process = (enable ? 1 : 0);
723✔
249
                break;
723✔
250
        case SCMP_ACT_NOTIFY:
723✔
251
                state.sup_user_notif = (enable ? 1 : 0);
723✔
252
                break;
723✔
253
        }
254
}
2,169✔
255

256
/**
257
 * Check to see if a seccomp() flag is supported by the kernel
258
 * @param flag the seccomp() flag
259
 *
260
 * This function checks to see if a seccomp() flag is supported by the kernel.
261
 * Return one if the flag is supported, zero otherwise.
262
 *
263
 */
264
static int _sys_chk_flag_kernel(int flag)
34,261✔
265
{
266
        /* this is an invalid seccomp(2) call because the last argument
267
         * is NULL, but depending on the errno value of EFAULT we can
268
         * guess if the filter flag is supported or not */
269
        if (sys_chk_seccomp_syscall() == 1 &&
68,522✔
270
            syscall(state.nr_seccomp,
34,261✔
271
                    SECCOMP_SET_MODE_FILTER, flag, NULL) == -1 &&
34,261✔
272
            errno == EFAULT)
34,261✔
273
                return 1;
34,261✔
274

275
        return 0;
276
}
277

278
/**
279
 * Check to see if a seccomp() flag is supported
280
 * @param flag the seccomp() flag
281
 *
282
 * This function checks to see if a seccomp() flag is supported by the system.
283
 * Return one if the syscall is supported, zero if unsupported, negative values
284
 * on error.
285
 *
286
 */
287
int sys_chk_seccomp_flag(int flag)
84,797✔
288
{
289
        switch (flag) {
84,797✔
290
        case SECCOMP_FILTER_FLAG_TSYNC:
6,854✔
291
                if (state.sup_flag_tsync < 0)
6,854✔
292
                        state.sup_flag_tsync = _sys_chk_flag_kernel(flag);
6,852✔
293
                return state.sup_flag_tsync;
6,854✔
294
        case SECCOMP_FILTER_FLAG_LOG:
6,854✔
295
                if (state.sup_flag_log < 0)
6,854✔
296
                        state.sup_flag_log = _sys_chk_flag_kernel(flag);
6,852✔
297
                return state.sup_flag_log;
6,854✔
298
        case SECCOMP_FILTER_FLAG_SPEC_ALLOW:
6,854✔
299
                if (state.sup_flag_spec_allow < 0)
6,854✔
300
                        state.sup_flag_spec_allow = _sys_chk_flag_kernel(flag);
6,852✔
301
                return state.sup_flag_spec_allow;
6,854✔
302
        case SECCOMP_FILTER_FLAG_NEW_LISTENER:
6,852✔
303
                if (state.sup_flag_new_listener < 0)
6,852✔
304
                        state.sup_flag_new_listener = _sys_chk_flag_kernel(flag);
6,852✔
305
                return state.sup_flag_new_listener;
6,852✔
306
        case SECCOMP_FILTER_FLAG_TSYNC_ESRCH:
57,383✔
307
                if (state.sup_flag_tsync_esrch < 0)
57,383✔
308
                        state.sup_flag_tsync_esrch = _sys_chk_flag_kernel(flag);
6,853✔
309
                return state.sup_flag_tsync_esrch;
57,383✔
310
        }
311

312
        return -EOPNOTSUPP;
313
}
314

315
/**
316
 * Force a seccomp() syscall flag support setting
317
 * @param flag the seccomp() flag
318
 * @param enable the intended support state
319
 *
320
 * This function overrides the current seccomp() syscall support setting for a
321
 * given flag; this is very much a "use at your own risk" function.
322
 *
323
 */
324
void sys_set_seccomp_flag(int flag, bool enable)
3,615✔
325
{
326
        switch (flag) {
3,615✔
327
        case SECCOMP_FILTER_FLAG_TSYNC:
723✔
328
                state.sup_flag_tsync = (enable ? 1 : 0);
723✔
329
                break;
723✔
330
        case SECCOMP_FILTER_FLAG_LOG:
723✔
331
                state.sup_flag_log = (enable ? 1 : 0);
723✔
332
                break;
723✔
333
        case SECCOMP_FILTER_FLAG_SPEC_ALLOW:
723✔
334
                state.sup_flag_spec_allow = (enable ? 1 : 0);
723✔
335
                break;
723✔
336
        case SECCOMP_FILTER_FLAG_NEW_LISTENER:
723✔
337
                state.sup_flag_new_listener = (enable ? 1 : 0);
723✔
338
                break;
723✔
339
        case SECCOMP_FILTER_FLAG_TSYNC_ESRCH:
723✔
340
                state.sup_flag_tsync_esrch = (enable ? 1 : 0);
723✔
341
                break;
723✔
342
        }
343
}
3,615✔
344

345
/**
346
 * Loads the filter into the kernel
347
 * @param col the filter collection
348
 * @param rawrc pass the raw return code if true
349
 *
350
 * This function loads the given seccomp filter context into the kernel.  If
351
 * the filter was loaded correctly, the kernel will be enforcing the filter
352
 * when this function returns.  Returns zero on success, negative values on
353
 * error.
354
 *
355
 */
356
int sys_filter_load(struct db_filter_col *col, bool rawrc)
1✔
357
{
358
        int rc;
1✔
359
        bool tsync_notify;
1✔
360
        bool listener_req;
1✔
361
        struct bpf_program *prgm = NULL;
1✔
362

363
        rc = gen_bpf_generate(col, &prgm);
1✔
364
        if (rc < 0)
1✔
365
                return rc;
366

367
        /* attempt to set NO_NEW_PRIVS */
368
        if (col->attr.nnp_enable) {
1✔
369
                rc = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
1✔
370
                if (rc < 0)
1✔
371
                        goto filter_load_out;
×
372
        }
373

374
        tsync_notify = state.sup_flag_tsync_esrch > 0 && state.notify_fd == -1;
1✔
375
        listener_req = state.sup_user_notif > 0 && \
3✔
376
                       col->notify_used && state.notify_fd == -1;
1✔
377

378
        /* load the filter into the kernel */
379
        if (sys_chk_seccomp_syscall() == 1) {
1✔
380
                int flgs = 0;
1✔
381
                if (tsync_notify) {
1✔
382
                        if (col->attr.tsync_enable)
1✔
383
                                flgs |= SECCOMP_FILTER_FLAG_TSYNC | \
1✔
384
                                        SECCOMP_FILTER_FLAG_TSYNC_ESRCH;
385
                        if (listener_req)
1✔
386
                                flgs |= SECCOMP_FILTER_FLAG_NEW_LISTENER;
×
387
                } else if (col->attr.tsync_enable) {
×
388
                        if (listener_req) {
×
389
                                /* NOTE: we _should_ catch this in db.c */
390
                                rc = -EFAULT;
×
391
                                goto filter_load_out;
×
392
                        }
393
                        flgs |= SECCOMP_FILTER_FLAG_TSYNC;
394
                } else if (listener_req)
×
395
                        flgs |= SECCOMP_FILTER_FLAG_NEW_LISTENER;
×
396
                if (col->attr.log_enable)
1✔
397
                        flgs |= SECCOMP_FILTER_FLAG_LOG;
1✔
398
                if (col->attr.spec_allow)
1✔
399
                        flgs |= SECCOMP_FILTER_FLAG_SPEC_ALLOW;
1✔
400
                rc = syscall(state.nr_seccomp,
1✔
401
                             SECCOMP_SET_MODE_FILTER, flgs, prgm);
402
                if (tsync_notify && rc > 0) {
1✔
403
                        /* return 0 on NEW_LISTENER success, but save the fd */
404
                        state.notify_fd = rc;
×
405
                        rc = 0;
×
406
                } else if (rc > 0 && col->attr.tsync_enable) {
1✔
407
                        /* always return -ESRCH if we fail to sync threads */
408
                        errno = ESRCH;
×
409
                        rc = -errno;
×
410
                } else if (rc > 0 && state.sup_user_notif > 0) {
1✔
411
                        /* return 0 on NEW_LISTENER success, but save the fd */
412
                        state.notify_fd = rc;
×
413
                        rc = 0;
×
414
                }
415
        } else
416
                rc = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, prgm);
×
417

418
filter_load_out:
1✔
419
        /* cleanup and return */
420
        gen_bpf_release(prgm);
1✔
421
        if (rc == -ESRCH)
1✔
422
                return -ESRCH;
423
        if (rc < 0)
1✔
424
                return (rawrc ? -errno : -ECANCELED);
×
425
        return rc;
426
}
427

428
/**
429
 * Return the userspace notification fd
430
 *
431
 * This function returns the userspace notification fd from
432
 * SECCOMP_FILTER_FLAG_NEW_LISTENER.  If the notification fd has not yet been
433
 * set, or an error has occurred, -1 is returned.
434
 *
435
 */
436
int sys_notify_fd(void)
1✔
437
{
438
        return state.notify_fd;
1✔
439
}
440

441
/**
442
 * Allocate a pair of notification request/response structures
443
 * @param req the request location
444
 * @param resp the response location
445
 *
446
 * This function allocates a pair of request/response structure by computing
447
 * the correct sized based on the currently running kernel. It returns zero on
448
 * success, and negative values on failure.
449
 *
450
 */
451
int sys_notify_alloc(struct seccomp_notif **req,
3✔
452
                     struct seccomp_notif_resp **resp)
453
{
454
        int rc;
3✔
455
        static struct seccomp_notif_sizes sizes = { 0, 0, 0 };
3✔
456

457
        if (state.sup_syscall <= 0)
3✔
458
                return -EOPNOTSUPP;
459

460
        if (sizes.seccomp_notif == 0 && sizes.seccomp_notif_resp == 0) {
3✔
461
                rc = syscall(__NR_seccomp, SECCOMP_GET_NOTIF_SIZES, 0, &sizes);
1✔
462
                if (rc < 0)
1✔
463
                        return -ECANCELED;
464
        }
465
        if (sizes.seccomp_notif == 0 || sizes.seccomp_notif_resp == 0)
3✔
466
                return -EFAULT;
467

468
        if (req) {
3✔
469
                *req = zmalloc(sizes.seccomp_notif);
1✔
470
                if (!*req)
1✔
471
                        return -ENOMEM;
472
        }
473

474
        if (resp) {
3✔
475
                *resp = zmalloc(sizes.seccomp_notif_resp);
1✔
476
                if (!*resp) {
1✔
477
                        if (req)
×
478
                                free(*req);
×
479
                        return -ENOMEM;
×
480
                }
481
        }
482

483
        return 0;
484
}
485

486
/**
487
 * Receive a notification from a seccomp notification fd
488
 * @param fd the notification fd
489
 * @param req the request buffer to save into
490
 *
491
 * Blocks waiting for a notification on this fd. This function is thread safe
492
 * (synchronization is performed in the kernel). Returns zero on success,
493
 * negative values on error.
494
 *
495
 */
496
int sys_notify_receive(int fd, struct seccomp_notif *req)
1✔
497
{
498
        if (state.sup_user_notif <= 0)
1✔
499
                return -EOPNOTSUPP;
500

501
        if (ioctl(fd, SECCOMP_IOCTL_NOTIF_RECV, req) < 0)
×
502
                return -ECANCELED;
×
503

504
        return 0;
505
}
506

507
/**
508
 * Send a notification response to a seccomp notification fd
509
 * @param fd the notification fd
510
 * @param resp the response buffer to use
511
 *
512
 * Sends a notification response on this fd. This function is thread safe
513
 * (synchronization is performed in the kernel). Returns zero on success,
514
 * negative values on error.
515
 *
516
 */
517
int sys_notify_respond(int fd, struct seccomp_notif_resp *resp)
1✔
518
{
519
        if (state.sup_user_notif <= 0)
1✔
520
                return -EOPNOTSUPP;
521

522
        if (ioctl(fd, SECCOMP_IOCTL_NOTIF_SEND, resp) < 0)
×
523
                return -ECANCELED;
×
524
        return 0;
525
}
526

527
/**
528
 * Check if a notification id is still valid
529
 * @param fd the notification fd
530
 * @param id the id to test
531
 *
532
 * Checks to see if a notification id is still valid. Returns 0 on success, and
533
 * negative values on failure.
534
 *
535
 */
536
int sys_notify_id_valid(int fd, uint64_t id)
1✔
537
{
538
        int rc;
1✔
539
        if (state.sup_user_notif <= 0)
1✔
540
                return -EOPNOTSUPP;
541

542
        rc = ioctl(fd, SECCOMP_IOCTL_NOTIF_ID_VALID, &id);
×
543
        if (rc < 0 && errno == EINVAL)
×
544
                /* It is possible that libseccomp was built against newer kernel
545
                 * headers than the kernel it is running on. If so, the older
546
                 * runtime kernel may not support the "fixed"
547
                 * SECCOMP_IOCTL_NOTIF_ID_VALID ioctl number which was introduced in
548
                 * kernel commit 47e33c05f9f0 ("seccomp: Fix ioctl number for
549
                 * SECCOMP_IOCTL_NOTIF_ID_VALID"). Try the old value. */
550
                rc = ioctl(fd, SECCOMP_IOCTL_NOTIF_ID_VALID_WRONG_DIR, &id);
×
551
        if (rc < 0)
×
552
                return -ENOENT;
×
553
        return 0;
554
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc