forked from canonical/snapd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathseccomp-support-ext.c
98 lines (89 loc) · 3.29 KB
/
seccomp-support-ext.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/*
* Copyright (C) 2019 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "seccomp-support-ext.h"
#include <errno.h>
#include <linux/seccomp.h>
#include <stdio.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include "../libsnap-confine-private/utils.h"
#ifndef SECCOMP_FILTER_FLAG_LOG
#define SECCOMP_FILTER_FLAG_LOG 2
#endif
#ifndef seccomp
// prototype because we build with -Wstrict-prototypes
int seccomp(unsigned int operation, unsigned int flags, void *args);
int seccomp(unsigned int operation, unsigned int flags, void *args) {
errno = 0;
return syscall(__NR_seccomp, operation, flags, args);
}
#endif
size_t sc_read_seccomp_filter(const char *filename, char *buf, size_t buf_size) {
if (buf_size == 0) {
die("seccomp load buffer cannot be empty");
}
FILE *file = fopen(filename, "rb");
if (file == NULL) {
die("cannot open seccomp filter %s", filename);
}
size_t num_read = fread(buf, 1, buf_size - 1, file);
buf[num_read] = '\0';
if (ferror(file) != 0) {
die("cannot read seccomp profile %s", filename);
}
if (feof(file) == 0) {
die("cannot fit seccomp profile %s to memory buffer", filename);
}
fclose(file);
debug("read %zu bytes from %s", num_read, filename);
return num_read;
}
void sc_apply_seccomp_filter(struct sock_fprog *prog) {
int err;
// Load filter into the kernel (by this point we have dropped to the
// calling user but still retain CAP_SYS_ADMIN).
//
// Importantly we are intentionally *not* setting NO_NEW_PRIVS because it
// interferes with exec transitions in AppArmor with certain snapd
// interfaces. Not setting NO_NEW_PRIVS does mean that applications can
// adjust their sandbox if they have CAP_SYS_ADMIN or, if running on < 4.8
// kernels, break out of the seccomp via ptrace. Both CAP_SYS_ADMIN and
// 'ptrace (trace)' are blocked by AppArmor with typical snapd interfaces.
err = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_LOG, prog);
if (err != 0) {
/* The profile may fail to load using the "modern" interface.
* In such case use the older prctl-based interface instead. */
switch (errno) {
case ENOSYS:
debug("kernel doesn't support the seccomp(2) syscall");
break;
case EINVAL:
debug("kernel may not support the SECCOMP_FILTER_FLAG_LOG flag");
break;
}
debug("falling back to prctl(2) syscall to load seccomp filter");
err = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, prog);
if (err != 0) {
die("cannot apply seccomp profile");
}
}
}