]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-execute.c
execute: support syscall filtering using seccomp filters
[thirdparty/systemd.git] / src / core / dbus-execute.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <dbus/dbus.h>
24 #include <sys/prctl.h>
25
26 #include "dbus-execute.h"
27 #include "missing.h"
28 #include "ioprio.h"
29 #include "strv.h"
30 #include "dbus-common.h"
31 #include "syscall-list.h"
32
33 DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_kill_mode, kill_mode, KillMode);
34
35 DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput);
36 DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput);
37
38 int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data) {
39 char **env_files = data, **j;
40 DBusMessageIter sub, sub2;
41
42 assert(i);
43 assert(property);
44
45 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sb)", &sub))
46 return -ENOMEM;
47
48 STRV_FOREACH(j, env_files) {
49 dbus_bool_t b = false;
50 char *fn = *j;
51
52 if (fn[0] == '-') {
53 b = true;
54 fn++;
55 }
56
57 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
58 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &fn) ||
59 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) ||
60 !dbus_message_iter_close_container(&sub, &sub2))
61 return -ENOMEM;
62 }
63
64 if (!dbus_message_iter_close_container(i, &sub))
65 return -ENOMEM;
66
67 return 0;
68 }
69
70 int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data) {
71 ExecContext *c = data;
72 int32_t n;
73
74 assert(i);
75 assert(property);
76 assert(c);
77
78 if (c->oom_score_adjust_set)
79 n = c->oom_score_adjust;
80 else {
81 char *t;
82
83 n = 0;
84 if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0) {
85 safe_atoi(t, &n);
86 free(t);
87 }
88 }
89
90 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
91 return -ENOMEM;
92
93 return 0;
94 }
95
96 int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data) {
97 ExecContext *c = data;
98 int32_t n;
99
100 assert(i);
101 assert(property);
102 assert(c);
103
104 if (c->nice_set)
105 n = c->nice;
106 else
107 n = getpriority(PRIO_PROCESS, 0);
108
109 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
110 return -ENOMEM;
111
112 return 0;
113 }
114
115 int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data) {
116 ExecContext *c = data;
117 int32_t n;
118
119 assert(i);
120 assert(property);
121 assert(c);
122
123 if (c->ioprio_set)
124 n = c->ioprio;
125 else
126 n = ioprio_get(IOPRIO_WHO_PROCESS, 0);
127
128 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
129 return -ENOMEM;
130
131 return 0;
132 }
133
134 int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data) {
135 ExecContext *c = data;
136 int32_t n;
137
138 assert(i);
139 assert(property);
140 assert(c);
141
142 if (c->cpu_sched_set)
143 n = c->cpu_sched_policy;
144 else
145 n = sched_getscheduler(0);
146
147 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
148 return -ENOMEM;
149
150 return 0;
151 }
152
153 int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data) {
154 ExecContext *c = data;
155 int32_t n;
156
157 assert(i);
158 assert(property);
159 assert(c);
160
161 if (c->cpu_sched_set)
162 n = c->cpu_sched_priority;
163 else {
164 struct sched_param p;
165 n = 0;
166
167 zero(p);
168 if (sched_getparam(0, &p) >= 0)
169 n = p.sched_priority;
170 }
171
172 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
173 return -ENOMEM;
174
175 return 0;
176 }
177
178 int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data) {
179 ExecContext *c = data;
180 dbus_bool_t b;
181 DBusMessageIter sub;
182
183 assert(i);
184 assert(property);
185 assert(c);
186
187 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub))
188 return -ENOMEM;
189
190 if (c->cpuset)
191 b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
192 else
193 b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, 0);
194
195 if (!b)
196 return -ENOMEM;
197
198 if (!dbus_message_iter_close_container(i, &sub))
199 return -ENOMEM;
200
201 return 0;
202 }
203
204 int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data) {
205 ExecContext *c = data;
206 uint64_t u;
207
208 assert(i);
209 assert(property);
210 assert(c);
211
212 if (c->timer_slack_nsec != (nsec_t) -1)
213 u = (uint64_t) c->timer_slack_nsec;
214 else
215 u = (uint64_t) prctl(PR_GET_TIMERSLACK);
216
217 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
218 return -ENOMEM;
219
220 return 0;
221 }
222
223 int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data) {
224 ExecContext *c = data;
225 uint64_t normal, inverted;
226
227 assert(i);
228 assert(property);
229 assert(c);
230
231 /* We store this negated internally, to match the kernel, but
232 * we expose it normalized. */
233
234 normal = *(uint64_t*) data;
235 inverted = ~normal;
236
237 return bus_property_append_uint64(i, property, &inverted);
238 }
239
240 int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data) {
241 ExecContext *c = data;
242 char *t = NULL;
243 const char *s;
244 dbus_bool_t b;
245
246 assert(i);
247 assert(property);
248 assert(c);
249
250 if (c->capabilities)
251 s = t = cap_to_text(c->capabilities, NULL);
252 else
253 s = "";
254
255 if (!s)
256 return -ENOMEM;
257
258 b = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &s);
259
260 if (t)
261 cap_free(t);
262
263 if (!b)
264 return -ENOMEM;
265
266 return 0;
267 }
268
269 int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data) {
270 ExecContext *c = data;
271 int r;
272 uint64_t u;
273
274 assert(i);
275 assert(property);
276 assert(c);
277
278 assert_se((r = rlimit_from_string(property)) >= 0);
279
280 if (c->rlimit[r])
281 u = (uint64_t) c->rlimit[r]->rlim_max;
282 else {
283 struct rlimit rl;
284
285 zero(rl);
286 getrlimit(r, &rl);
287
288 u = (uint64_t) rl.rlim_max;
289 }
290
291 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
292 return -ENOMEM;
293
294 return 0;
295 }
296
297 int bus_execute_append_command(DBusMessageIter *i, const char *property, void *data) {
298 ExecCommand *c = data;
299 DBusMessageIter sub, sub2, sub3;
300
301 assert(i);
302 assert(property);
303
304 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sasbttttuii)", &sub))
305 return -ENOMEM;
306
307 LIST_FOREACH(command, c, c) {
308 char **l;
309 uint32_t pid;
310 int32_t code, status;
311 dbus_bool_t b;
312
313 if (!c->path)
314 continue;
315
316 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
317 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &c->path) ||
318 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_ARRAY, "s", &sub3))
319 return -ENOMEM;
320
321 STRV_FOREACH(l, c->argv)
322 if (!dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, l))
323 return -ENOMEM;
324
325 pid = (uint32_t) c->exec_status.pid;
326 code = (int32_t) c->exec_status.code;
327 status = (int32_t) c->exec_status.status;
328
329 b = !!c->ignore;
330
331 if (!dbus_message_iter_close_container(&sub2, &sub3) ||
332 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) ||
333 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.realtime) ||
334 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.monotonic) ||
335 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.realtime) ||
336 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.monotonic) ||
337 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid) ||
338 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &code) ||
339 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &status))
340 return -ENOMEM;
341
342 if (!dbus_message_iter_close_container(&sub, &sub2))
343 return -ENOMEM;
344 }
345
346 if (!dbus_message_iter_close_container(i, &sub))
347 return -ENOMEM;
348
349 return 0;
350 }
351
352 int bus_execute_append_syscall_filter(DBusMessageIter *i, const char *property, void *data) {
353 ExecContext *c = data;
354 dbus_bool_t b;
355 DBusMessageIter sub;
356
357 assert(i);
358 assert(property);
359 assert(c);
360
361 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "u", &sub))
362 return -ENOMEM;
363
364 if (c->syscall_filter)
365 b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_UINT32, &c->syscall_filter, (syscall_max() + 31) >> 4);
366 else
367 b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_UINT32, &c->syscall_filter, 0);
368
369 if (!b)
370 return -ENOMEM;
371
372 if (!dbus_message_iter_close_container(i, &sub))
373 return -ENOMEM;
374
375 return 0;
376 }
377
378 const BusProperty bus_exec_context_properties[] = {
379 { "Environment", bus_property_append_strv, "as", offsetof(ExecContext, environment), true },
380 { "EnvironmentFiles", bus_execute_append_env_files, "a(sb)", offsetof(ExecContext, environment_files), true },
381 { "UMask", bus_property_append_mode, "u", offsetof(ExecContext, umask) },
382 { "LimitCPU", bus_execute_append_rlimits, "t", 0 },
383 { "LimitFSIZE", bus_execute_append_rlimits, "t", 0 },
384 { "LimitDATA", bus_execute_append_rlimits, "t", 0 },
385 { "LimitSTACK", bus_execute_append_rlimits, "t", 0 },
386 { "LimitCORE", bus_execute_append_rlimits, "t", 0 },
387 { "LimitRSS", bus_execute_append_rlimits, "t", 0 },
388 { "LimitNOFILE", bus_execute_append_rlimits, "t", 0 },
389 { "LimitAS", bus_execute_append_rlimits, "t", 0 },
390 { "LimitNPROC", bus_execute_append_rlimits, "t", 0 },
391 { "LimitMEMLOCK", bus_execute_append_rlimits, "t", 0 },
392 { "LimitLOCKS", bus_execute_append_rlimits, "t", 0 },
393 { "LimitSIGPENDING", bus_execute_append_rlimits, "t", 0 },
394 { "LimitMSGQUEUE", bus_execute_append_rlimits, "t", 0 },
395 { "LimitNICE", bus_execute_append_rlimits, "t", 0 },
396 { "LimitRTPRIO", bus_execute_append_rlimits, "t", 0 },
397 { "LimitRTTIME", bus_execute_append_rlimits, "t", 0 },
398 { "WorkingDirectory", bus_property_append_string, "s", offsetof(ExecContext, working_directory), true },
399 { "RootDirectory", bus_property_append_string, "s", offsetof(ExecContext, root_directory), true },
400 { "OOMScoreAdjust", bus_execute_append_oom_score_adjust, "i", 0 },
401 { "Nice", bus_execute_append_nice, "i", 0 },
402 { "IOScheduling", bus_execute_append_ioprio, "i", 0 },
403 { "CPUSchedulingPolicy", bus_execute_append_cpu_sched_policy, "i", 0 },
404 { "CPUSchedulingPriority", bus_execute_append_cpu_sched_priority, "i", 0 },
405 { "CPUAffinity", bus_execute_append_affinity, "ay", 0 },
406 { "TimerSlackNSec", bus_execute_append_timer_slack_nsec, "t", 0 },
407 { "CPUSchedulingResetOnFork", bus_property_append_bool, "b", offsetof(ExecContext, cpu_sched_reset_on_fork) },
408 { "NonBlocking", bus_property_append_bool, "b", offsetof(ExecContext, non_blocking) },
409 { "StandardInput", bus_execute_append_input, "s", offsetof(ExecContext, std_input) },
410 { "StandardOutput", bus_execute_append_output, "s", offsetof(ExecContext, std_output) },
411 { "StandardError", bus_execute_append_output, "s", offsetof(ExecContext, std_error) },
412 { "TTYPath", bus_property_append_string, "s", offsetof(ExecContext, tty_path), true },
413 { "TTYReset", bus_property_append_bool, "b", offsetof(ExecContext, tty_reset) },
414 { "TTYVHangup", bus_property_append_bool, "b", offsetof(ExecContext, tty_vhangup) },
415 { "TTYVTDisallocate", bus_property_append_bool, "b", offsetof(ExecContext, tty_vt_disallocate) },
416 { "SyslogPriority", bus_property_append_int, "i", offsetof(ExecContext, syslog_priority) },
417 { "SyslogIdentifier", bus_property_append_string, "s", offsetof(ExecContext, syslog_identifier), true },
418 { "SyslogLevelPrefix", bus_property_append_bool, "b", offsetof(ExecContext, syslog_level_prefix) },
419 { "Capabilities", bus_execute_append_capabilities, "s", 0 },
420 { "SecureBits", bus_property_append_int, "i", offsetof(ExecContext, secure_bits) },
421 { "CapabilityBoundingSet", bus_execute_append_capability_bs, "t", offsetof(ExecContext, capability_bounding_set_drop) },
422 { "User", bus_property_append_string, "s", offsetof(ExecContext, user), true },
423 { "Group", bus_property_append_string, "s", offsetof(ExecContext, group), true },
424 { "SupplementaryGroups", bus_property_append_strv, "as", offsetof(ExecContext, supplementary_groups), true },
425 { "TCPWrapName", bus_property_append_string, "s", offsetof(ExecContext, tcpwrap_name), true },
426 { "PAMName", bus_property_append_string, "s", offsetof(ExecContext, pam_name), true },
427 { "ReadWriteDirectories", bus_property_append_strv, "as", offsetof(ExecContext, read_write_dirs), true },
428 { "ReadOnlyDirectories", bus_property_append_strv, "as", offsetof(ExecContext, read_only_dirs), true },
429 { "InaccessibleDirectories", bus_property_append_strv, "as", offsetof(ExecContext, inaccessible_dirs), true },
430 { "MountFlags", bus_property_append_ul, "t", offsetof(ExecContext, mount_flags) },
431 { "PrivateTmp", bus_property_append_bool, "b", offsetof(ExecContext, private_tmp) },
432 { "PrivateNetwork", bus_property_append_bool, "b", offsetof(ExecContext, private_network) },
433 { "SameProcessGroup", bus_property_append_bool, "b", offsetof(ExecContext, same_pgrp) },
434 { "KillMode", bus_execute_append_kill_mode, "s", offsetof(ExecContext, kill_mode) },
435 { "KillSignal", bus_property_append_int, "i", offsetof(ExecContext, kill_signal) },
436 { "UtmpIdentifier", bus_property_append_string, "s", offsetof(ExecContext, utmp_id), true },
437 { "ControlGroupModify", bus_property_append_bool, "b", offsetof(ExecContext, control_group_modify) },
438 { "ControlGroupPersistent", bus_property_append_tristate_false, "b", offsetof(ExecContext, control_group_persistent) },
439 { "IgnoreSIGPIPE", bus_property_append_bool, "b", offsetof(ExecContext, ignore_sigpipe) },
440 { "NoNewPrivileges", bus_property_append_bool, "b", offsetof(ExecContext, no_new_privileges) },
441 { "SystemCallFilter", bus_execute_append_syscall_filter, "au", 0 },
442 { NULL, }
443 };