Merge remote-tracking branch 'remotes/kraxel/tags/ui-20180626-pull-request' into...
[qemu/ar7.git] / qemu-seccomp.c
blob148e4c6f24ddf169ca3f73a846e55fad3afe806b
1 /*
2 * QEMU seccomp mode 2 support with libseccomp
4 * Copyright IBM, Corp. 2012
6 * Authors:
7 * Eduardo Otubo <eotubo@br.ibm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
12 * Contributions after 2012-01-13 are licensed under the terms of the
13 * GNU GPL, version 2 or (at your option) any later version.
15 #include "qemu/osdep.h"
16 #include "qemu/config-file.h"
17 #include "qemu/option.h"
18 #include "qemu/module.h"
19 #include "qemu/error-report.h"
20 #include <sys/prctl.h>
21 #include <seccomp.h>
22 #include "sysemu/seccomp.h"
24 /* For some architectures (notably ARM) cacheflush is not supported until
25 * libseccomp 2.2.3, but configure enforces that we are using a more recent
26 * version on those hosts, so it is OK for this check to be less strict.
28 #if SCMP_VER_MAJOR >= 3
29 #define HAVE_CACHEFLUSH
30 #elif SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR >= 2
31 #define HAVE_CACHEFLUSH
32 #endif
34 struct QemuSeccompSyscall {
35 int32_t num;
36 uint8_t set;
39 static const struct QemuSeccompSyscall blacklist[] = {
40 /* default set of syscalls to blacklist */
41 { SCMP_SYS(reboot), QEMU_SECCOMP_SET_DEFAULT },
42 { SCMP_SYS(swapon), QEMU_SECCOMP_SET_DEFAULT },
43 { SCMP_SYS(swapoff), QEMU_SECCOMP_SET_DEFAULT },
44 { SCMP_SYS(syslog), QEMU_SECCOMP_SET_DEFAULT },
45 { SCMP_SYS(mount), QEMU_SECCOMP_SET_DEFAULT },
46 { SCMP_SYS(umount), QEMU_SECCOMP_SET_DEFAULT },
47 { SCMP_SYS(kexec_load), QEMU_SECCOMP_SET_DEFAULT },
48 { SCMP_SYS(afs_syscall), QEMU_SECCOMP_SET_DEFAULT },
49 { SCMP_SYS(break), QEMU_SECCOMP_SET_DEFAULT },
50 { SCMP_SYS(ftime), QEMU_SECCOMP_SET_DEFAULT },
51 { SCMP_SYS(getpmsg), QEMU_SECCOMP_SET_DEFAULT },
52 { SCMP_SYS(gtty), QEMU_SECCOMP_SET_DEFAULT },
53 { SCMP_SYS(lock), QEMU_SECCOMP_SET_DEFAULT },
54 { SCMP_SYS(mpx), QEMU_SECCOMP_SET_DEFAULT },
55 { SCMP_SYS(prof), QEMU_SECCOMP_SET_DEFAULT },
56 { SCMP_SYS(profil), QEMU_SECCOMP_SET_DEFAULT },
57 { SCMP_SYS(putpmsg), QEMU_SECCOMP_SET_DEFAULT },
58 { SCMP_SYS(security), QEMU_SECCOMP_SET_DEFAULT },
59 { SCMP_SYS(stty), QEMU_SECCOMP_SET_DEFAULT },
60 { SCMP_SYS(tuxcall), QEMU_SECCOMP_SET_DEFAULT },
61 { SCMP_SYS(ulimit), QEMU_SECCOMP_SET_DEFAULT },
62 { SCMP_SYS(vserver), QEMU_SECCOMP_SET_DEFAULT },
63 /* obsolete */
64 { SCMP_SYS(readdir), QEMU_SECCOMP_SET_OBSOLETE },
65 { SCMP_SYS(_sysctl), QEMU_SECCOMP_SET_OBSOLETE },
66 { SCMP_SYS(bdflush), QEMU_SECCOMP_SET_OBSOLETE },
67 { SCMP_SYS(create_module), QEMU_SECCOMP_SET_OBSOLETE },
68 { SCMP_SYS(get_kernel_syms), QEMU_SECCOMP_SET_OBSOLETE },
69 { SCMP_SYS(query_module), QEMU_SECCOMP_SET_OBSOLETE },
70 { SCMP_SYS(sgetmask), QEMU_SECCOMP_SET_OBSOLETE },
71 { SCMP_SYS(ssetmask), QEMU_SECCOMP_SET_OBSOLETE },
72 { SCMP_SYS(sysfs), QEMU_SECCOMP_SET_OBSOLETE },
73 { SCMP_SYS(uselib), QEMU_SECCOMP_SET_OBSOLETE },
74 { SCMP_SYS(ustat), QEMU_SECCOMP_SET_OBSOLETE },
75 /* privileged */
76 { SCMP_SYS(setuid), QEMU_SECCOMP_SET_PRIVILEGED },
77 { SCMP_SYS(setgid), QEMU_SECCOMP_SET_PRIVILEGED },
78 { SCMP_SYS(setpgid), QEMU_SECCOMP_SET_PRIVILEGED },
79 { SCMP_SYS(setsid), QEMU_SECCOMP_SET_PRIVILEGED },
80 { SCMP_SYS(setreuid), QEMU_SECCOMP_SET_PRIVILEGED },
81 { SCMP_SYS(setregid), QEMU_SECCOMP_SET_PRIVILEGED },
82 { SCMP_SYS(setresuid), QEMU_SECCOMP_SET_PRIVILEGED },
83 { SCMP_SYS(setresgid), QEMU_SECCOMP_SET_PRIVILEGED },
84 { SCMP_SYS(setfsuid), QEMU_SECCOMP_SET_PRIVILEGED },
85 { SCMP_SYS(setfsgid), QEMU_SECCOMP_SET_PRIVILEGED },
86 /* spawn */
87 { SCMP_SYS(fork), QEMU_SECCOMP_SET_SPAWN },
88 { SCMP_SYS(vfork), QEMU_SECCOMP_SET_SPAWN },
89 { SCMP_SYS(execve), QEMU_SECCOMP_SET_SPAWN },
90 /* resource control */
91 { SCMP_SYS(getpriority), QEMU_SECCOMP_SET_RESOURCECTL },
92 { SCMP_SYS(setpriority), QEMU_SECCOMP_SET_RESOURCECTL },
93 { SCMP_SYS(sched_setparam), QEMU_SECCOMP_SET_RESOURCECTL },
94 { SCMP_SYS(sched_getparam), QEMU_SECCOMP_SET_RESOURCECTL },
95 { SCMP_SYS(sched_setscheduler), QEMU_SECCOMP_SET_RESOURCECTL },
96 { SCMP_SYS(sched_getscheduler), QEMU_SECCOMP_SET_RESOURCECTL },
97 { SCMP_SYS(sched_setaffinity), QEMU_SECCOMP_SET_RESOURCECTL },
98 { SCMP_SYS(sched_getaffinity), QEMU_SECCOMP_SET_RESOURCECTL },
99 { SCMP_SYS(sched_get_priority_max), QEMU_SECCOMP_SET_RESOURCECTL },
100 { SCMP_SYS(sched_get_priority_min), QEMU_SECCOMP_SET_RESOURCECTL },
104 static int seccomp_start(uint32_t seccomp_opts)
106 int rc = 0;
107 unsigned int i = 0;
108 scmp_filter_ctx ctx;
110 ctx = seccomp_init(SCMP_ACT_ALLOW);
111 if (ctx == NULL) {
112 rc = -1;
113 goto seccomp_return;
116 for (i = 0; i < ARRAY_SIZE(blacklist); i++) {
117 if (!(seccomp_opts & blacklist[i].set)) {
118 continue;
121 rc = seccomp_rule_add(ctx, SCMP_ACT_KILL, blacklist[i].num, 0);
122 if (rc < 0) {
123 goto seccomp_return;
127 rc = seccomp_load(ctx);
129 seccomp_return:
130 seccomp_release(ctx);
131 return rc;
134 #ifdef CONFIG_SECCOMP
135 int parse_sandbox(void *opaque, QemuOpts *opts, Error **errp)
137 if (qemu_opt_get_bool(opts, "enable", false)) {
138 uint32_t seccomp_opts = QEMU_SECCOMP_SET_DEFAULT
139 | QEMU_SECCOMP_SET_OBSOLETE;
140 const char *value = NULL;
142 value = qemu_opt_get(opts, "obsolete");
143 if (value) {
144 if (g_str_equal(value, "allow")) {
145 seccomp_opts &= ~QEMU_SECCOMP_SET_OBSOLETE;
146 } else if (g_str_equal(value, "deny")) {
147 /* this is the default option, this if is here
148 * to provide a little bit of consistency for
149 * the command line */
150 } else {
151 error_report("invalid argument for obsolete");
152 return -1;
156 value = qemu_opt_get(opts, "elevateprivileges");
157 if (value) {
158 if (g_str_equal(value, "deny")) {
159 seccomp_opts |= QEMU_SECCOMP_SET_PRIVILEGED;
160 } else if (g_str_equal(value, "children")) {
161 seccomp_opts |= QEMU_SECCOMP_SET_PRIVILEGED;
163 /* calling prctl directly because we're
164 * not sure if host has CAP_SYS_ADMIN set*/
165 if (prctl(PR_SET_NO_NEW_PRIVS, 1)) {
166 error_report("failed to set no_new_privs "
167 "aborting");
168 return -1;
170 } else if (g_str_equal(value, "allow")) {
171 /* default value */
172 } else {
173 error_report("invalid argument for elevateprivileges");
174 return -1;
178 value = qemu_opt_get(opts, "spawn");
179 if (value) {
180 if (g_str_equal(value, "deny")) {
181 seccomp_opts |= QEMU_SECCOMP_SET_SPAWN;
182 } else if (g_str_equal(value, "allow")) {
183 /* default value */
184 } else {
185 error_report("invalid argument for spawn");
186 return -1;
190 value = qemu_opt_get(opts, "resourcecontrol");
191 if (value) {
192 if (g_str_equal(value, "deny")) {
193 seccomp_opts |= QEMU_SECCOMP_SET_RESOURCECTL;
194 } else if (g_str_equal(value, "allow")) {
195 /* default value */
196 } else {
197 error_report("invalid argument for resourcecontrol");
198 return -1;
202 if (seccomp_start(seccomp_opts) < 0) {
203 error_report("failed to install seccomp syscall filter "
204 "in the kernel");
205 return -1;
209 return 0;
212 static QemuOptsList qemu_sandbox_opts = {
213 .name = "sandbox",
214 .implied_opt_name = "enable",
215 .head = QTAILQ_HEAD_INITIALIZER(qemu_sandbox_opts.head),
216 .desc = {
218 .name = "enable",
219 .type = QEMU_OPT_BOOL,
222 .name = "obsolete",
223 .type = QEMU_OPT_STRING,
226 .name = "elevateprivileges",
227 .type = QEMU_OPT_STRING,
230 .name = "spawn",
231 .type = QEMU_OPT_STRING,
234 .name = "resourcecontrol",
235 .type = QEMU_OPT_STRING,
237 { /* end of list */ }
241 static void seccomp_register(void)
243 qemu_add_opts(&qemu_sandbox_opts);
245 opts_init(seccomp_register);
246 #endif