Bug Summary

File:build-scan/../src/core/execute.c
Warning:line 1870, column 33
Potential leak of memory pointed to by 'uid_map'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name execute.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I src/core/libcore.a.p -I src/core -I ../src/core -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -I . -I .. -I /usr/include/libmount -I /usr/include/blkid -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/core/execute.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <errno(*__errno_location ()).h>
4#include <fcntl.h>
5#include <glob.h>
6#include <grp.h>
7#include <poll.h>
8#include <signal.h>
9#include <string.h>
10#include <sys/capability.h>
11#include <sys/eventfd.h>
12#include <sys/mman.h>
13#include <sys/personality.h>
14#include <sys/prctl.h>
15#include <sys/shm.h>
16#include <sys/socket.h>
17#include <sys/stat.h>
18#include <sys/types.h>
19#include <sys/un.h>
20#include <unistd.h>
21#include <utmpx.h>
22
23#if HAVE_PAM1
24#include <security/pam_appl.h>
25#endif
26
27#if HAVE_SELINUX1
28#include <selinux/selinux.h>
29#endif
30
31#if HAVE_SECCOMP1
32#include <seccomp.h>
33#endif
34
35#if HAVE_APPARMOR0
36#include <sys/apparmor.h>
37#endif
38
39#include "sd-messages.h"
40
41#include "af-list.h"
42#include "alloc-util.h"
43#if HAVE_APPARMOR0
44#include "apparmor-util.h"
45#endif
46#include "async.h"
47#include "barrier.h"
48#include "cap-list.h"
49#include "capability-util.h"
50#include "chown-recursive.h"
51#include "cpu-set-util.h"
52#include "def.h"
53#include "env-util.h"
54#include "errno-list.h"
55#include "execute.h"
56#include "exit-status.h"
57#include "fd-util.h"
58#include "fileio.h"
59#include "format-util.h"
60#include "fs-util.h"
61#include "glob-util.h"
62#include "io-util.h"
63#include "ioprio.h"
64#include "label.h"
65#include "log.h"
66#include "macro.h"
67#include "manager.h"
68#include "missing.h"
69#include "mkdir.h"
70#include "namespace.h"
71#include "parse-util.h"
72#include "path-util.h"
73#include "process-util.h"
74#include "rlimit-util.h"
75#include "rm-rf.h"
76#if HAVE_SECCOMP1
77#include "seccomp-util.h"
78#endif
79#include "securebits.h"
80#include "securebits-util.h"
81#include "selinux-util.h"
82#include "signal-util.h"
83#include "smack-util.h"
84#include "socket-util.h"
85#include "special.h"
86#include "stat-util.h"
87#include "string-table.h"
88#include "string-util.h"
89#include "strv.h"
90#include "syslog-util.h"
91#include "terminal-util.h"
92#include "umask-util.h"
93#include "unit.h"
94#include "user-util.h"
95#include "util.h"
96#include "utmp-wtmp.h"
97
98#define IDLE_TIMEOUT_USEC(5*((usec_t) 1000000ULL)) (5*USEC_PER_SEC((usec_t) 1000000ULL))
99#define IDLE_TIMEOUT2_USEC(1*((usec_t) 1000000ULL)) (1*USEC_PER_SEC((usec_t) 1000000ULL))
100
101/* This assumes there is a 'tty' group */
102#define TTY_MODE0620 0620
103
104#define SNDBUF_SIZE(8*1024*1024) (8*1024*1024)
105
106static int shift_fds(int fds[], size_t n_fds) {
107 int start, restart_from;
108
109 if (n_fds <= 0)
110 return 0;
111
112 /* Modifies the fds array! (sorts it) */
113
114 assert(fds)do { if ((__builtin_expect(!!(!(fds)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fds"), "../src/core/execute.c", 114, __PRETTY_FUNCTION__
); } while (0)
;
115
116 start = 0;
117 for (;;) {
118 int i;
119
120 restart_from = -1;
121
122 for (i = start; i < (int) n_fds; i++) {
123 int nfd;
124
125 /* Already at right index? */
126 if (fds[i] == i+3)
127 continue;
128
129 nfd = fcntl(fds[i], F_DUPFD0, i + 3);
130 if (nfd < 0)
131 return -errno(*__errno_location ());
132
133 safe_close(fds[i]);
134 fds[i] = nfd;
135
136 /* Hmm, the fd we wanted isn't free? Then
137 * let's remember that and try again from here */
138 if (nfd != i+3 && restart_from < 0)
139 restart_from = i;
140 }
141
142 if (restart_from < 0)
143 break;
144
145 start = restart_from;
146 }
147
148 return 0;
149}
150
151static int flags_fds(const int fds[], size_t n_socket_fds, size_t n_storage_fds, bool_Bool nonblock) {
152 size_t i, n_fds;
153 int r;
154
155 n_fds = n_socket_fds + n_storage_fds;
156 if (n_fds <= 0)
157 return 0;
158
159 assert(fds)do { if ((__builtin_expect(!!(!(fds)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fds"), "../src/core/execute.c", 159, __PRETTY_FUNCTION__
); } while (0)
;
160
161 /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags.
162 * O_NONBLOCK only applies to socket activation though. */
163
164 for (i = 0; i < n_fds; i++) {
165
166 if (i < n_socket_fds) {
167 r = fd_nonblock(fds[i], nonblock);
168 if (r < 0)
169 return r;
170 }
171
172 /* We unconditionally drop FD_CLOEXEC from the fds,
173 * since after all we want to pass these fds to our
174 * children */
175
176 r = fd_cloexec(fds[i], false0);
177 if (r < 0)
178 return r;
179 }
180
181 return 0;
182}
183
184static const char *exec_context_tty_path(const ExecContext *context) {
185 assert(context)do { if ((__builtin_expect(!!(!(context)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("context"), "../src/core/execute.c", 185
, __PRETTY_FUNCTION__); } while (0)
;
186
187 if (context->stdio_as_fds)
188 return NULL((void*)0);
189
190 if (context->tty_path)
191 return context->tty_path;
192
193 return "/dev/console";
194}
195
196static void exec_context_tty_reset(const ExecContext *context, const ExecParameters *p) {
197 const char *path;
198
199 assert(context)do { if ((__builtin_expect(!!(!(context)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("context"), "../src/core/execute.c", 199
, __PRETTY_FUNCTION__); } while (0)
;
200
201 path = exec_context_tty_path(context);
202
203 if (context->tty_vhangup) {
204 if (p && p->stdin_fd >= 0)
205 (void) terminal_vhangup_fd(p->stdin_fd);
206 else if (path)
207 (void) terminal_vhangup(path);
208 }
209
210 if (context->tty_reset) {
211 if (p && p->stdin_fd >= 0)
212 (void) reset_terminal_fd(p->stdin_fd, true1);
213 else if (path)
214 (void) reset_terminal(path);
215 }
216
217 if (context->tty_vt_disallocate && path)
218 (void) vt_disallocate(path);
219}
220
221static bool_Bool is_terminal_input(ExecInput i) {
222 return IN_SET(i,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_INPUT_TTY, EXEC_INPUT_TTY_FORCE, EXEC_INPUT_TTY_FAIL
})/sizeof(int)]; switch(i) { case EXEC_INPUT_TTY: case EXEC_INPUT_TTY_FORCE
: case EXEC_INPUT_TTY_FAIL: _found = 1; break; default: break
; } _found; })
223 EXEC_INPUT_TTY,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_INPUT_TTY, EXEC_INPUT_TTY_FORCE, EXEC_INPUT_TTY_FAIL
})/sizeof(int)]; switch(i) { case EXEC_INPUT_TTY: case EXEC_INPUT_TTY_FORCE
: case EXEC_INPUT_TTY_FAIL: _found = 1; break; default: break
; } _found; })
224 EXEC_INPUT_TTY_FORCE,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_INPUT_TTY, EXEC_INPUT_TTY_FORCE, EXEC_INPUT_TTY_FAIL
})/sizeof(int)]; switch(i) { case EXEC_INPUT_TTY: case EXEC_INPUT_TTY_FORCE
: case EXEC_INPUT_TTY_FAIL: _found = 1; break; default: break
; } _found; })
225 EXEC_INPUT_TTY_FAIL)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_INPUT_TTY, EXEC_INPUT_TTY_FORCE, EXEC_INPUT_TTY_FAIL
})/sizeof(int)]; switch(i) { case EXEC_INPUT_TTY: case EXEC_INPUT_TTY_FORCE
: case EXEC_INPUT_TTY_FAIL: _found = 1; break; default: break
; } _found; })
;
226}
227
228static bool_Bool is_terminal_output(ExecOutput o) {
229 return IN_SET(o,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_TTY, EXEC_OUTPUT_SYSLOG_AND_CONSOLE
, EXEC_OUTPUT_KMSG_AND_CONSOLE, EXEC_OUTPUT_JOURNAL_AND_CONSOLE
})/sizeof(int)]; switch(o) { case EXEC_OUTPUT_TTY: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE
: case EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
230 EXEC_OUTPUT_TTY,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_TTY, EXEC_OUTPUT_SYSLOG_AND_CONSOLE
, EXEC_OUTPUT_KMSG_AND_CONSOLE, EXEC_OUTPUT_JOURNAL_AND_CONSOLE
})/sizeof(int)]; switch(o) { case EXEC_OUTPUT_TTY: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE
: case EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
231 EXEC_OUTPUT_SYSLOG_AND_CONSOLE,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_TTY, EXEC_OUTPUT_SYSLOG_AND_CONSOLE
, EXEC_OUTPUT_KMSG_AND_CONSOLE, EXEC_OUTPUT_JOURNAL_AND_CONSOLE
})/sizeof(int)]; switch(o) { case EXEC_OUTPUT_TTY: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE
: case EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
232 EXEC_OUTPUT_KMSG_AND_CONSOLE,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_TTY, EXEC_OUTPUT_SYSLOG_AND_CONSOLE
, EXEC_OUTPUT_KMSG_AND_CONSOLE, EXEC_OUTPUT_JOURNAL_AND_CONSOLE
})/sizeof(int)]; switch(o) { case EXEC_OUTPUT_TTY: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE
: case EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
233 EXEC_OUTPUT_JOURNAL_AND_CONSOLE)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_TTY, EXEC_OUTPUT_SYSLOG_AND_CONSOLE
, EXEC_OUTPUT_KMSG_AND_CONSOLE, EXEC_OUTPUT_JOURNAL_AND_CONSOLE
})/sizeof(int)]; switch(o) { case EXEC_OUTPUT_TTY: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE
: case EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
;
234}
235
236static bool_Bool is_syslog_output(ExecOutput o) {
237 return IN_SET(o,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE
})/sizeof(int)]; switch(o) { case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
238 EXEC_OUTPUT_SYSLOG,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE
})/sizeof(int)]; switch(o) { case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
239 EXEC_OUTPUT_SYSLOG_AND_CONSOLE)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE
})/sizeof(int)]; switch(o) { case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
;
240}
241
242static bool_Bool is_kmsg_output(ExecOutput o) {
243 return IN_SET(o,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE
})/sizeof(int)]; switch(o) { case EXEC_OUTPUT_KMSG: case EXEC_OUTPUT_KMSG_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
244 EXEC_OUTPUT_KMSG,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE
})/sizeof(int)]; switch(o) { case EXEC_OUTPUT_KMSG: case EXEC_OUTPUT_KMSG_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
245 EXEC_OUTPUT_KMSG_AND_CONSOLE)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE
})/sizeof(int)]; switch(o) { case EXEC_OUTPUT_KMSG: case EXEC_OUTPUT_KMSG_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
;
246}
247
248static bool_Bool exec_context_needs_term(const ExecContext *c) {
249 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 249, __PRETTY_FUNCTION__
); } while (0)
;
250
251 /* Return true if the execution context suggests we should set $TERM to something useful. */
252
253 if (is_terminal_input(c->std_input))
254 return true1;
255
256 if (is_terminal_output(c->std_output))
257 return true1;
258
259 if (is_terminal_output(c->std_error))
260 return true1;
261
262 return !!c->tty_path;
263}
264
265static int open_null_as(int flags, int nfd) {
266 int fd;
267
268 assert(nfd >= 0)do { if ((__builtin_expect(!!(!(nfd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("nfd >= 0"), "../src/core/execute.c",
268, __PRETTY_FUNCTION__); } while (0)
;
269
270 fd = open("/dev/null", flags|O_NOCTTY0400);
271 if (fd < 0)
272 return -errno(*__errno_location ());
273
274 return move_fd(fd, nfd, false0);
275}
276
277static int connect_journal_socket(int fd, uid_t uid, gid_t gid) {
278 static const union sockaddr_union sa = {
279 .un.sun_family = AF_UNIX1,
280 .un.sun_path = "/run/systemd/journal/stdout",
281 };
282 uid_t olduid = UID_INVALID((uid_t) -1);
283 gid_t oldgid = GID_INVALID((gid_t) -1);
284 int r;
285
286 if (gid_is_valid(gid)) {
287 oldgid = getgid();
288
289 if (setegid(gid) < 0)
290 return -errno(*__errno_location ());
291 }
292
293 if (uid_is_valid(uid)) {
294 olduid = getuid();
295
296 if (seteuid(uid) < 0) {
297 r = -errno(*__errno_location ());
298 goto restore_gid;
299 }
300 }
301
302 r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)({ const struct sockaddr_un *_sa = &(sa.un); do { if ((__builtin_expect
(!!(!(_sa->sun_family == 1)),0))) log_assert_failed_realm(
LOG_REALM_SYSTEMD, ("_sa->sun_family == AF_UNIX"), "../src/core/execute.c"
, 302, __PRETTY_FUNCTION__); } while (0); __builtin_offsetof(
struct sockaddr_un, sun_path) + (_sa->sun_path[0] == 0 ? 1
+ strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : strnlen
(_sa->sun_path, sizeof(_sa->sun_path))); })
) < 0 ? -errno(*__errno_location ()) : 0;
303
304 /* If we fail to restore the uid or gid, things will likely
305 fail later on. This should only happen if an LSM interferes. */
306
307 if (uid_is_valid(uid))
308 (void) seteuid(olduid);
309
310 restore_gid:
311 if (gid_is_valid(gid))
312 (void) setegid(oldgid);
313
314 return r;
315}
316
317static int connect_logger_as(
318 const Unit *unit,
319 const ExecContext *context,
320 const ExecParameters *params,
321 ExecOutput output,
322 const char *ident,
323 int nfd,
324 uid_t uid,
325 gid_t gid) {
326
327 int fd, r;
328
329 assert(context)do { if ((__builtin_expect(!!(!(context)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("context"), "../src/core/execute.c", 329
, __PRETTY_FUNCTION__); } while (0)
;
330 assert(params)do { if ((__builtin_expect(!!(!(params)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("params"), "../src/core/execute.c", 330,
__PRETTY_FUNCTION__); } while (0)
;
331 assert(output < _EXEC_OUTPUT_MAX)do { if ((__builtin_expect(!!(!(output < _EXEC_OUTPUT_MAX)
),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("output < _EXEC_OUTPUT_MAX"
), "../src/core/execute.c", 331, __PRETTY_FUNCTION__); } while
(0)
;
332 assert(ident)do { if ((__builtin_expect(!!(!(ident)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ident"), "../src/core/execute.c", 332, __PRETTY_FUNCTION__
); } while (0)
;
333 assert(nfd >= 0)do { if ((__builtin_expect(!!(!(nfd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("nfd >= 0"), "../src/core/execute.c",
333, __PRETTY_FUNCTION__); } while (0)
;
334
335 fd = socket(AF_UNIX1, SOCK_STREAMSOCK_STREAM, 0);
336 if (fd < 0)
337 return -errno(*__errno_location ());
338
339 r = connect_journal_socket(fd, uid, gid);
340 if (r < 0)
341 return r;
342
343 if (shutdown(fd, SHUT_RDSHUT_RD) < 0) {
344 safe_close(fd);
345 return -errno(*__errno_location ());
346 }
347
348 (void) fd_inc_sndbuf(fd, SNDBUF_SIZE(8*1024*1024));
349
350 dprintf(fd,
351 "%s\n"
352 "%s\n"
353 "%i\n"
354 "%i\n"
355 "%i\n"
356 "%i\n"
357 "%i\n",
358 context->syslog_identifier ?: ident,
359 params->flags & EXEC_PASS_LOG_UNIT ? unit->id : "",
360 context->syslog_priority,
361 !!context->syslog_level_prefix,
362 is_syslog_output(output),
363 is_kmsg_output(output),
364 is_terminal_output(output));
365
366 return move_fd(fd, nfd, false0);
367}
368static int open_terminal_as(const char *path, int flags, int nfd) {
369 int fd;
370
371 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/core/execute.c", 371, __PRETTY_FUNCTION__
); } while (0)
;
372 assert(nfd >= 0)do { if ((__builtin_expect(!!(!(nfd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("nfd >= 0"), "../src/core/execute.c",
372, __PRETTY_FUNCTION__); } while (0)
;
373
374 fd = open_terminal(path, flags | O_NOCTTY0400);
375 if (fd < 0)
376 return fd;
377
378 return move_fd(fd, nfd, false0);
379}
380
381static int acquire_path(const char *path, int flags, mode_t mode) {
382 union sockaddr_union sa = {
383 .sa.sa_family = AF_UNIX1,
384 };
385 int fd, r;
386
387 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/core/execute.c", 387, __PRETTY_FUNCTION__
); } while (0)
;
388
389 if (IN_SET(flags & O_ACCMODE, O_WRONLY, O_RDWR)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){01, 02})/sizeof(int)]; switch(flags &
0003) { case 01: case 02: _found = 1; break; default: break;
} _found; })
)
390 flags |= O_CREAT0100;
391
392 fd = open(path, flags|O_NOCTTY0400, mode);
393 if (fd >= 0)
394 return fd;
395
396 if (errno(*__errno_location ()) != ENXIO6) /* ENXIO is returned when we try to open() an AF_UNIX file system socket on Linux */
397 return -errno(*__errno_location ());
398 if (strlen(path) > sizeof(sa.un.sun_path)) /* Too long, can't be a UNIX socket */
399 return -ENXIO6;
400
401 /* So, it appears the specified path could be an AF_UNIX socket. Let's see if we can connect to it. */
402
403 fd = socket(AF_UNIX1, SOCK_STREAMSOCK_STREAM, 0);
404 if (fd < 0)
405 return -errno(*__errno_location ());
406
407 strncpy(sa.un.sun_path, path, sizeof(sa.un.sun_path));
408 if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)({ const struct sockaddr_un *_sa = &(sa.un); do { if ((__builtin_expect
(!!(!(_sa->sun_family == 1)),0))) log_assert_failed_realm(
LOG_REALM_SYSTEMD, ("_sa->sun_family == AF_UNIX"), "../src/core/execute.c"
, 408, __PRETTY_FUNCTION__); } while (0); __builtin_offsetof(
struct sockaddr_un, sun_path) + (_sa->sun_path[0] == 0 ? 1
+ strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : strnlen
(_sa->sun_path, sizeof(_sa->sun_path))); })
) < 0) {
409 safe_close(fd);
410 return errno(*__errno_location ()) == EINVAL22 ? -ENXIO6 : -errno(*__errno_location ()); /* Propagate initial error if we get EINVAL, i.e. we have
411 * indication that his wasn't an AF_UNIX socket after all */
412 }
413
414 if ((flags & O_ACCMODE0003) == O_RDONLY00)
415 r = shutdown(fd, SHUT_WRSHUT_WR);
416 else if ((flags & O_ACCMODE0003) == O_WRONLY01)
417 r = shutdown(fd, SHUT_RDSHUT_RD);
418 else
419 return fd;
420 if (r < 0) {
421 safe_close(fd);
422 return -errno(*__errno_location ());
423 }
424
425 return fd;
426}
427
428static int fixup_input(
429 const ExecContext *context,
430 int socket_fd,
431 bool_Bool apply_tty_stdin) {
432
433 ExecInput std_input;
434
435 assert(context)do { if ((__builtin_expect(!!(!(context)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("context"), "../src/core/execute.c", 435
, __PRETTY_FUNCTION__); } while (0)
;
436
437 std_input = context->std_input;
438
439 if (is_terminal_input(std_input) && !apply_tty_stdin)
440 return EXEC_INPUT_NULL;
441
442 if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0)
443 return EXEC_INPUT_NULL;
444
445 if (std_input == EXEC_INPUT_DATA && context->stdin_data_size == 0)
446 return EXEC_INPUT_NULL;
447
448 return std_input;
449}
450
451static int fixup_output(ExecOutput std_output, int socket_fd) {
452
453 if (std_output == EXEC_OUTPUT_SOCKET && socket_fd < 0)
454 return EXEC_OUTPUT_INHERIT;
455
456 return std_output;
457}
458
459static int setup_input(
460 const ExecContext *context,
461 const ExecParameters *params,
462 int socket_fd,
463 int named_iofds[3]) {
464
465 ExecInput i;
466
467 assert(context)do { if ((__builtin_expect(!!(!(context)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("context"), "../src/core/execute.c", 467
, __PRETTY_FUNCTION__); } while (0)
;
468 assert(params)do { if ((__builtin_expect(!!(!(params)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("params"), "../src/core/execute.c", 468,
__PRETTY_FUNCTION__); } while (0)
;
469
470 if (params->stdin_fd >= 0) {
471 if (dup2(params->stdin_fd, STDIN_FILENO0) < 0)
472 return -errno(*__errno_location ());
473
474 /* Try to make this the controlling tty, if it is a tty, and reset it */
475 if (isatty(STDIN_FILENO0)) {
476 (void) ioctl(STDIN_FILENO0, TIOCSCTTY0x540E, context->std_input == EXEC_INPUT_TTY_FORCE);
477 (void) reset_terminal_fd(STDIN_FILENO0, true1);
478 }
479
480 return STDIN_FILENO0;
481 }
482
483 i = fixup_input(context, socket_fd, params->flags & EXEC_APPLY_TTY_STDIN);
484
485 switch (i) {
486
487 case EXEC_INPUT_NULL:
488 return open_null_as(O_RDONLY00, STDIN_FILENO0);
489
490 case EXEC_INPUT_TTY:
491 case EXEC_INPUT_TTY_FORCE:
492 case EXEC_INPUT_TTY_FAIL: {
493 int fd;
494
495 fd = acquire_terminal(exec_context_tty_path(context),
496 i == EXEC_INPUT_TTY_FAIL ? ACQUIRE_TERMINAL_TRY :
497 i == EXEC_INPUT_TTY_FORCE ? ACQUIRE_TERMINAL_FORCE :
498 ACQUIRE_TERMINAL_WAIT,
499 USEC_INFINITY((usec_t) -1));
500 if (fd < 0)
501 return fd;
502
503 return move_fd(fd, STDIN_FILENO0, false0);
504 }
505
506 case EXEC_INPUT_SOCKET:
507 assert(socket_fd >= 0)do { if ((__builtin_expect(!!(!(socket_fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("socket_fd >= 0"), "../src/core/execute.c"
, 507, __PRETTY_FUNCTION__); } while (0)
;
508
509 return dup2(socket_fd, STDIN_FILENO0) < 0 ? -errno(*__errno_location ()) : STDIN_FILENO0;
510
511 case EXEC_INPUT_NAMED_FD:
512 assert(named_iofds[STDIN_FILENO] >= 0)do { if ((__builtin_expect(!!(!(named_iofds[0] >= 0)),0)))
log_assert_failed_realm(LOG_REALM_SYSTEMD, ("named_iofds[STDIN_FILENO] >= 0"
), "../src/core/execute.c", 512, __PRETTY_FUNCTION__); } while
(0)
;
513
514 (void) fd_nonblock(named_iofds[STDIN_FILENO0], false0);
515 return dup2(named_iofds[STDIN_FILENO0], STDIN_FILENO0) < 0 ? -errno(*__errno_location ()) : STDIN_FILENO0;
516
517 case EXEC_INPUT_DATA: {
518 int fd;
519
520 fd = acquire_data_fd(context->stdin_data, context->stdin_data_size, 0);
521 if (fd < 0)
522 return fd;
523
524 return move_fd(fd, STDIN_FILENO0, false0);
525 }
526
527 case EXEC_INPUT_FILE: {
528 bool_Bool rw;
529 int fd;
530
531 assert(context->stdio_file[STDIN_FILENO])do { if ((__builtin_expect(!!(!(context->stdio_file[0])),0
))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("context->stdio_file[STDIN_FILENO]"
), "../src/core/execute.c", 531, __PRETTY_FUNCTION__); } while
(0)
;
532
533 rw = (context->std_output == EXEC_OUTPUT_FILE && streq_ptr(context->stdio_file[STDIN_FILENO0], context->stdio_file[STDOUT_FILENO1])) ||
534 (context->std_error == EXEC_OUTPUT_FILE && streq_ptr(context->stdio_file[STDIN_FILENO0], context->stdio_file[STDERR_FILENO2]));
535
536 fd = acquire_path(context->stdio_file[STDIN_FILENO0], rw ? O_RDWR02 : O_RDONLY00, 0666 & ~context->umask);
537 if (fd < 0)
538 return fd;
539
540 return move_fd(fd, STDIN_FILENO0, false0);
541 }
542
543 default:
544 assert_not_reached("Unknown input type")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, (
"Unknown input type"), "../src/core/execute.c", 544, __PRETTY_FUNCTION__
); } while (0)
;
545 }
546}
547
548static int setup_output(
549 const Unit *unit,
550 const ExecContext *context,
551 const ExecParameters *params,
552 int fileno,
553 int socket_fd,
554 int named_iofds[3],
555 const char *ident,
556 uid_t uid,
557 gid_t gid,
558 dev_t *journal_stream_dev,
559 ino_t *journal_stream_ino) {
560
561 ExecOutput o;
562 ExecInput i;
563 int r;
564
565 assert(unit)do { if ((__builtin_expect(!!(!(unit)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("unit"), "../src/core/execute.c", 565, __PRETTY_FUNCTION__
); } while (0)
;
566 assert(context)do { if ((__builtin_expect(!!(!(context)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("context"), "../src/core/execute.c", 566
, __PRETTY_FUNCTION__); } while (0)
;
567 assert(params)do { if ((__builtin_expect(!!(!(params)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("params"), "../src/core/execute.c", 567,
__PRETTY_FUNCTION__); } while (0)
;
568 assert(ident)do { if ((__builtin_expect(!!(!(ident)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ident"), "../src/core/execute.c", 568, __PRETTY_FUNCTION__
); } while (0)
;
569 assert(journal_stream_dev)do { if ((__builtin_expect(!!(!(journal_stream_dev)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("journal_stream_dev"), "../src/core/execute.c"
, 569, __PRETTY_FUNCTION__); } while (0)
;
570 assert(journal_stream_ino)do { if ((__builtin_expect(!!(!(journal_stream_ino)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("journal_stream_ino"), "../src/core/execute.c"
, 570, __PRETTY_FUNCTION__); } while (0)
;
571
572 if (fileno == STDOUT_FILENO1 && params->stdout_fd >= 0) {
573
574 if (dup2(params->stdout_fd, STDOUT_FILENO1) < 0)
575 return -errno(*__errno_location ());
576
577 return STDOUT_FILENO1;
578 }
579
580 if (fileno == STDERR_FILENO2 && params->stderr_fd >= 0) {
581 if (dup2(params->stderr_fd, STDERR_FILENO2) < 0)
582 return -errno(*__errno_location ());
583
584 return STDERR_FILENO2;
585 }
586
587 i = fixup_input(context, socket_fd, params->flags & EXEC_APPLY_TTY_STDIN);
588 o = fixup_output(context->std_output, socket_fd);
589
590 if (fileno == STDERR_FILENO2) {
591 ExecOutput e;
592 e = fixup_output(context->std_error, socket_fd);
593
594 /* This expects the input and output are already set up */
595
596 /* Don't change the stderr file descriptor if we inherit all
597 * the way and are not on a tty */
598 if (e == EXEC_OUTPUT_INHERIT &&
599 o == EXEC_OUTPUT_INHERIT &&
600 i == EXEC_INPUT_NULL &&
601 !is_terminal_input(context->std_input) &&
602 getppid () != 1)
603 return fileno;
604
605 /* Duplicate from stdout if possible */
606 if ((e == o && e != EXEC_OUTPUT_NAMED_FD) || e == EXEC_OUTPUT_INHERIT)
607 return dup2(STDOUT_FILENO1, fileno) < 0 ? -errno(*__errno_location ()) : fileno;
608
609 o = e;
610
611 } else if (o == EXEC_OUTPUT_INHERIT) {
612 /* If input got downgraded, inherit the original value */
613 if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input))
614 return open_terminal_as(exec_context_tty_path(context), O_WRONLY01, fileno);
615
616 /* If the input is connected to anything that's not a /dev/null or a data fd, inherit that... */
617 if (!IN_SET(i, EXEC_INPUT_NULL, EXEC_INPUT_DATA)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_INPUT_NULL, EXEC_INPUT_DATA})/sizeof
(int)]; switch(i) { case EXEC_INPUT_NULL: case EXEC_INPUT_DATA
: _found = 1; break; default: break; } _found; })
)
618 return dup2(STDIN_FILENO0, fileno) < 0 ? -errno(*__errno_location ()) : fileno;
619
620 /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */
621 if (getppid() != 1)
622 return fileno;
623
624 /* We need to open /dev/null here anew, to get the right access mode. */
625 return open_null_as(O_WRONLY01, fileno);
626 }
627
628 switch (o) {
629
630 case EXEC_OUTPUT_NULL:
631 return open_null_as(O_WRONLY01, fileno);
632
633 case EXEC_OUTPUT_TTY:
634 if (is_terminal_input(i))
635 return dup2(STDIN_FILENO0, fileno) < 0 ? -errno(*__errno_location ()) : fileno;
636
637 /* We don't reset the terminal if this is just about output */
638 return open_terminal_as(exec_context_tty_path(context), O_WRONLY01, fileno);
639
640 case EXEC_OUTPUT_SYSLOG:
641 case EXEC_OUTPUT_SYSLOG_AND_CONSOLE:
642 case EXEC_OUTPUT_KMSG:
643 case EXEC_OUTPUT_KMSG_AND_CONSOLE:
644 case EXEC_OUTPUT_JOURNAL:
645 case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
646 r = connect_logger_as(unit, context, params, o, ident, fileno, uid, gid);
647 if (r < 0) {
648 log_unit_warning_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m", fileno == STDOUT_FILENO ? "stdout" : "stderr")({ const Unit *_u = (unit); _u ? log_object_internal(4, r, "../src/core/execute.c"
, 648, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to connect %s to the journal socket, ignoring: %m",
fileno == 1 ? "stdout" : "stderr") : log_internal_realm(((LOG_REALM_SYSTEMD
) << 10 | ((4))), r, "../src/core/execute.c", 648, __func__
, "Failed to connect %s to the journal socket, ignoring: %m",
fileno == 1 ? "stdout" : "stderr"); })
;
649 r = open_null_as(O_WRONLY01, fileno);
650 } else {
651 struct stat st;
652
653 /* If we connected this fd to the journal via a stream, patch the device/inode into the passed
654 * parameters, but only then. This is useful so that we can set $JOURNAL_STREAM that permits
655 * services to detect whether they are connected to the journal or not.
656 *
657 * If both stdout and stderr are connected to a stream then let's make sure to store the data
658 * about STDERR as that's usually the best way to do logging. */
659
660 if (fstat(fileno, &st) >= 0 &&
661 (*journal_stream_ino == 0 || fileno == STDERR_FILENO2)) {
662 *journal_stream_dev = st.st_dev;
663 *journal_stream_ino = st.st_ino;
664 }
665 }
666 return r;
667
668 case EXEC_OUTPUT_SOCKET:
669 assert(socket_fd >= 0)do { if ((__builtin_expect(!!(!(socket_fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("socket_fd >= 0"), "../src/core/execute.c"
, 669, __PRETTY_FUNCTION__); } while (0)
;
670
671 return dup2(socket_fd, fileno) < 0 ? -errno(*__errno_location ()) : fileno;
672
673 case EXEC_OUTPUT_NAMED_FD:
674 assert(named_iofds[fileno] >= 0)do { if ((__builtin_expect(!!(!(named_iofds[fileno] >= 0))
,0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("named_iofds[fileno] >= 0"
), "../src/core/execute.c", 674, __PRETTY_FUNCTION__); } while
(0)
;
675
676 (void) fd_nonblock(named_iofds[fileno], false0);
677 return dup2(named_iofds[fileno], fileno) < 0 ? -errno(*__errno_location ()) : fileno;
678
679 case EXEC_OUTPUT_FILE:
680 case EXEC_OUTPUT_FILE_APPEND: {
681 bool_Bool rw;
682 int fd, flags;
683
684 assert(context->stdio_file[fileno])do { if ((__builtin_expect(!!(!(context->stdio_file[fileno
])),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("context->stdio_file[fileno]"
), "../src/core/execute.c", 684, __PRETTY_FUNCTION__); } while
(0)
;
685
686 rw = context->std_input == EXEC_INPUT_FILE &&
687 streq_ptr(context->stdio_file[fileno], context->stdio_file[STDIN_FILENO0]);
688
689 if (rw)
690 return dup2(STDIN_FILENO0, fileno) < 0 ? -errno(*__errno_location ()) : fileno;
691
692 flags = O_WRONLY01;
693 if (o == EXEC_OUTPUT_FILE_APPEND)
694 flags |= O_APPEND02000;
695
696 fd = acquire_path(context->stdio_file[fileno], flags, 0666 & ~context->umask);
697
698 if (fd < 0)
699 return fd;
700
701 return move_fd(fd, fileno, 0);
702 }
703
704 default:
705 assert_not_reached("Unknown error type")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, (
"Unknown error type"), "../src/core/execute.c", 705, __PRETTY_FUNCTION__
); } while (0)
;
706 }
707}
708
709static int chown_terminal(int fd, uid_t uid) {
710 struct stat st;
711
712 assert(fd >= 0)do { if ((__builtin_expect(!!(!(fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fd >= 0"), "../src/core/execute.c", 712
, __PRETTY_FUNCTION__); } while (0)
;
713
714 /* Before we chown/chmod the TTY, let's ensure this is actually a tty */
715 if (isatty(fd) < 1)
716 return 0;
717
718 /* This might fail. What matters are the results. */
719 (void) fchown(fd, uid, -1);
720 (void) fchmod(fd, TTY_MODE0620);
721
722 if (fstat(fd, &st) < 0)
723 return -errno(*__errno_location ());
724
725 if (st.st_uid != uid || (st.st_mode & 0777) != TTY_MODE0620)
726 return -EPERM1;
727
728 return 0;
729}
730
731static int setup_confirm_stdio(const char *vc, int *_saved_stdin, int *_saved_stdout) {
732 _cleanup_close___attribute__((cleanup(closep))) int fd = -1, saved_stdin = -1, saved_stdout = -1;
733 int r;
734
735 assert(_saved_stdin)do { if ((__builtin_expect(!!(!(_saved_stdin)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("_saved_stdin"), "../src/core/execute.c"
, 735, __PRETTY_FUNCTION__); } while (0)
;
736 assert(_saved_stdout)do { if ((__builtin_expect(!!(!(_saved_stdout)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("_saved_stdout"), "../src/core/execute.c"
, 736, __PRETTY_FUNCTION__); } while (0)
;
737
738 saved_stdin = fcntl(STDIN_FILENO0, F_DUPFD0, 3);
739 if (saved_stdin < 0)
740 return -errno(*__errno_location ());
741
742 saved_stdout = fcntl(STDOUT_FILENO1, F_DUPFD0, 3);
743 if (saved_stdout < 0)
744 return -errno(*__errno_location ());
745
746 fd = acquire_terminal(vc, ACQUIRE_TERMINAL_WAIT, DEFAULT_CONFIRM_USEC(30*((usec_t) 1000000ULL)));
747 if (fd < 0)
748 return fd;
749
750 r = chown_terminal(fd, getuid());
751 if (r < 0)
752 return r;
753
754 r = reset_terminal_fd(fd, true1);
755 if (r < 0)
756 return r;
757
758 r = rearrange_stdio(fd, fd, STDERR_FILENO2);
759 fd = -1;
760 if (r < 0)
761 return r;
762
763 *_saved_stdin = saved_stdin;
764 *_saved_stdout = saved_stdout;
765
766 saved_stdin = saved_stdout = -1;
767
768 return 0;
769}
770
771static void write_confirm_error_fd(int err, int fd, const Unit *u) {
772 assert(err < 0)do { if ((__builtin_expect(!!(!(err < 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("err < 0"), "../src/core/execute.c", 772
, __PRETTY_FUNCTION__); } while (0)
;
773
774 if (err == -ETIMEDOUT110)
775 dprintf(fd, "Confirmation question timed out for %s, assuming positive response.\n", u->id);
776 else {
777 errno(*__errno_location ()) = -err;
778 dprintf(fd, "Couldn't ask confirmation for %s: %m, assuming positive response.\n", u->id);
779 }
780}
781
782static void write_confirm_error(int err, const char *vc, const Unit *u) {
783 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
784
785 assert(vc)do { if ((__builtin_expect(!!(!(vc)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("vc"), "../src/core/execute.c", 785, __PRETTY_FUNCTION__
); } while (0)
;
786
787 fd = open_terminal(vc, O_WRONLY01|O_NOCTTY0400|O_CLOEXEC02000000);
788 if (fd < 0)
789 return;
790
791 write_confirm_error_fd(err, fd, u);
792}
793
794static int restore_confirm_stdio(int *saved_stdin, int *saved_stdout) {
795 int r = 0;
796
797 assert(saved_stdin)do { if ((__builtin_expect(!!(!(saved_stdin)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("saved_stdin"), "../src/core/execute.c",
797, __PRETTY_FUNCTION__); } while (0)
;
798 assert(saved_stdout)do { if ((__builtin_expect(!!(!(saved_stdout)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("saved_stdout"), "../src/core/execute.c"
, 798, __PRETTY_FUNCTION__); } while (0)
;
799
800 release_terminal();
801
802 if (*saved_stdin >= 0)
803 if (dup2(*saved_stdin, STDIN_FILENO0) < 0)
804 r = -errno(*__errno_location ());
805
806 if (*saved_stdout >= 0)
807 if (dup2(*saved_stdout, STDOUT_FILENO1) < 0)
808 r = -errno(*__errno_location ());
809
810 *saved_stdin = safe_close(*saved_stdin);
811 *saved_stdout = safe_close(*saved_stdout);
812
813 return r;
814}
815
816enum {
817 CONFIRM_PRETEND_FAILURE = -1,
818 CONFIRM_PRETEND_SUCCESS = 0,
819 CONFIRM_EXECUTE = 1,
820};
821
822static int ask_for_confirmation(const char *vc, Unit *u, const char *cmdline) {
823 int saved_stdout = -1, saved_stdin = -1, r;
824 _cleanup_free___attribute__((cleanup(freep))) char *e = NULL((void*)0);
825 char c;
826
827 /* For any internal errors, assume a positive response. */
828 r = setup_confirm_stdio(vc, &saved_stdin, &saved_stdout);
829 if (r < 0) {
830 write_confirm_error(r, vc, u);
831 return CONFIRM_EXECUTE;
832 }
833
834 /* confirm_spawn might have been disabled while we were sleeping. */
835 if (manager_is_confirm_spawn_disabled(u->manager)) {
836 r = 1;
837 goto restore_stdio;
838 }
839
840 e = ellipsize(cmdline, 60, 100);
841 if (!e) {
842 log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/core/execute.c", 842
, __func__)
;
843 r = CONFIRM_EXECUTE;
844 goto restore_stdio;
845 }
846
847 for (;;) {
848 r = ask_char(&c, "yfshiDjcn", "Execute %s? [y, f, s – h for help] ", e);
849 if (r < 0) {
850 write_confirm_error_fd(r, STDOUT_FILENO1, u);
851 r = CONFIRM_EXECUTE;
852 goto restore_stdio;
853 }
854
855 switch (c) {
856 case 'c':
857 printf("Resuming normal execution.\n");
858 manager_disable_confirm_spawn();
859 r = 1;
860 break;
861 case 'D':
862 unit_dump(u, stdoutstdout, " ");
863 continue; /* ask again */
864 case 'f':
865 printf("Failing execution.\n");
866 r = CONFIRM_PRETEND_FAILURE;
867 break;
868 case 'h':
869 printf(" c - continue, proceed without asking anymore\n"
870 " D - dump, show the state of the unit\n"
871 " f - fail, don't execute the command and pretend it failed\n"
872 " h - help\n"
873 " i - info, show a short summary of the unit\n"
874 " j - jobs, show jobs that are in progress\n"
875 " s - skip, don't execute the command and pretend it succeeded\n"
876 " y - yes, execute the command\n");
877 continue; /* ask again */
878 case 'i':
879 printf(" Description: %s\n"
880 " Unit: %s\n"
881 " Command: %s\n",
882 u->id, u->description, cmdline);
883 continue; /* ask again */
884 case 'j':
885 manager_dump_jobs(u->manager, stdoutstdout, " ");
886 continue; /* ask again */
887 case 'n':
888 /* 'n' was removed in favor of 'f'. */
889 printf("Didn't understand 'n', did you mean 'f'?\n");
890 continue; /* ask again */
891 case 's':
892 printf("Skipping execution.\n");
893 r = CONFIRM_PRETEND_SUCCESS;
894 break;
895 case 'y':
896 r = CONFIRM_EXECUTE;
897 break;
898 default:
899 assert_not_reached("Unhandled choice")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, (
"Unhandled choice"), "../src/core/execute.c", 899, __PRETTY_FUNCTION__
); } while (0)
;
900 }
901 break;
902 }
903
904restore_stdio:
905 restore_confirm_stdio(&saved_stdin, &saved_stdout);
906 return r;
907}
908
909static int get_fixed_user(const ExecContext *c, const char **user,
910 uid_t *uid, gid_t *gid,
911 const char **home, const char **shell) {
912 int r;
913 const char *name;
914
915 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 915, __PRETTY_FUNCTION__
); } while (0)
;
916
917 if (!c->user)
918 return 0;
919
920 /* Note that we don't set $HOME or $SHELL if they are not particularly enlightening anyway
921 * (i.e. are "/" or "/bin/nologin"). */
922
923 name = c->user;
924 r = get_user_creds_clean(&name, uid, gid, home, shell);
925 if (r < 0)
926 return r;
927
928 *user = name;
929 return 0;
930}
931
932static int get_fixed_group(const ExecContext *c, const char **group, gid_t *gid) {
933 int r;
934 const char *name;
935
936 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 936, __PRETTY_FUNCTION__
); } while (0)
;
937
938 if (!c->group)
939 return 0;
940
941 name = c->group;
942 r = get_group_creds(&name, gid);
943 if (r < 0)
944 return r;
945
946 *group = name;
947 return 0;
948}
949
950static int get_supplementary_groups(const ExecContext *c, const char *user,
951 const char *group, gid_t gid,
952 gid_t **supplementary_gids, int *ngids) {
953 char **i;
954 int r, k = 0;
955 int ngroups_max;
956 bool_Bool keep_groups = false0;
957 gid_t *groups = NULL((void*)0);
958 _cleanup_free___attribute__((cleanup(freep))) gid_t *l_gids = NULL((void*)0);
959
960 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 960, __PRETTY_FUNCTION__
); } while (0)
;
961
962 /*
963 * If user is given, then lookup GID and supplementary groups list.
964 * We avoid NSS lookups for gid=0. Also we have to initialize groups
965 * here and as early as possible so we keep the list of supplementary
966 * groups of the caller.
967 */
968 if (user && gid_is_valid(gid) && gid != 0) {
969 /* First step, initialize groups from /etc/groups */
970 if (initgroups(user, gid) < 0)
971 return -errno(*__errno_location ());
972
973 keep_groups = true1;
974 }
975
976 if (strv_isempty(c->supplementary_groups))
977 return 0;
978
979 /*
980 * If SupplementaryGroups= was passed then NGROUPS_MAX has to
981 * be positive, otherwise fail.
982 */
983 errno(*__errno_location ()) = 0;
984 ngroups_max = (int) sysconf(_SC_NGROUPS_MAX_SC_NGROUPS_MAX);
985 if (ngroups_max <= 0) {
986 if (errno(*__errno_location ()) > 0)
987 return -errno(*__errno_location ());
988 else
989 return -EOPNOTSUPP95; /* For all other values */
990 }
991
992 l_gids = new(gid_t, ngroups_max)((gid_t*) malloc_multiply(sizeof(gid_t), (ngroups_max)));
993 if (!l_gids)
994 return -ENOMEM12;
995
996 if (keep_groups) {
997 /*
998 * Lookup the list of groups that the user belongs to, we
999 * avoid NSS lookups here too for gid=0.
1000 */
1001 k = ngroups_max;
1002 if (getgrouplist(user, gid, l_gids, &k) < 0)
1003 return -EINVAL22;
1004 } else
1005 k = 0;
1006
1007 STRV_FOREACH(i, c->supplementary_groups)for ((i) = (c->supplementary_groups); (i) && *(i);
(i)++)
{
1008 const char *g;
1009
1010 if (k >= ngroups_max)
1011 return -E2BIG7;
1012
1013 g = *i;
1014 r = get_group_creds(&g, l_gids+k);
1015 if (r < 0)
1016 return r;
1017
1018 k++;
1019 }
1020
1021 /*
1022 * Sets ngids to zero to drop all supplementary groups, happens
1023 * when we are under root and SupplementaryGroups= is empty.
1024 */
1025 if (k == 0) {
1026 *ngids = 0;
1027 return 0;
1028 }
1029
1030 /* Otherwise get the final list of supplementary groups */
1031 groups = memdup(l_gids, sizeof(gid_t) * k);
1032 if (!groups)
1033 return -ENOMEM12;
1034
1035 *supplementary_gids = groups;
1036 *ngids = k;
1037
1038 groups = NULL((void*)0);
1039
1040 return 0;
1041}
1042
1043static int enforce_groups(gid_t gid, const gid_t *supplementary_gids, int ngids) {
1044 int r;
1045
1046 /* Handle SupplementaryGroups= if it is not empty */
1047 if (ngids > 0) {
1048 r = maybe_setgroups(ngids, supplementary_gids);
1049 if (r < 0)
1050 return r;
1051 }
1052
1053 if (gid_is_valid(gid)) {
1054 /* Then set our gids */
1055 if (setresgid(gid, gid, gid) < 0)
1056 return -errno(*__errno_location ());
1057 }
1058
1059 return 0;
1060}
1061
1062static int enforce_user(const ExecContext *context, uid_t uid) {
1063 assert(context)do { if ((__builtin_expect(!!(!(context)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("context"), "../src/core/execute.c", 1063
, __PRETTY_FUNCTION__); } while (0)
;
1064
1065 if (!uid_is_valid(uid))
1066 return 0;
1067
1068 /* Sets (but doesn't look up) the uid and make sure we keep the
1069 * capabilities while doing so. */
1070
1071 if (context->capability_ambient_set != 0) {
1072
1073 /* First step: If we need to keep capabilities but
1074 * drop privileges we need to make sure we keep our
1075 * caps, while we drop privileges. */
1076 if (uid != 0) {
1077 int sb = context->secure_bits | 1<<SECURE_KEEP_CAPS4;
1078
1079 if (prctl(PR_GET_SECUREBITS27) != sb)
1080 if (prctl(PR_SET_SECUREBITS28, sb) < 0)
1081 return -errno(*__errno_location ());
1082 }
1083 }
1084
1085 /* Second step: actually set the uids */
1086 if (setresuid(uid, uid, uid) < 0)
1087 return -errno(*__errno_location ());
1088
1089 /* At this point we should have all necessary capabilities but
1090 are otherwise a normal user. However, the caps might got
1091 corrupted due to the setresuid() so we need clean them up
1092 later. This is done outside of this call. */
1093
1094 return 0;
1095}
1096
1097#if HAVE_PAM1
1098
1099static int null_conv(
1100 int num_msg,
1101 const struct pam_message **msg,
1102 struct pam_response **resp,
1103 void *appdata_ptr) {
1104
1105 /* We don't support conversations */
1106
1107 return PAM_CONV_ERR19;
1108}
1109
1110#endif
1111
1112static int setup_pam(
1113 const char *name,
1114 const char *user,
1115 uid_t uid,
1116 gid_t gid,
1117 const char *tty,
1118 char ***env,
1119 int fds[], size_t n_fds) {
1120
1121#if HAVE_PAM1
1122
1123 static const struct pam_conv conv = {
1124 .conv = null_conv,
1125 .appdata_ptr = NULL((void*)0)
1126 };
1127
1128 _cleanup_(barrier_destroy)__attribute__((cleanup(barrier_destroy))) Barrier barrier = BARRIER_NULL{-1, -1, {-1, -1}, 0};
1129 pam_handle_t *handle = NULL((void*)0);
1130 sigset_t old_ss;
1131 int pam_code = PAM_SUCCESS0, r;
1132 char **nv, **e = NULL((void*)0);
1133 bool_Bool close_session = false0;
1134 pid_t pam_pid = 0, parent_pid;
1135 int flags = 0;
1136
1137 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/core/execute.c", 1137, __PRETTY_FUNCTION__
); } while (0)
;
1138 assert(user)do { if ((__builtin_expect(!!(!(user)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("user"), "../src/core/execute.c", 1138, __PRETTY_FUNCTION__
); } while (0)
;
1139 assert(env)do { if ((__builtin_expect(!!(!(env)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("env"), "../src/core/execute.c", 1139, __PRETTY_FUNCTION__
); } while (0)
;
1140
1141 /* We set up PAM in the parent process, then fork. The child
1142 * will then stay around until killed via PR_GET_PDEATHSIG or
1143 * systemd via the cgroup logic. It will then remove the PAM
1144 * session again. The parent process will exec() the actual
1145 * daemon. We do things this way to ensure that the main PID
1146 * of the daemon is the one we initially fork()ed. */
1147
1148 r = barrier_create(&barrier);
1149 if (r < 0)
1150 goto fail;
1151
1152 if (log_get_max_level()log_get_max_level_realm(LOG_REALM_SYSTEMD) < LOG_DEBUG7)
1153 flags |= PAM_SILENT0x8000U;
1154
1155 pam_code = pam_start(name, user, &conv, &handle);
1156 if (pam_code != PAM_SUCCESS0) {
1157 handle = NULL((void*)0);
1158 goto fail;
1159 }
1160
1161 if (tty) {
1162 pam_code = pam_set_item(handle, PAM_TTY3, tty);
1163 if (pam_code != PAM_SUCCESS0)
1164 goto fail;
1165 }
1166
1167 STRV_FOREACH(nv, *env)for ((nv) = (*env); (nv) && *(nv); (nv)++) {
1168 pam_code = pam_putenv(handle, *nv);
1169 if (pam_code != PAM_SUCCESS0)
1170 goto fail;
1171 }
1172
1173 pam_code = pam_acct_mgmt(handle, flags);
1174 if (pam_code != PAM_SUCCESS0)
1175 goto fail;
1176
1177 pam_code = pam_open_session(handle, flags);
1178 if (pam_code != PAM_SUCCESS0)
1179 goto fail;
1180
1181 close_session = true1;
1182
1183 e = pam_getenvlist(handle);
1184 if (!e) {
1185 pam_code = PAM_BUF_ERR5;
1186 goto fail;
1187 }
1188
1189 /* Block SIGTERM, so that we know that it won't get lost in
1190 * the child */
1191
1192 assert_se(sigprocmask_many(SIG_BLOCK, &old_ss, SIGTERM, -1) >= 0)do { if ((__builtin_expect(!!(!(sigprocmask_many(0, &old_ss
, 15, -1) >= 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("sigprocmask_many(SIG_BLOCK, &old_ss, SIGTERM, -1) >= 0"
), "../src/core/execute.c", 1192, __PRETTY_FUNCTION__); } while
(0)
;
1193
1194 parent_pid = getpid_cached();
1195
1196 r = safe_fork("(sd-pam)", 0, &pam_pid);
1197 if (r < 0)
1198 goto fail;
1199 if (r == 0) {
1200 int sig, ret = EXIT_PAM;
1201
1202 /* The child's job is to reset the PAM session on
1203 * termination */
1204 barrier_set_role(&barrier, BARRIER_CHILD);
1205
1206 /* Make sure we don't keep open the passed fds in this child. We assume that otherwise only those fds
1207 * are open here that have been opened by PAM. */
1208 (void) close_many(fds, n_fds);
1209
1210 /* Drop privileges - we don't need any to pam_close_session
1211 * and this will make PR_SET_PDEATHSIG work in most cases.
1212 * If this fails, ignore the error - but expect sd-pam threads
1213 * to fail to exit normally */
1214
1215 r = maybe_setgroups(0, NULL((void*)0));
1216 if (r < 0)
1217 log_warning_errno(r, "Failed to setgroups() in sd-pam: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/core/execute.c", 1217, __func__, "Failed to setgroups() in sd-pam: %m"
) : -abs(_e); })
;
1218 if (setresgid(gid, gid, gid) < 0)
1219 log_warning_errno(errno, "Failed to setresgid() in sd-pam: %m")({ int _level = ((4)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/core/execute.c", 1219, __func__,
"Failed to setresgid() in sd-pam: %m") : -abs(_e); })
;
1220 if (setresuid(uid, uid, uid) < 0)
1221 log_warning_errno(errno, "Failed to setresuid() in sd-pam: %m")({ int _level = ((4)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/core/execute.c", 1221, __func__,
"Failed to setresuid() in sd-pam: %m") : -abs(_e); })
;
1222
1223 (void) ignore_signals(SIGPIPE13, -1);
1224
1225 /* Wait until our parent died. This will only work if
1226 * the above setresuid() succeeds, otherwise the kernel
1227 * will not allow unprivileged parents kill their privileged
1228 * children this way. We rely on the control groups kill logic
1229 * to do the rest for us. */
1230 if (prctl(PR_SET_PDEATHSIG1, SIGTERM15) < 0)
1231 goto child_finish;
1232
1233 /* Tell the parent that our setup is done. This is especially
1234 * important regarding dropping privileges. Otherwise, unit
1235 * setup might race against our setresuid(2) call.
1236 *
1237 * If the parent aborted, we'll detect this below, hence ignore
1238 * return failure here. */
1239 (void) barrier_place(&barrier);
1240
1241 /* Check if our parent process might already have died? */
1242 if (getppid() == parent_pid) {
1243 sigset_t ss;
1244
1245 assert_se(sigemptyset(&ss) >= 0)do { if ((__builtin_expect(!!(!(sigemptyset(&ss) >= 0)
),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("sigemptyset(&ss) >= 0"
), "../src/core/execute.c", 1245, __PRETTY_FUNCTION__); } while
(0)
;
1246 assert_se(sigaddset(&ss, SIGTERM) >= 0)do { if ((__builtin_expect(!!(!(sigaddset(&ss, 15) >= 0
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("sigaddset(&ss, SIGTERM) >= 0"
), "../src/core/execute.c", 1246, __PRETTY_FUNCTION__); } while
(0)
;
1247
1248 for (;;) {
1249 if (sigwait(&ss, &sig) < 0) {
1250 if (errno(*__errno_location ()) == EINTR4)
1251 continue;
1252
1253 goto child_finish;
1254 }
1255
1256 assert(sig == SIGTERM)do { if ((__builtin_expect(!!(!(sig == 15)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("sig == SIGTERM"), "../src/core/execute.c"
, 1256, __PRETTY_FUNCTION__); } while (0)
;
1257 break;
1258 }
1259 }
1260
1261 /* If our parent died we'll end the session */
1262 if (getppid() != parent_pid) {
1263 pam_code = pam_close_session(handle, flags);
1264 if (pam_code != PAM_SUCCESS0)
1265 goto child_finish;
1266 }
1267
1268 ret = 0;
1269
1270 child_finish:
1271 pam_end(handle, pam_code | flags);
1272 _exit(ret);
1273 }
1274
1275 barrier_set_role(&barrier, BARRIER_PARENT);
1276
1277 /* If the child was forked off successfully it will do all the
1278 * cleanups, so forget about the handle here. */
1279 handle = NULL((void*)0);
1280
1281 /* Unblock SIGTERM again in the parent */
1282 assert_se(sigprocmask(SIG_SETMASK, &old_ss, NULL) >= 0)do { if ((__builtin_expect(!!(!(sigprocmask(2, &old_ss, (
(void*)0)) >= 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("sigprocmask(SIG_SETMASK, &old_ss, NULL) >= 0"), "../src/core/execute.c"
, 1282, __PRETTY_FUNCTION__); } while (0)
;
1283
1284 /* We close the log explicitly here, since the PAM modules
1285 * might have opened it, but we don't want this fd around. */
1286 closelog();
1287
1288 /* Synchronously wait for the child to initialize. We don't care for
1289 * errors as we cannot recover. However, warn loudly if it happens. */
1290 if (!barrier_place_and_sync(&barrier))
1291 log_error("PAM initialization failed")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/core/execute.c", 1291, __func__, "PAM initialization failed"
) : -abs(_e); })
;
1292
1293 return strv_free_and_replace(*env, e)({ strv_free(*env); (*env) = (e); (e) = ((void*)0); 0; });
1294
1295fail:
1296 if (pam_code != PAM_SUCCESS0) {
1297 log_error("PAM failed: %s", pam_strerror(handle, pam_code))({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/core/execute.c", 1297, __func__, "PAM failed: %s", pam_strerror
(handle, pam_code)) : -abs(_e); })
;
1298 r = -EPERM1; /* PAM errors do not map to errno */
1299 } else
1300 log_error_errno(r, "PAM failed: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/core/execute.c", 1300, __func__, "PAM failed: %m") :
-abs(_e); })
;
1301
1302 if (handle) {
1303 if (close_session)
1304 pam_code = pam_close_session(handle, flags);
1305
1306 pam_end(handle, pam_code | flags);
1307 }
1308
1309 strv_free(e);
1310 closelog();
1311
1312 return r;
1313#else
1314 return 0;
1315#endif
1316}
1317
1318static void rename_process_from_path(const char *path) {
1319 char process_name[11];
1320 const char *p;
1321 size_t l;
1322
1323 /* This resulting string must fit in 10 chars (i.e. the length
1324 * of "/sbin/init") to look pretty in /bin/ps */
1325
1326 p = basename(path);
1327 if (isempty(p)) {
1328 rename_process("(...)");
1329 return;
1330 }
1331
1332 l = strlen(p);
1333 if (l > 8) {
1334 /* The end of the process name is usually more
1335 * interesting, since the first bit might just be
1336 * "systemd-" */
1337 p = p + l - 8;
1338 l = 8;
1339 }
1340
1341 process_name[0] = '(';
1342 memcpy(process_name+1, p, l);
1343 process_name[1+l] = ')';
1344 process_name[1+l+1] = 0;
1345
1346 rename_process(process_name);
1347}
1348
1349static bool_Bool context_has_address_families(const ExecContext *c) {
1350 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 1350, __PRETTY_FUNCTION__
); } while (0)
;
1351
1352 return c->address_families_whitelist ||
1353 !set_isempty(c->address_families);
1354}
1355
1356static bool_Bool context_has_syscall_filters(const ExecContext *c) {
1357 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 1357, __PRETTY_FUNCTION__
); } while (0)
;
1358
1359 return c->syscall_whitelist ||
1360 !hashmap_isempty(c->syscall_filter);
1361}
1362
1363static bool_Bool context_has_no_new_privileges(const ExecContext *c) {
1364 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 1364, __PRETTY_FUNCTION__
); } while (0)
;
1365
1366 if (c->no_new_privileges)
1367 return true1;
1368
1369 if (have_effective_cap(CAP_SYS_ADMIN21)) /* if we are privileged, we don't need NNP */
1370 return false0;
1371
1372 /* We need NNP if we have any form of seccomp and are unprivileged */
1373 return context_has_address_families(c) ||
1374 c->memory_deny_write_execute ||
1375 c->restrict_realtime ||
1376 c->restrict_suid_sgid ||
1377 exec_context_restrict_namespaces_set(c) ||
1378 c->protect_kernel_tunables ||
1379 c->protect_kernel_modules ||
1380 c->private_devices ||
1381 context_has_syscall_filters(c) ||
1382 !set_isempty(c->syscall_archs) ||
1383 c->lock_personality;
1384}
1385
1386#if HAVE_SECCOMP1
1387
1388static bool_Bool skip_seccomp_unavailable(const Unit* u, const char* msg) {
1389
1390 if (is_seccomp_available())
1391 return false0;
1392
1393 log_unit_debug(u, "SECCOMP features not detected in the kernel, skipping %s", msg)({ const Unit *_u = (u); _u ? log_object_internal(7, 0, "../src/core/execute.c"
, 1393, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "SECCOMP features not detected in the kernel, skipping %s",
msg) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 |
((7))), 0, "../src/core/execute.c", 1393, __func__, "SECCOMP features not detected in the kernel, skipping %s"
, msg); })
;
1394 return true1;
1395}
1396
1397static int apply_syscall_filter(const Unit* u, const ExecContext *c, bool_Bool needs_ambient_hack) {
1398 uint32_t negative_action, default_action, action;
1399 int r;
1400
1401 assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("u"), "../src/core/execute.c", 1401, __PRETTY_FUNCTION__
); } while (0)
;
1402 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 1402, __PRETTY_FUNCTION__
); } while (0)
;
1403
1404 if (!context_has_syscall_filters(c))
1405 return 0;
1406
1407 if (skip_seccomp_unavailable(u, "SystemCallFilter="))
1408 return 0;
1409
1410 negative_action = c->syscall_errno == 0 ? SCMP_ACT_KILL0x00000000U : SCMP_ACT_ERRNO(c->syscall_errno)(0x00050000U | ((c->syscall_errno) & 0x0000ffffU));
1411
1412 if (c->syscall_whitelist) {
1413 default_action = negative_action;
1414 action = SCMP_ACT_ALLOW0x7fff0000U;
1415 } else {
1416 default_action = SCMP_ACT_ALLOW0x7fff0000U;
1417 action = negative_action;
1418 }
1419
1420 if (needs_ambient_hack) {
1421 r = seccomp_filter_set_add(c->syscall_filter, c->syscall_whitelist, syscall_filter_sets + SYSCALL_FILTER_SET_SETUID);
1422 if (r < 0)
1423 return r;
1424 }
1425
1426 return seccomp_load_syscall_filter_set_raw(default_action, c->syscall_filter, action, false0);
1427}
1428
1429static int apply_syscall_archs(const Unit *u, const ExecContext *c) {
1430 assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("u"), "../src/core/execute.c", 1430, __PRETTY_FUNCTION__
); } while (0)
;
1431 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 1431, __PRETTY_FUNCTION__
); } while (0)
;
1432
1433 if (set_isempty(c->syscall_archs))
1434 return 0;
1435
1436 if (skip_seccomp_unavailable(u, "SystemCallArchitectures="))
1437 return 0;
1438
1439 return seccomp_restrict_archs(c->syscall_archs);
1440}
1441
1442static int apply_address_families(const Unit* u, const ExecContext *c) {
1443 assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("u"), "../src/core/execute.c", 1443, __PRETTY_FUNCTION__
); } while (0)
;
1444 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 1444, __PRETTY_FUNCTION__
); } while (0)
;
1445
1446 if (!context_has_address_families(c))
1447 return 0;
1448
1449 if (skip_seccomp_unavailable(u, "RestrictAddressFamilies="))
1450 return 0;
1451
1452 return seccomp_restrict_address_families(c->address_families, c->address_families_whitelist);
1453}
1454
1455static int apply_memory_deny_write_execute(const Unit* u, const ExecContext *c) {
1456 assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("u"), "../src/core/execute.c", 1456, __PRETTY_FUNCTION__
); } while (0)
;
1457 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 1457, __PRETTY_FUNCTION__
); } while (0)
;
1458
1459 if (!c->memory_deny_write_execute)
1460 return 0;
1461
1462 if (skip_seccomp_unavailable(u, "MemoryDenyWriteExecute="))
1463 return 0;
1464
1465 return seccomp_memory_deny_write_execute();
1466}
1467
1468static int apply_restrict_realtime(const Unit* u, const ExecContext *c) {
1469 assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("u"), "../src/core/execute.c", 1469, __PRETTY_FUNCTION__
); } while (0)
;
1470 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 1470, __PRETTY_FUNCTION__
); } while (0)
;
1471
1472 if (!c->restrict_realtime)
1473 return 0;
1474
1475 if (skip_seccomp_unavailable(u, "RestrictRealtime="))
1476 return 0;
1477
1478 return seccomp_restrict_realtime();
1479}
1480
1481static int apply_restrict_suid_sgid(const Unit* u, const ExecContext *c) {
1482 assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("u"), "../src/core/execute.c", 1482, __PRETTY_FUNCTION__
); } while (0)
;
1483 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 1483, __PRETTY_FUNCTION__
); } while (0)
;
1484
1485 if (!c->restrict_suid_sgid)
1486 return 0;
1487
1488 if (skip_seccomp_unavailable(u, "RestrictSUIDSGID="))
1489 return 0;
1490
1491 return seccomp_restrict_suid_sgid();
1492}
1493
1494static int apply_protect_sysctl(const Unit *u, const ExecContext *c) {
1495 assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("u"), "../src/core/execute.c", 1495, __PRETTY_FUNCTION__
); } while (0)
;
1496 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 1496, __PRETTY_FUNCTION__
); } while (0)
;
1497
1498 /* Turn off the legacy sysctl() system call. Many distributions turn this off while building the kernel, but
1499 * let's protect even those systems where this is left on in the kernel. */
1500
1501 if (!c->protect_kernel_tunables)
1502 return 0;
1503
1504 if (skip_seccomp_unavailable(u, "ProtectKernelTunables="))
1505 return 0;
1506
1507 return seccomp_protect_sysctl();
1508}
1509
1510static int apply_protect_kernel_modules(const Unit *u, const ExecContext *c) {
1511 assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("u"), "../src/core/execute.c", 1511, __PRETTY_FUNCTION__
); } while (0)
;
1512 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 1512, __PRETTY_FUNCTION__
); } while (0)
;
1513
1514 /* Turn off module syscalls on ProtectKernelModules=yes */
1515
1516 if (!c->protect_kernel_modules)
1517 return 0;
1518
1519 if (skip_seccomp_unavailable(u, "ProtectKernelModules="))
1520 return 0;
1521
1522 return seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW0x7fff0000U, syscall_filter_sets + SYSCALL_FILTER_SET_MODULE, SCMP_ACT_ERRNO(EPERM)(0x00050000U | ((1) & 0x0000ffffU)), false0);
1523}
1524
1525static int apply_private_devices(const Unit *u, const ExecContext *c) {
1526 assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("u"), "../src/core/execute.c", 1526, __PRETTY_FUNCTION__
); } while (0)
;
1527 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 1527, __PRETTY_FUNCTION__
); } while (0)
;
1528
1529 /* If PrivateDevices= is set, also turn off iopl and all @raw-io syscalls. */
1530
1531 if (!c->private_devices)
1532 return 0;
1533
1534 if (skip_seccomp_unavailable(u, "PrivateDevices="))
1535 return 0;
1536
1537 return seccomp_load_syscall_filter_set(SCMP_ACT_ALLOW0x7fff0000U, syscall_filter_sets + SYSCALL_FILTER_SET_RAW_IO, SCMP_ACT_ERRNO(EPERM)(0x00050000U | ((1) & 0x0000ffffU)), false0);
1538}
1539
1540static int apply_restrict_namespaces(const Unit *u, const ExecContext *c) {
1541 assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("u"), "../src/core/execute.c", 1541, __PRETTY_FUNCTION__
); } while (0)
;
1542 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 1542, __PRETTY_FUNCTION__
); } while (0)
;
1543
1544 if (!exec_context_restrict_namespaces_set(c))
1545 return 0;
1546
1547 if (skip_seccomp_unavailable(u, "RestrictNamespaces="))
1548 return 0;
1549
1550 return seccomp_restrict_namespaces(c->restrict_namespaces);
1551}
1552
1553static int apply_lock_personality(const Unit* u, const ExecContext *c) {
1554 unsigned long personality;
1555 int r;
1556
1557 assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("u"), "../src/core/execute.c", 1557, __PRETTY_FUNCTION__
); } while (0)
;
1558 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 1558, __PRETTY_FUNCTION__
); } while (0)
;
1559
1560 if (!c->lock_personality)
1561 return 0;
1562
1563 if (skip_seccomp_unavailable(u, "LockPersonality="))
1564 return 0;
1565
1566 personality = c->personality;
1567
1568 /* If personality is not specified, use either PER_LINUX or PER_LINUX32 depending on what is currently set. */
1569 if (personality == PERSONALITY_INVALID0xffffffffLU) {
1570
1571 r = opinionated_personality(&personality);
1572 if (r < 0)
1573 return r;
1574 }
1575
1576 return seccomp_lock_personality(personality);
1577}
1578
1579#endif
1580
1581static void do_idle_pipe_dance(int idle_pipe[4]) {
1582 assert(idle_pipe)do { if ((__builtin_expect(!!(!(idle_pipe)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("idle_pipe"), "../src/core/execute.c", 1582
, __PRETTY_FUNCTION__); } while (0)
;
1583
1584 idle_pipe[1] = safe_close(idle_pipe[1]);
1585 idle_pipe[2] = safe_close(idle_pipe[2]);
1586
1587 if (idle_pipe[0] >= 0) {
1588 int r;
1589
1590 r = fd_wait_for_event(idle_pipe[0], POLLHUP0x010, IDLE_TIMEOUT_USEC(5*((usec_t) 1000000ULL)));
1591
1592 if (idle_pipe[3] >= 0 && r == 0 /* timeout */) {
1593 ssize_t n;
1594
1595 /* Signal systemd that we are bored and want to continue. */
1596 n = write(idle_pipe[3], "x", 1);
1597 if (n > 0)
1598 /* Wait for systemd to react to the signal above. */
1599 fd_wait_for_event(idle_pipe[0], POLLHUP0x010, IDLE_TIMEOUT2_USEC(1*((usec_t) 1000000ULL)));
1600 }
1601
1602 idle_pipe[0] = safe_close(idle_pipe[0]);
1603
1604 }
1605
1606 idle_pipe[3] = safe_close(idle_pipe[3]);
1607}
1608
1609static int build_environment(
1610 const Unit *u,
1611 const ExecContext *c,
1612 const ExecParameters *p,
1613 size_t n_fds,
1614 const char *home,
1615 const char *username,
1616 const char *shell,
1617 dev_t journal_stream_dev,
1618 ino_t journal_stream_ino,
1619 char ***ret) {
1620
1621 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **our_env = NULL((void*)0);
1622 size_t n_env = 0;
1623 char *x;
1624
1625 assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("u"), "../src/core/execute.c", 1625, __PRETTY_FUNCTION__
); } while (0)
;
1626 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 1626, __PRETTY_FUNCTION__
); } while (0)
;
1627 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/core/execute.c", 1627, __PRETTY_FUNCTION__
); } while (0)
;
1628
1629 our_env = new0(char*, 14)((char**) calloc((14), sizeof(char*)));
1630 if (!our_env)
1631 return -ENOMEM12;
1632
1633 if (n_fds > 0) {
1634 _cleanup_free___attribute__((cleanup(freep))) char *joined = NULL((void*)0);
1635
1636 if (asprintf(&x, "LISTEN_PID="PID_FMT"%" "i", getpid_cached()) < 0)
1637 return -ENOMEM12;
1638 our_env[n_env++] = x;
1639
1640 if (asprintf(&x, "LISTEN_FDS=%zu", n_fds) < 0)
1641 return -ENOMEM12;
1642 our_env[n_env++] = x;
1643
1644 joined = strv_join(p->fd_names, ":");
1645 if (!joined)
1646 return -ENOMEM12;
1647
1648 x = strjoin("LISTEN_FDNAMES=", joined)strjoin_real(("LISTEN_FDNAMES="), joined, ((void*)0));
1649 if (!x)
1650 return -ENOMEM12;
1651 our_env[n_env++] = x;
1652 }
1653
1654 if ((p->flags & EXEC_SET_WATCHDOG) && p->watchdog_usec > 0) {
1655 if (asprintf(&x, "WATCHDOG_PID="PID_FMT"%" "i", getpid_cached()) < 0)
1656 return -ENOMEM12;
1657 our_env[n_env++] = x;
1658
1659 if (asprintf(&x, "WATCHDOG_USEC="USEC_FMT"%" "l" "u", p->watchdog_usec) < 0)
1660 return -ENOMEM12;
1661 our_env[n_env++] = x;
1662 }
1663
1664 /* If this is D-Bus, tell the nss-systemd module, since it relies on being able to use D-Bus look up dynamic
1665 * users via PID 1, possibly dead-locking the dbus daemon. This way it will not use D-Bus to resolve names, but
1666 * check the database directly. */
1667 if (p->flags & EXEC_NSS_BYPASS_BUS) {
1668 x = strdup("SYSTEMD_NSS_BYPASS_BUS=1");
1669 if (!x)
1670 return -ENOMEM12;
1671 our_env[n_env++] = x;
1672 }
1673
1674 if (home) {
1675 x = strappend("HOME=", home);
1676 if (!x)
1677 return -ENOMEM12;
1678 our_env[n_env++] = x;
1679 }
1680
1681 if (username) {
1682 x = strappend("LOGNAME=", username);
1683 if (!x)
1684 return -ENOMEM12;
1685 our_env[n_env++] = x;
1686
1687 x = strappend("USER=", username);
1688 if (!x)
1689 return -ENOMEM12;
1690 our_env[n_env++] = x;
1691 }
1692
1693 if (shell) {
1694 x = strappend("SHELL=", shell);
1695 if (!x)
1696 return -ENOMEM12;
1697 our_env[n_env++] = x;
1698 }
1699
1700 if (!sd_id128_is_null(u->invocation_id)) {
1701 if (asprintf(&x, "INVOCATION_ID=" SD_ID128_FORMAT_STR"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", SD_ID128_FORMAT_VAL(u->invocation_id)(u->invocation_id).bytes[0], (u->invocation_id).bytes[1
], (u->invocation_id).bytes[2], (u->invocation_id).bytes
[3], (u->invocation_id).bytes[4], (u->invocation_id).bytes
[5], (u->invocation_id).bytes[6], (u->invocation_id).bytes
[7], (u->invocation_id).bytes[8], (u->invocation_id).bytes
[9], (u->invocation_id).bytes[10], (u->invocation_id).bytes
[11], (u->invocation_id).bytes[12], (u->invocation_id).
bytes[13], (u->invocation_id).bytes[14], (u->invocation_id
).bytes[15]
) < 0)
1702 return -ENOMEM12;
1703
1704 our_env[n_env++] = x;
1705 }
1706
1707 if (exec_context_needs_term(c)) {
1708 const char *tty_path, *term = NULL((void*)0);
1709
1710 tty_path = exec_context_tty_path(c);
1711
1712 /* If we are forked off PID 1 and we are supposed to operate on /dev/console, then let's try to inherit
1713 * the $TERM set for PID 1. This is useful for containers so that the $TERM the container manager
1714 * passes to PID 1 ends up all the way in the console login shown. */
1715
1716 if (path_equal(tty_path, "/dev/console") && getppid() == 1)
1717 term = getenv("TERM");
1718 if (!term)
1719 term = default_term_for_tty(tty_path);
1720
1721 x = strappend("TERM=", term);
1722 if (!x)
1723 return -ENOMEM12;
1724 our_env[n_env++] = x;
1725 }
1726
1727 if (journal_stream_dev != 0 && journal_stream_ino != 0) {
1728 if (asprintf(&x, "JOURNAL_STREAM=" DEV_FMT"%" "l" "u" ":" INO_FMT"%" "l" "u", journal_stream_dev, journal_stream_ino) < 0)
1729 return -ENOMEM12;
1730
1731 our_env[n_env++] = x;
1732 }
1733
1734 our_env[n_env++] = NULL((void*)0);
1735 assert(n_env <= 12)do { if ((__builtin_expect(!!(!(n_env <= 12)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("n_env <= 12"), "../src/core/execute.c"
, 1735, __PRETTY_FUNCTION__); } while (0)
;
1736
1737 *ret = TAKE_PTR(our_env)({ typeof(our_env) _ptr_ = (our_env); (our_env) = ((void*)0);
_ptr_; })
;
1738
1739 return 0;
1740}
1741
1742static int build_pass_environment(const ExecContext *c, char ***ret) {
1743 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **pass_env = NULL((void*)0);
1744 size_t n_env = 0, n_bufsize = 0;
1745 char **i;
1746
1747 STRV_FOREACH(i, c->pass_environment)for ((i) = (c->pass_environment); (i) && *(i); (i)
++)
{
1748 _cleanup_free___attribute__((cleanup(freep))) char *x = NULL((void*)0);
1749 char *v;
1750
1751 v = getenv(*i);
1752 if (!v)
1753 continue;
1754 x = strjoin(*i, "=", v)strjoin_real((*i), "=", v, ((void*)0));
1755 if (!x)
1756 return -ENOMEM12;
1757
1758 if (!GREEDY_REALLOC(pass_env, n_bufsize, n_env + 2)greedy_realloc((void**) &(pass_env), &(n_bufsize), (n_env
+ 2), sizeof((pass_env)[0]))
)
1759 return -ENOMEM12;
1760
1761 pass_env[n_env++] = TAKE_PTR(x)({ typeof(x) _ptr_ = (x); (x) = ((void*)0); _ptr_; });
1762 pass_env[n_env] = NULL((void*)0);
1763 }
1764
1765 *ret = TAKE_PTR(pass_env)({ typeof(pass_env) _ptr_ = (pass_env); (pass_env) = ((void*)
0); _ptr_; })
;
1766
1767 return 0;
1768}
1769
1770static bool_Bool exec_needs_mount_namespace(
1771 const ExecContext *context,
1772 const ExecParameters *params,
1773 const ExecRuntime *runtime) {
1774
1775 assert(context)do { if ((__builtin_expect(!!(!(context)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("context"), "../src/core/execute.c", 1775
, __PRETTY_FUNCTION__); } while (0)
;
1776 assert(params)do { if ((__builtin_expect(!!(!(params)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("params"), "../src/core/execute.c", 1776
, __PRETTY_FUNCTION__); } while (0)
;
1777
1778 if (context->root_image)
1779 return true1;
1780
1781 if (!strv_isempty(context->read_write_paths) ||
1782 !strv_isempty(context->read_only_paths) ||
1783 !strv_isempty(context->inaccessible_paths))
1784 return true1;
1785
1786 if (context->n_bind_mounts > 0)
1787 return true1;
1788
1789 if (context->n_temporary_filesystems > 0)
1790 return true1;
1791
1792 if (context->mount_flags != 0)
1793 return true1;
1794
1795 if (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir))
1796 return true1;
1797
1798 if (context->private_devices ||
1799 context->private_mounts ||
1800 context->protect_system != PROTECT_SYSTEM_NO ||
1801 context->protect_home != PROTECT_HOME_NO ||
1802 context->protect_kernel_tunables ||
1803 context->protect_kernel_modules ||
1804 context->protect_control_groups)
1805 return true1;
1806
1807 if (context->root_directory) {
1808 ExecDirectoryType t;
1809
1810 if (context->mount_apivfs)
1811 return true1;
1812
1813 for (t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
1814 if (!params->prefix[t])
1815 continue;
1816
1817 if (!strv_isempty(context->directories[t].paths))
1818 return true1;
1819 }
1820 }
1821
1822 if (context->dynamic_user &&
1823 (!strv_isempty(context->directories[EXEC_DIRECTORY_STATE].paths) ||
1824 !strv_isempty(context->directories[EXEC_DIRECTORY_CACHE].paths) ||
1825 !strv_isempty(context->directories[EXEC_DIRECTORY_LOGS].paths)))
1826 return true1;
1827
1828 return false0;
1829}
1830
1831static int setup_private_users(uid_t uid, gid_t gid) {
1832 _cleanup_free___attribute__((cleanup(freep))) char *uid_map = NULL((void*)0), *gid_map = NULL((void*)0);
1833 _cleanup_close_pair___attribute__((cleanup(close_pairp))) int errno_pipe[2] = { -1, -1 };
1834 _cleanup_close___attribute__((cleanup(closep))) int unshare_ready_fd = -1;
1835 _cleanup_(sigkill_waitp)__attribute__((cleanup(sigkill_waitp))) pid_t pid = 0;
1836 uint64_t c = 1;
1837 ssize_t n;
1838 int r;
1839
1840 /* Set up a user namespace and map root to root, the selected UID/GID to itself, and everything else to
1841 * nobody. In order to be able to write this mapping we need CAP_SETUID in the original user namespace, which
1842 * we however lack after opening the user namespace. To work around this we fork() a temporary child process,
1843 * which waits for the parent to create the new user namespace while staying in the original namespace. The
1844 * child then writes the UID mapping, under full privileges. The parent waits for the child to finish and
1845 * continues execution normally. */
1846
1847 if (uid != 0 && uid_is_valid(uid)) {
1
Assuming 'uid' is equal to 0
1848 r = asprintf(&uid_map,
1849 "0 0 1\n" /* Map root → root */
1850 UID_FMT"%" "u" " " UID_FMT"%" "u" " 1\n", /* Map $UID → $UID */
1851 uid, uid);
1852 if (r < 0)
1853 return -ENOMEM12;
1854 } else {
1855 uid_map = strdup("0 0 1\n"); /* The case where the above is the same */
2
Memory is allocated
1856 if (!uid_map)
3
Assuming 'uid_map' is non-null
4
Taking false branch
1857 return -ENOMEM12;
1858 }
1859
1860 if (gid != 0 && gid_is_valid(gid)) {
5
Assuming 'gid' is equal to 0
1861 r = asprintf(&gid_map,
1862 "0 0 1\n" /* Map root → root */
1863 GID_FMT"%" "u" " " GID_FMT"%" "u" " 1\n", /* Map $GID → $GID */
1864 gid, gid);
1865 if (r < 0)
1866 return -ENOMEM12;
1867 } else {
1868 gid_map = strdup("0 0 1\n"); /* The case where the above is the same */
1869 if (!gid_map)
6
Assuming 'gid_map' is null
7
Taking true branch
1870 return -ENOMEM12;
8
Potential leak of memory pointed to by 'uid_map'
1871 }
1872
1873 /* Create a communication channel so that the parent can tell the child when it finished creating the user
1874 * namespace. */
1875 unshare_ready_fd = eventfd(0, EFD_CLOEXECEFD_CLOEXEC);
1876 if (unshare_ready_fd < 0)
1877 return -errno(*__errno_location ());
1878
1879 /* Create a communication channel so that the child can tell the parent a proper error code in case it
1880 * failed. */
1881 if (pipe2(errno_pipe, O_CLOEXEC02000000) < 0)
1882 return -errno(*__errno_location ());
1883
1884 r = safe_fork("(sd-userns)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
1885 if (r < 0)
1886 return r;
1887 if (r == 0) {
1888 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
1889 const char *a;
1890 pid_t ppid;
1891
1892 /* Child process, running in the original user namespace. Let's update the parent's UID/GID map from
1893 * here, after the parent opened its own user namespace. */
1894
1895 ppid = getppid();
1896 errno_pipe[0] = safe_close(errno_pipe[0]);
1897
1898 /* Wait until the parent unshared the user namespace */
1899 if (read(unshare_ready_fd, &c, sizeof(c)) < 0) {
1900 r = -errno(*__errno_location ());
1901 goto child_fail;
1902 }
1903
1904 /* Disable the setgroups() system call in the child user namespace, for good. */
1905 a = procfs_file_alloca(ppid, "setgroups")({ pid_t _pid_ = (ppid); const char *_r_; if (_pid_ == 0) { _r_
= ("/proc/self/" "setgroups"); } else { _r_ = __builtin_alloca
((sizeof("""/proc/""") - 1) + (2+(sizeof(pid_t) <= 1 ? 3 :
sizeof(pid_t) <= 2 ? 5 : sizeof(pid_t) <= 4 ? 10 : sizeof
(pid_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(pid_t) > 8)])
)) + 1 + sizeof("setgroups")); sprintf((char*) _r_, "/proc/""%"
"i""/" "setgroups", _pid_); } _r_; })
;
1906 fd = open(a, O_WRONLY01|O_CLOEXEC02000000);
1907 if (fd < 0) {
1908 if (errno(*__errno_location ()) != ENOENT2) {
1909 r = -errno(*__errno_location ());
1910 goto child_fail;
1911 }
1912
1913 /* If the file is missing the kernel is too old, let's continue anyway. */
1914 } else {
1915 if (write(fd, "deny\n", 5) < 0) {
1916 r = -errno(*__errno_location ());
1917 goto child_fail;
1918 }
1919
1920 fd = safe_close(fd);
1921 }
1922
1923 /* First write the GID map */
1924 a = procfs_file_alloca(ppid, "gid_map")({ pid_t _pid_ = (ppid); const char *_r_; if (_pid_ == 0) { _r_
= ("/proc/self/" "gid_map"); } else { _r_ = __builtin_alloca
((sizeof("""/proc/""") - 1) + (2+(sizeof(pid_t) <= 1 ? 3 :
sizeof(pid_t) <= 2 ? 5 : sizeof(pid_t) <= 4 ? 10 : sizeof
(pid_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(pid_t) > 8)])
)) + 1 + sizeof("gid_map")); sprintf((char*) _r_, "/proc/""%"
"i""/" "gid_map", _pid_); } _r_; })
;
1925 fd = open(a, O_WRONLY01|O_CLOEXEC02000000);
1926 if (fd < 0) {
1927 r = -errno(*__errno_location ());
1928 goto child_fail;
1929 }
1930 if (write(fd, gid_map, strlen(gid_map)) < 0) {
1931 r = -errno(*__errno_location ());
1932 goto child_fail;
1933 }
1934 fd = safe_close(fd);
1935
1936 /* The write the UID map */
1937 a = procfs_file_alloca(ppid, "uid_map")({ pid_t _pid_ = (ppid); const char *_r_; if (_pid_ == 0) { _r_
= ("/proc/self/" "uid_map"); } else { _r_ = __builtin_alloca
((sizeof("""/proc/""") - 1) + (2+(sizeof(pid_t) <= 1 ? 3 :
sizeof(pid_t) <= 2 ? 5 : sizeof(pid_t) <= 4 ? 10 : sizeof
(pid_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(pid_t) > 8)])
)) + 1 + sizeof("uid_map")); sprintf((char*) _r_, "/proc/""%"
"i""/" "uid_map", _pid_); } _r_; })
;
1938 fd = open(a, O_WRONLY01|O_CLOEXEC02000000);
1939 if (fd < 0) {
1940 r = -errno(*__errno_location ());
1941 goto child_fail;
1942 }
1943 if (write(fd, uid_map, strlen(uid_map)) < 0) {
1944 r = -errno(*__errno_location ());
1945 goto child_fail;
1946 }
1947
1948 _exit(EXIT_SUCCESS0);
1949
1950 child_fail:
1951 (void) write(errno_pipe[1], &r, sizeof(r));
1952 _exit(EXIT_FAILURE1);
1953 }
1954
1955 errno_pipe[1] = safe_close(errno_pipe[1]);
1956
1957 if (unshare(CLONE_NEWUSER0x10000000) < 0)
1958 return -errno(*__errno_location ());
1959
1960 /* Let the child know that the namespace is ready now */
1961 if (write(unshare_ready_fd, &c, sizeof(c)) < 0)
1962 return -errno(*__errno_location ());
1963
1964 /* Try to read an error code from the child */
1965 n = read(errno_pipe[0], &r, sizeof(r));
1966 if (n < 0)
1967 return -errno(*__errno_location ());
1968 if (n == sizeof(r)) { /* an error code was sent to us */
1969 if (r < 0)
1970 return r;
1971 return -EIO5;
1972 }
1973 if (n != 0) /* on success we should have read 0 bytes */
1974 return -EIO5;
1975
1976 r = wait_for_terminate_and_check("(sd-userns)", pid, 0);
1977 pid = 0;
1978 if (r < 0)
1979 return r;
1980 if (r != EXIT_SUCCESS0) /* If something strange happened with the child, let's consider this fatal, too */
1981 return -EIO5;
1982
1983 return 0;
1984}
1985
1986static int setup_exec_directory(
1987 const ExecContext *context,
1988 const ExecParameters *params,
1989 uid_t uid,
1990 gid_t gid,
1991 ExecDirectoryType type,
1992 int *exit_status) {
1993
1994 static const int exit_status_table[_EXEC_DIRECTORY_TYPE_MAX] = {
1995 [EXEC_DIRECTORY_RUNTIME] = EXIT_RUNTIME_DIRECTORY,
1996 [EXEC_DIRECTORY_STATE] = EXIT_STATE_DIRECTORY,
1997 [EXEC_DIRECTORY_CACHE] = EXIT_CACHE_DIRECTORY,
1998 [EXEC_DIRECTORY_LOGS] = EXIT_LOGS_DIRECTORY,
1999 [EXEC_DIRECTORY_CONFIGURATION] = EXIT_CONFIGURATION_DIRECTORY,
2000 };
2001 char **rt;
2002 int r;
2003
2004 assert(context)do { if ((__builtin_expect(!!(!(context)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("context"), "../src/core/execute.c", 2004
, __PRETTY_FUNCTION__); } while (0)
;
2005 assert(params)do { if ((__builtin_expect(!!(!(params)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("params"), "../src/core/execute.c", 2005
, __PRETTY_FUNCTION__); } while (0)
;
2006 assert(type >= 0 && type < _EXEC_DIRECTORY_TYPE_MAX)do { if ((__builtin_expect(!!(!(type >= 0 && type <
_EXEC_DIRECTORY_TYPE_MAX)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("type >= 0 && type < _EXEC_DIRECTORY_TYPE_MAX"
), "../src/core/execute.c", 2006, __PRETTY_FUNCTION__); } while
(0)
;
2007 assert(exit_status)do { if ((__builtin_expect(!!(!(exit_status)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("exit_status"), "../src/core/execute.c",
2007, __PRETTY_FUNCTION__); } while (0)
;
2008
2009 if (!params->prefix[type])
2010 return 0;
2011
2012 if (params->flags & EXEC_CHOWN_DIRECTORIES) {
2013 if (!uid_is_valid(uid))
2014 uid = 0;
2015 if (!gid_is_valid(gid))
2016 gid = 0;
2017 }
2018
2019 STRV_FOREACH(rt, context->directories[type].paths)for ((rt) = (context->directories[type].paths); (rt) &&
*(rt); (rt)++)
{
2020 _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0), *pp = NULL((void*)0);
2021
2022 p = strjoin(params->prefix[type], "/", *rt)strjoin_real((params->prefix[type]), "/", *rt, ((void*)0));
2023 if (!p) {
2024 r = -ENOMEM12;
2025 goto fail;
2026 }
2027
2028 r = mkdir_parents_label(p, 0755);
2029 if (r < 0)
2030 goto fail;
2031
2032 if (context->dynamic_user &&
2033 !IN_SET(type, EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION
})/sizeof(int)]; switch(type) { case EXEC_DIRECTORY_RUNTIME: case
EXEC_DIRECTORY_CONFIGURATION: _found = 1; break; default: break
; } _found; })
) {
2034 _cleanup_free___attribute__((cleanup(freep))) char *private_root = NULL((void*)0), *relative = NULL((void*)0), *parent = NULL((void*)0);
2035
2036 /* So, here's one extra complication when dealing with DynamicUser=1 units. In that case we
2037 * want to avoid leaving a directory around fully accessible that is owned by a dynamic user
2038 * whose UID is later on reused. To lock this down we use the same trick used by container
2039 * managers to prohibit host users to get access to files of the same UID in containers: we
2040 * place everything inside a directory that has an access mode of 0700 and is owned root:root,
2041 * so that it acts as security boundary for unprivileged host code. We then use fs namespacing
2042 * to make this directory permeable for the service itself.
2043 *
2044 * Specifically: for a service which wants a special directory "foo/" we first create a
2045 * directory "private/" with access mode 0700 owned by root:root. Then we place "foo" inside of
2046 * that directory (i.e. "private/foo/"), and make "foo" a symlink to "private/foo". This way,
2047 * privileged host users can access "foo/" as usual, but unprivileged host users can't look
2048 * into it. Inside of the namespaceof the container "private/" is replaced by a more liberally
2049 * accessible tmpfs, into which the host's "private/foo/" is mounted under the same name, thus
2050 * disabling the access boundary for the service and making sure it only gets access to the
2051 * dirs it needs but no others. Tricky? Yes, absolutely, but it works!
2052 *
2053 * Note that we don't do this for EXEC_DIRECTORY_CONFIGURATION as that's assumed not to be
2054 * owned by the service itself.
2055 * Also, note that we don't do this for EXEC_DIRECTORY_RUNTIME as that's often used for sharing
2056 * files or sockets with other services. */
2057
2058 private_root = strjoin(params->prefix[type], "/private")strjoin_real((params->prefix[type]), "/private", ((void*)0
))
;
2059 if (!private_root) {
2060 r = -ENOMEM12;
2061 goto fail;
2062 }
2063
2064 /* First set up private root if it doesn't exist yet, with access mode 0700 and owned by root:root */
2065 r = mkdir_safe_label(private_root, 0700, 0, 0, MKDIR_WARN_MODE);
2066 if (r < 0)
2067 goto fail;
2068
2069 pp = strjoin(private_root, "/", *rt)strjoin_real((private_root), "/", *rt, ((void*)0));
2070 if (!pp) {
2071 r = -ENOMEM12;
2072 goto fail;
2073 }
2074
2075 /* Create all directories between the configured directory and this private root, and mark them 0755 */
2076 r = mkdir_parents_label(pp, 0755);
2077 if (r < 0)
2078 goto fail;
2079
2080 if (is_dir(p, false0) > 0 &&
2081 (laccess(pp, F_OK)faccessat(-100, (pp), (0), 0x100) < 0 && errno(*__errno_location ()) == ENOENT2)) {
2082
2083 /* Hmm, the private directory doesn't exist yet, but the normal one exists? If so, move
2084 * it over. Most likely the service has been upgraded from one that didn't use
2085 * DynamicUser=1, to one that does. */
2086
2087 if (rename(p, pp) < 0) {
2088 r = -errno(*__errno_location ());
2089 goto fail;
2090 }
2091 } else {
2092 /* Otherwise, create the actual directory for the service */
2093
2094 r = mkdir_label(pp, context->directories[type].mode);
2095 if (r < 0 && r != -EEXIST17)
2096 goto fail;
2097 }
2098
2099 parent = dirname_malloc(p);
2100 if (!parent) {
2101 r = -ENOMEM12;
2102 goto fail;
2103 }
2104
2105 r = path_make_relative(parent, pp, &relative);
2106 if (r < 0)
2107 goto fail;
2108
2109 /* And link it up from the original place */
2110 r = symlink_idempotent(relative, p);
2111 if (r < 0)
2112 goto fail;
2113
2114 } else {
2115 r = mkdir_label(p, context->directories[type].mode);
2116 if (r < 0) {
2117 if (r != -EEXIST17)
2118 goto fail;
2119
2120 if (type == EXEC_DIRECTORY_CONFIGURATION) {
2121 struct stat st;
2122
2123 /* Don't change the owner/access mode of the configuration directory,
2124 * as in the common case it is not written to by a service, and shall
2125 * not be writable. */
2126
2127 if (stat(p, &st) < 0) {
2128 r = -errno(*__errno_location ());
2129 goto fail;
2130 }
2131
2132 /* Still complain if the access mode doesn't match */
2133 if (((st.st_mode ^ context->directories[type].mode) & 07777) != 0)
2134 log_warning("%s \'%s\' already exists but the mode is different. "({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/core/execute.c", 2137, __func__, "%s \'%s\' already exists but the mode is different. "
"(File system: %o %sMode: %o)", exec_directory_type_to_string
(type), *rt, st.st_mode & 07777, exec_directory_type_to_string
(type), context->directories[type].mode & 07777) : -abs
(_e); })
2135 "(File system: %o %sMode: %o)",({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/core/execute.c", 2137, __func__, "%s \'%s\' already exists but the mode is different. "
"(File system: %o %sMode: %o)", exec_directory_type_to_string
(type), *rt, st.st_mode & 07777, exec_directory_type_to_string
(type), context->directories[type].mode & 07777) : -abs
(_e); })
2136 exec_directory_type_to_string(type), *rt,({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/core/execute.c", 2137, __func__, "%s \'%s\' already exists but the mode is different. "
"(File system: %o %sMode: %o)", exec_directory_type_to_string
(type), *rt, st.st_mode & 07777, exec_directory_type_to_string
(type), context->directories[type].mode & 07777) : -abs
(_e); })
2137 st.st_mode & 07777, exec_directory_type_to_string(type), context->directories[type].mode & 07777)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/core/execute.c", 2137, __func__, "%s \'%s\' already exists but the mode is different. "
"(File system: %o %sMode: %o)", exec_directory_type_to_string
(type), *rt, st.st_mode & 07777, exec_directory_type_to_string
(type), context->directories[type].mode & 07777) : -abs
(_e); })
;
2138
2139 continue;
2140 }
2141 }
2142 }
2143
2144 /* Lock down the access mode (we use chmod_and_chown() to make this idempotent. We don't
2145 * specifiy UID/GID here, so that path_chown_recursive() can optimize things depending on the
2146 * current UID/GID ownership.) */
2147 r = chmod_and_chown(pp ?: p, context->directories[type].mode, UID_INVALID((uid_t) -1), GID_INVALID((gid_t) -1));
2148 if (r < 0)
2149 goto fail;
2150
2151 /* Then, change the ownership of the whole tree, if necessary */
2152 r = path_chown_recursive(pp ?: p, uid, gid);
2153 if (r < 0)
2154 goto fail;
2155 }
2156
2157 return 0;
2158
2159fail:
2160 *exit_status = exit_status_table[type];
2161 return r;
2162}
2163
2164#if ENABLE_SMACK1
2165static int setup_smack(
2166 const ExecContext *context,
2167 const ExecCommand *command) {
2168
2169 int r;
2170
2171 assert(context)do { if ((__builtin_expect(!!(!(context)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("context"), "../src/core/execute.c", 2171
, __PRETTY_FUNCTION__); } while (0)
;
2172 assert(command)do { if ((__builtin_expect(!!(!(command)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("command"), "../src/core/execute.c", 2172
, __PRETTY_FUNCTION__); } while (0)
;
2173
2174 if (context->smack_process_label) {
2175 r = mac_smack_apply_pid(0, context->smack_process_label);
2176 if (r < 0)
2177 return r;
2178 }
2179#ifdef SMACK_DEFAULT_PROCESS_LABEL
2180 else {
2181 _cleanup_free___attribute__((cleanup(freep))) char *exec_label = NULL((void*)0);
2182
2183 r = mac_smack_read(command->path, SMACK_ATTR_EXEC, &exec_label);
2184 if (r < 0 && !IN_SET(r, -ENODATA, -EOPNOTSUPP)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){-61, -95})/sizeof(int)]; switch(r) { case
-61: case -95: _found = 1; break; default: break; } _found; }
)
)
2185 return r;
2186
2187 r = mac_smack_apply_pid(0, exec_label ? : SMACK_DEFAULT_PROCESS_LABEL);
2188 if (r < 0)
2189 return r;
2190 }
2191#endif
2192
2193 return 0;
2194}
2195#endif
2196
2197static int compile_bind_mounts(
2198 const ExecContext *context,
2199 const ExecParameters *params,
2200 BindMount **ret_bind_mounts,
2201 size_t *ret_n_bind_mounts,
2202 char ***ret_empty_directories) {
2203
2204 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **empty_directories = NULL((void*)0);
2205 BindMount *bind_mounts;
2206 size_t n, h = 0, i;
2207 ExecDirectoryType t;
2208 int r;
2209
2210 assert(context)do { if ((__builtin_expect(!!(!(context)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("context"), "../src/core/execute.c", 2210
, __PRETTY_FUNCTION__); } while (0)
;
2211 assert(params)do { if ((__builtin_expect(!!(!(params)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("params"), "../src/core/execute.c", 2211
, __PRETTY_FUNCTION__); } while (0)
;
2212 assert(ret_bind_mounts)do { if ((__builtin_expect(!!(!(ret_bind_mounts)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret_bind_mounts"), "../src/core/execute.c"
, 2212, __PRETTY_FUNCTION__); } while (0)
;
2213 assert(ret_n_bind_mounts)do { if ((__builtin_expect(!!(!(ret_n_bind_mounts)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret_n_bind_mounts"), "../src/core/execute.c"
, 2213, __PRETTY_FUNCTION__); } while (0)
;
2214 assert(ret_empty_directories)do { if ((__builtin_expect(!!(!(ret_empty_directories)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret_empty_directories"), "../src/core/execute.c"
, 2214, __PRETTY_FUNCTION__); } while (0)
;
2215
2216 n = context->n_bind_mounts;
2217 for (t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
2218 if (!params->prefix[t])
2219 continue;
2220
2221 n += strv_length(context->directories[t].paths);
2222 }
2223
2224 if (n <= 0) {
2225 *ret_bind_mounts = NULL((void*)0);
2226 *ret_n_bind_mounts = 0;
2227 *ret_empty_directories = NULL((void*)0);
2228 return 0;
2229 }
2230
2231 bind_mounts = new(BindMount, n)((BindMount*) malloc_multiply(sizeof(BindMount), (n)));
2232 if (!bind_mounts)
2233 return -ENOMEM12;
2234
2235 for (i = 0; i < context->n_bind_mounts; i++) {
2236 BindMount *item = context->bind_mounts + i;
2237 char *s, *d;
2238
2239 s = strdup(item->source);
2240 if (!s) {
2241 r = -ENOMEM12;
2242 goto finish;
2243 }
2244
2245 d = strdup(item->destination);
2246 if (!d) {
2247 free(s);
2248 r = -ENOMEM12;
2249 goto finish;
2250 }
2251
2252 bind_mounts[h++] = (BindMount) {
2253 .source = s,
2254 .destination = d,
2255 .read_only = item->read_only,
2256 .recursive = item->recursive,
2257 .ignore_enoent = item->ignore_enoent,
2258 };
2259 }
2260
2261 for (t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
2262 char **suffix;
2263
2264 if (!params->prefix[t])
2265 continue;
2266
2267 if (strv_isempty(context->directories[t].paths))
2268 continue;
2269
2270 if (context->dynamic_user &&
2271 !IN_SET(t, EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION
})/sizeof(int)]; switch(t) { case EXEC_DIRECTORY_RUNTIME: case
EXEC_DIRECTORY_CONFIGURATION: _found = 1; break; default: break
; } _found; })
&&
2272 !(context->root_directory || context->root_image)) {
2273 char *private_root;
2274
2275 /* So this is for a dynamic user, and we need to make sure the process can access its own
2276 * directory. For that we overmount the usually inaccessible "private" subdirectory with a
2277 * tmpfs that makes it accessible and is empty except for the submounts we do this for. */
2278
2279 private_root = strjoin(params->prefix[t], "/private")strjoin_real((params->prefix[t]), "/private", ((void*)0));
2280 if (!private_root) {
2281 r = -ENOMEM12;
2282 goto finish;
2283 }
2284
2285 r = strv_consume(&empty_directories, private_root);
2286 if (r < 0)
2287 goto finish;
2288 }
2289
2290 STRV_FOREACH(suffix, context->directories[t].paths)for ((suffix) = (context->directories[t].paths); (suffix) &&
*(suffix); (suffix)++)
{
2291 char *s, *d;
2292
2293 if (context->dynamic_user &&
2294 !IN_SET(t, EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION
})/sizeof(int)]; switch(t) { case EXEC_DIRECTORY_RUNTIME: case
EXEC_DIRECTORY_CONFIGURATION: _found = 1; break; default: break
; } _found; })
)
2295 s = strjoin(params->prefix[t], "/private/", *suffix)strjoin_real((params->prefix[t]), "/private/", *suffix, ((
void*)0))
;
2296 else
2297 s = strjoin(params->prefix[t], "/", *suffix)strjoin_real((params->prefix[t]), "/", *suffix, ((void*)0)
)
;
2298 if (!s) {
2299 r = -ENOMEM12;
2300 goto finish;
2301 }
2302
2303 if (context->dynamic_user &&
2304 !IN_SET(t, EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION
})/sizeof(int)]; switch(t) { case EXEC_DIRECTORY_RUNTIME: case
EXEC_DIRECTORY_CONFIGURATION: _found = 1; break; default: break
; } _found; })
&&
2305 (context->root_directory || context->root_image))
2306 /* When RootDirectory= or RootImage= are set, then the symbolic link to the private
2307 * directory is not created on the root directory. So, let's bind-mount the directory
2308 * on the 'non-private' place. */
2309 d = strjoin(params->prefix[t], "/", *suffix)strjoin_real((params->prefix[t]), "/", *suffix, ((void*)0)
)
;
2310 else
2311 d = strdup(s);
2312 if (!d) {
2313 free(s);
2314 r = -ENOMEM12;
2315 goto finish;
2316 }
2317
2318 bind_mounts[h++] = (BindMount) {
2319 .source = s,
2320 .destination = d,
2321 .read_only = false0,
2322 .recursive = true1,
2323 .ignore_enoent = false0,
2324 };
2325 }
2326 }
2327
2328 assert(h == n)do { if ((__builtin_expect(!!(!(h == n)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("h == n"), "../src/core/execute.c", 2328
, __PRETTY_FUNCTION__); } while (0)
;
2329
2330 *ret_bind_mounts = bind_mounts;
2331 *ret_n_bind_mounts = n;
2332 *ret_empty_directories = TAKE_PTR(empty_directories)({ typeof(empty_directories) _ptr_ = (empty_directories); (empty_directories
) = ((void*)0); _ptr_; })
;
2333
2334 return (int) n;
2335
2336finish:
2337 bind_mount_free_many(bind_mounts, h);
2338 return r;
2339}
2340
2341static int apply_mount_namespace(
2342 const Unit *u,
2343 const ExecCommand *command,
2344 const ExecContext *context,
2345 const ExecParameters *params,
2346 const ExecRuntime *runtime) {
2347
2348 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **empty_directories = NULL((void*)0);
2349 char *tmp = NULL((void*)0), *var = NULL((void*)0);
2350 const char *root_dir = NULL((void*)0), *root_image = NULL((void*)0);
2351 NamespaceInfo ns_info;
2352 bool_Bool needs_sandboxing;
2353 BindMount *bind_mounts = NULL((void*)0);
2354 size_t n_bind_mounts = 0;
2355 int r;
2356
2357 assert(context)do { if ((__builtin_expect(!!(!(context)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("context"), "../src/core/execute.c", 2357
, __PRETTY_FUNCTION__); } while (0)
;
2358
2359 /* The runtime struct only contains the parent of the private /tmp,
2360 * which is non-accessible to world users. Inside of it there's a /tmp
2361 * that is sticky, and that's the one we want to use here. */
2362
2363 if (context->private_tmp && runtime) {
2364 if (runtime->tmp_dir)
2365 tmp = strjoina(runtime->tmp_dir, "/tmp")({ const char *_appendees_[] = { runtime->tmp_dir, "/tmp" }
; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0
; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
2366 if (runtime->var_tmp_dir)
2367 var = strjoina(runtime->var_tmp_dir, "/tmp")({ const char *_appendees_[] = { runtime->var_tmp_dir, "/tmp"
}; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ =
0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
2368 }
2369
2370 if (params->flags & EXEC_APPLY_CHROOT) {
2371 root_image = context->root_image;
2372
2373 if (!root_image)
2374 root_dir = context->root_directory;
2375 }
2376
2377 r = compile_bind_mounts(context, params, &bind_mounts, &n_bind_mounts, &empty_directories);
2378 if (r < 0)
2379 return r;
2380
2381 needs_sandboxing = (params->flags & EXEC_APPLY_SANDBOXING) && !(command->flags & EXEC_COMMAND_FULLY_PRIVILEGED);
2382 if (needs_sandboxing)
2383 ns_info = (NamespaceInfo) {
2384 .ignore_protect_paths = false0,
2385 .private_dev = context->private_devices,
2386 .protect_control_groups = context->protect_control_groups,
2387 .protect_kernel_tunables = context->protect_kernel_tunables,
2388 .protect_kernel_modules = context->protect_kernel_modules,
2389 .mount_apivfs = context->mount_apivfs,
2390 .private_mounts = context->private_mounts,
2391 };
2392 else if (!context->dynamic_user && root_dir)
2393 /*
2394 * If DynamicUser=no and RootDirectory= is set then lets pass a relaxed
2395 * sandbox info, otherwise enforce it, don't ignore protected paths and
2396 * fail if we are enable to apply the sandbox inside the mount namespace.
2397 */
2398 ns_info = (NamespaceInfo) {
2399 .ignore_protect_paths = true1,
2400 };
2401 else
2402 ns_info = (NamespaceInfo) {};
2403
2404 r = setup_namespace(root_dir, root_image,
2405 &ns_info, context->read_write_paths,
2406 needs_sandboxing ? context->read_only_paths : NULL((void*)0),
2407 needs_sandboxing ? context->inaccessible_paths : NULL((void*)0),
2408 empty_directories,
2409 bind_mounts,
2410 n_bind_mounts,
2411 context->temporary_filesystems,
2412 context->n_temporary_filesystems,
2413 tmp,
2414 var,
2415 needs_sandboxing ? context->protect_home : PROTECT_HOME_NO,
2416 needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO,
2417 context->mount_flags,
2418 DISSECT_IMAGE_DISCARD_ON_LOOP);
2419
2420 bind_mount_free_many(bind_mounts, n_bind_mounts);
2421
2422 /* If we couldn't set up the namespace this is probably due to a
2423 * missing capability. In this case, silently proceeed. */
2424 if (IN_SET(r, -EPERM, -EACCES)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){-1, -13})/sizeof(int)]; switch(r) { case
-1: case -13: _found = 1; break; default: break; } _found; }
)
) {
2425 log_unit_debug_errno(u, r, "Failed to set up namespace, assuming containerized execution, ignoring: %m")({ const Unit *_u = (u); _u ? log_object_internal(7, r, "../src/core/execute.c"
, 2425, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to set up namespace, assuming containerized execution, ignoring: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7
))), r, "../src/core/execute.c", 2425, __func__, "Failed to set up namespace, assuming containerized execution, ignoring: %m"
); })
;
2426 return 0;
2427 }
2428
2429 return r;
2430}
2431
2432static int apply_working_directory(
2433 const ExecContext *context,
2434 const ExecParameters *params,
2435 const char *home,
2436 const bool_Bool needs_mount_ns,
2437 int *exit_status) {
2438
2439 const char *d, *wd;
2440
2441 assert(context)do { if ((__builtin_expect(!!(!(context)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("context"), "../src/core/execute.c", 2441
, __PRETTY_FUNCTION__); } while (0)
;
2442 assert(exit_status)do { if ((__builtin_expect(!!(!(exit_status)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("exit_status"), "../src/core/execute.c",
2442, __PRETTY_FUNCTION__); } while (0)
;
2443
2444 if (context->working_directory_home) {
2445
2446 if (!home) {
2447 *exit_status = EXIT_CHDIR;
2448 return -ENXIO6;
2449 }
2450
2451 wd = home;
2452
2453 } else if (context->working_directory)
2454 wd = context->working_directory;
2455 else
2456 wd = "/";
2457
2458 if (params->flags & EXEC_APPLY_CHROOT) {
2459 if (!needs_mount_ns && context->root_directory)
2460 if (chroot(context->root_directory) < 0) {
2461 *exit_status = EXIT_CHROOT;
2462 return -errno(*__errno_location ());
2463 }
2464
2465 d = wd;
2466 } else
2467 d = prefix_roota(context->root_directory, wd)({ const char* _path = (wd), *_root = (context->root_directory
), *_ret; char *_p, *_n; size_t _l; while (_path[0] == '/' &&
_path[1] == '/') _path ++; if (empty_or_root(_root)) _ret = _path
; else { _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca
(_l); _p = stpcpy(_n, _root); while (_p > _n && _p
[-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy
(_p, _path); _ret = _n; } _ret; })
;
2468
2469 if (chdir(d) < 0 && !context->working_directory_missing_ok) {
2470 *exit_status = EXIT_CHDIR;
2471 return -errno(*__errno_location ());
2472 }
2473
2474 return 0;
2475}
2476
2477static int setup_keyring(
2478 const Unit *u,
2479 const ExecContext *context,
2480 const ExecParameters *p,
2481 uid_t uid, gid_t gid) {
2482
2483 key_serial_t keyring;
2484 int r = 0;
2485 uid_t saved_uid;
2486 gid_t saved_gid;
2487
2488 assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("u"), "../src/core/execute.c", 2488, __PRETTY_FUNCTION__
); } while (0)
;
2489 assert(context)do { if ((__builtin_expect(!!(!(context)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("context"), "../src/core/execute.c", 2489
, __PRETTY_FUNCTION__); } while (0)
;
2490 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/core/execute.c", 2490, __PRETTY_FUNCTION__
); } while (0)
;
2491
2492 /* Let's set up a new per-service "session" kernel keyring for each system service. This has the benefit that
2493 * each service runs with its own keyring shared among all processes of the service, but with no hook-up beyond
2494 * that scope, and in particular no link to the per-UID keyring. If we don't do this the keyring will be
2495 * automatically created on-demand and then linked to the per-UID keyring, by the kernel. The kernel's built-in
2496 * on-demand behaviour is very appropriate for login users, but probably not so much for system services, where
2497 * UIDs are not necessarily specific to a service but reused (at least in the case of UID 0). */
2498
2499 if (!(p->flags & EXEC_NEW_KEYRING))
2500 return 0;
2501
2502 if (context->keyring_mode == EXEC_KEYRING_INHERIT)
2503 return 0;
2504
2505 /* Acquiring a reference to the user keyring is nasty. We briefly change identity in order to get things set up
2506 * properly by the kernel. If we don't do that then we can't create it atomically, and that sucks for parallel
2507 * execution. This mimics what pam_keyinit does, too. Setting up session keyring, to be owned by the right user
2508 * & group is just as nasty as acquiring a reference to the user keyring. */
2509
2510 saved_uid = getuid();
2511 saved_gid = getgid();
2512
2513 if (gid_is_valid(gid) && gid != saved_gid) {
2514 if (setregid(gid, -1) < 0)
2515 return log_unit_error_errno(u, errno, "Failed to change GID for user keyring: %m")({ const Unit *_u = (u); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 2515, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to change GID for user keyring: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 2515, __func__
, "Failed to change GID for user keyring: %m"); })
;
2516 }
2517
2518 if (uid_is_valid(uid) && uid != saved_uid) {
2519 if (setreuid(uid, -1) < 0) {
2520 r = log_unit_error_errno(u, errno, "Failed to change UID for user keyring: %m")({ const Unit *_u = (u); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 2520, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to change UID for user keyring: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 2520, __func__
, "Failed to change UID for user keyring: %m"); })
;
2521 goto out;
2522 }
2523 }
2524
2525 keyring = keyctlmissing_keyctl(KEYCTL_JOIN_SESSION_KEYRING1, 0, 0, 0, 0);
2526 if (keyring == -1) {
2527 if (errno(*__errno_location ()) == ENOSYS38)
2528 log_unit_debug_errno(u, errno, "Kernel keyring not supported, ignoring.")({ const Unit *_u = (u); _u ? log_object_internal(7, (*__errno_location
()), "../src/core/execute.c", 2528, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Kernel keyring not supported, ignoring."
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7
))), (*__errno_location ()), "../src/core/execute.c", 2528, __func__
, "Kernel keyring not supported, ignoring."); })
;
2529 else if (IN_SET(errno, EACCES, EPERM)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){13, 1})/sizeof(int)]; switch((*__errno_location
())) { case 13: case 1: _found = 1; break; default: break; }
_found; })
)
2530 log_unit_debug_errno(u, errno, "Kernel keyring access prohibited, ignoring.")({ const Unit *_u = (u); _u ? log_object_internal(7, (*__errno_location
()), "../src/core/execute.c", 2530, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Kernel keyring access prohibited, ignoring."
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7
))), (*__errno_location ()), "../src/core/execute.c", 2530, __func__
, "Kernel keyring access prohibited, ignoring."); })
;
2531 else if (errno(*__errno_location ()) == EDQUOT122)
2532 log_unit_debug_errno(u, errno, "Out of kernel keyrings to allocate, ignoring.")({ const Unit *_u = (u); _u ? log_object_internal(7, (*__errno_location
()), "../src/core/execute.c", 2532, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Out of kernel keyrings to allocate, ignoring."
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7
))), (*__errno_location ()), "../src/core/execute.c", 2532, __func__
, "Out of kernel keyrings to allocate, ignoring."); })
;
2533 else
2534 r = log_unit_error_errno(u, errno, "Setting up kernel keyring failed: %m")({ const Unit *_u = (u); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 2534, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Setting up kernel keyring failed: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 2534, __func__
, "Setting up kernel keyring failed: %m"); })
;
2535
2536 goto out;
2537 }
2538
2539 /* When requested link the user keyring into the session keyring. */
2540 if (context->keyring_mode == EXEC_KEYRING_SHARED) {
2541
2542 if (keyctlmissing_keyctl(KEYCTL_LINK8,
2543 KEY_SPEC_USER_KEYRING-4,
2544 KEY_SPEC_SESSION_KEYRING-3, 0, 0) < 0) {
2545 r = log_unit_error_errno(u, errno, "Failed to link user keyring into session keyring: %m")({ const Unit *_u = (u); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 2545, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to link user keyring into session keyring: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 2545, __func__
, "Failed to link user keyring into session keyring: %m"); })
;
2546 goto out;
2547 }
2548 }
2549
2550 /* Restore uid/gid back */
2551 if (uid_is_valid(uid) && uid != saved_uid) {
2552 if (setreuid(saved_uid, -1) < 0) {
2553 r = log_unit_error_errno(u, errno, "Failed to change UID back for user keyring: %m")({ const Unit *_u = (u); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 2553, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to change UID back for user keyring: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 2553, __func__
, "Failed to change UID back for user keyring: %m"); })
;
2554 goto out;
2555 }
2556 }
2557
2558 if (gid_is_valid(gid) && gid != saved_gid) {
2559 if (setregid(saved_gid, -1) < 0)
2560 return log_unit_error_errno(u, errno, "Failed to change GID back for user keyring: %m")({ const Unit *_u = (u); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 2560, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to change GID back for user keyring: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 2560, __func__
, "Failed to change GID back for user keyring: %m"); })
;
2561 }
2562
2563 /* Populate they keyring with the invocation ID by default, as original saved_uid. */
2564 if (!sd_id128_is_null(u->invocation_id)) {
2565 key_serial_t key;
2566
2567 key = add_keymissing_add_key("user", "invocation_id", &u->invocation_id, sizeof(u->invocation_id), KEY_SPEC_SESSION_KEYRING-3);
2568 if (key == -1)
2569 log_unit_debug_errno(u, errno, "Failed to add invocation ID to keyring, ignoring: %m")({ const Unit *_u = (u); _u ? log_object_internal(7, (*__errno_location
()), "../src/core/execute.c", 2569, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to add invocation ID to keyring, ignoring: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7
))), (*__errno_location ()), "../src/core/execute.c", 2569, __func__
, "Failed to add invocation ID to keyring, ignoring: %m"); })
;
2570 else {
2571 if (keyctlmissing_keyctl(KEYCTL_SETPERM5, key,
2572 KEY_POS_VIEW0x01000000|KEY_POS_READ0x02000000|KEY_POS_SEARCH0x08000000|
2573 KEY_USR_VIEW0x00010000|KEY_USR_READ0x00020000|KEY_USR_SEARCH0x00080000, 0, 0) < 0)
2574 r = log_unit_error_errno(u, errno, "Failed to restrict invocation ID permission: %m")({ const Unit *_u = (u); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 2574, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to restrict invocation ID permission: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 2574, __func__
, "Failed to restrict invocation ID permission: %m"); })
;
2575 }
2576 }
2577
2578out:
2579 /* Revert back uid & gid for the the last time, and exit */
2580 /* no extra logging, as only the first already reported error matters */
2581 if (getuid() != saved_uid)
2582 (void) setreuid(saved_uid, -1);
2583
2584 if (getgid() != saved_gid)
2585 (void) setregid(saved_gid, -1);
2586
2587 return r;
2588}
2589
2590static void append_socket_pair(int *array, size_t *n, const int pair[2]) {
2591 assert(array)do { if ((__builtin_expect(!!(!(array)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("array"), "../src/core/execute.c", 2591,
__PRETTY_FUNCTION__); } while (0)
;
2592 assert(n)do { if ((__builtin_expect(!!(!(n)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("n"), "../src/core/execute.c", 2592, __PRETTY_FUNCTION__
); } while (0)
;
2593
2594 if (!pair)
2595 return;
2596
2597 if (pair[0] >= 0)
2598 array[(*n)++] = pair[0];
2599 if (pair[1] >= 0)
2600 array[(*n)++] = pair[1];
2601}
2602
2603static int close_remaining_fds(
2604 const ExecParameters *params,
2605 const ExecRuntime *runtime,
2606 const DynamicCreds *dcreds,
2607 int user_lookup_fd,
2608 int socket_fd,
2609 int exec_fd,
2610 int *fds, size_t n_fds) {
2611
2612 size_t n_dont_close = 0;
2613 int dont_close[n_fds + 12];
2614
2615 assert(params)do { if ((__builtin_expect(!!(!(params)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("params"), "../src/core/execute.c", 2615
, __PRETTY_FUNCTION__); } while (0)
;
2616
2617 if (params->stdin_fd >= 0)
2618 dont_close[n_dont_close++] = params->stdin_fd;
2619 if (params->stdout_fd >= 0)
2620 dont_close[n_dont_close++] = params->stdout_fd;
2621 if (params->stderr_fd >= 0)
2622 dont_close[n_dont_close++] = params->stderr_fd;
2623
2624 if (socket_fd >= 0)
2625 dont_close[n_dont_close++] = socket_fd;
2626 if (exec_fd >= 0)
2627 dont_close[n_dont_close++] = exec_fd;
2628 if (n_fds > 0) {
2629 memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
2630 n_dont_close += n_fds;
2631 }
2632
2633 if (runtime)
2634 append_socket_pair(dont_close, &n_dont_close, runtime->netns_storage_socket);
2635
2636 if (dcreds) {
2637 if (dcreds->user)
2638 append_socket_pair(dont_close, &n_dont_close, dcreds->user->storage_socket);
2639 if (dcreds->group)
2640 append_socket_pair(dont_close, &n_dont_close, dcreds->group->storage_socket);
2641 }
2642
2643 if (user_lookup_fd >= 0)
2644 dont_close[n_dont_close++] = user_lookup_fd;
2645
2646 return close_all_fds(dont_close, n_dont_close);
2647}
2648
2649static int send_user_lookup(
2650 Unit *unit,
2651 int user_lookup_fd,
2652 uid_t uid,
2653 gid_t gid) {
2654
2655 assert(unit)do { if ((__builtin_expect(!!(!(unit)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("unit"), "../src/core/execute.c", 2655, __PRETTY_FUNCTION__
); } while (0)
;
2656
2657 /* Send the resolved UID/GID to PID 1 after we learnt it. We send a single datagram, containing the UID/GID
2658 * data as well as the unit name. Note that we suppress sending this if no user/group to resolve was
2659 * specified. */
2660
2661 if (user_lookup_fd < 0)
2662 return 0;
2663
2664 if (!uid_is_valid(uid) && !gid_is_valid(gid))
2665 return 0;
2666
2667 if (writev(user_lookup_fd,
2668 (struct iovec[]) {
2669 IOVEC_INIT(&uid, sizeof(uid)){ .iov_base = (&uid), .iov_len = (sizeof(uid)) },
2670 IOVEC_INIT(&gid, sizeof(gid)){ .iov_base = (&gid), .iov_len = (sizeof(gid)) },
2671 IOVEC_INIT_STRING(unit->id){ .iov_base = ((char*) unit->id), .iov_len = (strlen(unit->
id)) }
}, 3) < 0)
2672 return -errno(*__errno_location ());
2673
2674 return 0;
2675}
2676
2677static int acquire_home(const ExecContext *c, uid_t uid, const char** home, char **buf) {
2678 int r;
2679
2680 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 2680, __PRETTY_FUNCTION__
); } while (0)
;
2681 assert(home)do { if ((__builtin_expect(!!(!(home)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("home"), "../src/core/execute.c", 2681, __PRETTY_FUNCTION__
); } while (0)
;
2682 assert(buf)do { if ((__builtin_expect(!!(!(buf)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("buf"), "../src/core/execute.c", 2682, __PRETTY_FUNCTION__
); } while (0)
;
2683
2684 /* If WorkingDirectory=~ is set, try to acquire a usable home directory. */
2685
2686 if (*home)
2687 return 0;
2688
2689 if (!c->working_directory_home)
2690 return 0;
2691
2692 if (uid == 0) {
2693 /* Hardcode /root as home directory for UID 0 */
2694 *home = "/root";
2695 return 1;
2696 }
2697
2698 r = get_home_dir(buf);
2699 if (r < 0)
2700 return r;
2701
2702 *home = *buf;
2703 return 1;
2704}
2705
2706static int compile_suggested_paths(const ExecContext *c, const ExecParameters *p, char ***ret) {
2707 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char ** list = NULL((void*)0);
2708 ExecDirectoryType t;
2709 int r;
2710
2711 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 2711, __PRETTY_FUNCTION__
); } while (0)
;
2712 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/core/execute.c", 2712, __PRETTY_FUNCTION__
); } while (0)
;
2713 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/core/execute.c", 2713, __PRETTY_FUNCTION__
); } while (0)
;
2714
2715 assert(c->dynamic_user)do { if ((__builtin_expect(!!(!(c->dynamic_user)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c->dynamic_user"), "../src/core/execute.c"
, 2715, __PRETTY_FUNCTION__); } while (0)
;
2716
2717 /* Compile a list of paths that it might make sense to read the owning UID from to use as initial candidate for
2718 * dynamic UID allocation, in order to save us from doing costly recursive chown()s of the special
2719 * directories. */
2720
2721 for (t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
2722 char **i;
2723
2724 if (t == EXEC_DIRECTORY_CONFIGURATION)
2725 continue;
2726
2727 if (!p->prefix[t])
2728 continue;
2729
2730 STRV_FOREACH(i, c->directories[t].paths)for ((i) = (c->directories[t].paths); (i) && *(i);
(i)++)
{
2731 char *e;
2732
2733 if (t == EXEC_DIRECTORY_RUNTIME)
2734 e = strjoin(p->prefix[t], "/", *i)strjoin_real((p->prefix[t]), "/", *i, ((void*)0));
2735 else
2736 e = strjoin(p->prefix[t], "/private/", *i)strjoin_real((p->prefix[t]), "/private/", *i, ((void*)0));
2737 if (!e)
2738 return -ENOMEM12;
2739
2740 r = strv_consume(&list, e);
2741 if (r < 0)
2742 return r;
2743 }
2744 }
2745
2746 *ret = TAKE_PTR(list)({ typeof(list) _ptr_ = (list); (list) = ((void*)0); _ptr_; }
)
;
2747
2748 return 0;
2749}
2750
2751static char *exec_command_line(char **argv);
2752
2753static int exec_context_cpu_affinity_from_numa(const ExecContext *c, CPUSet *ret) {
2754 _cleanup_(cpu_set_reset)__attribute__((cleanup(cpu_set_reset))) CPUSet s = {};
2755 int r;
2756
2757 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 2757, __PRETTY_FUNCTION__
); } while (0)
;
2758 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/core/execute.c", 2758, __PRETTY_FUNCTION__
); } while (0)
;
2759
2760 if (!c->numa_policy.nodes.set) {
2761 log_debug("Can't derive CPU affinity mask from NUMA mask because NUMA mask is not set, ignoring")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/core/execute.c", 2761, __func__, "Can't derive CPU affinity mask from NUMA mask because NUMA mask is not set, ignoring"
) : -abs(_e); })
;
2762 return 0;
2763 }
2764
2765 r = numa_to_cpu_set(&c->numa_policy, &s);
2766 if (r < 0)
2767 return r;
2768
2769 cpu_set_reset(ret);
2770
2771 return cpu_set_add_all(ret, &s);
2772}
2773
2774bool_Bool exec_context_get_cpu_affinity_from_numa(const ExecContext *c) {
2775 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 2775, __PRETTY_FUNCTION__
); } while (0)
;
2776
2777 return c->cpu_affinity_from_numa;
2778}
2779
2780static int exec_child(
2781 Unit *unit,
2782 const ExecCommand *command,
2783 const ExecContext *context,
2784 const ExecParameters *params,
2785 ExecRuntime *runtime,
2786 DynamicCreds *dcreds,
2787 char **argv,
2788 int socket_fd,
2789 int named_iofds[3],
2790 int *fds,
2791 size_t n_socket_fds,
2792 size_t n_storage_fds,
2793 char **files_env,
2794 int user_lookup_fd,
2795 int *exit_status) {
2796
2797 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **our_env = NULL((void*)0), **pass_env = NULL((void*)0), **accum_env = NULL((void*)0), **final_argv = NULL((void*)0);
2798 int *fds_with_exec_fd, n_fds_with_exec_fd, r, ngids = 0, exec_fd = -1;
2799 _cleanup_free___attribute__((cleanup(freep))) gid_t *supplementary_gids = NULL((void*)0);
2800 const char *username = NULL((void*)0), *groupname = NULL((void*)0);
2801 _cleanup_free___attribute__((cleanup(freep))) char *home_buffer = NULL((void*)0);
2802 const char *home = NULL((void*)0), *shell = NULL((void*)0);
2803 dev_t journal_stream_dev = 0;
2804 ino_t journal_stream_ino = 0;
2805 bool_Bool needs_sandboxing, /* Do we need to set up full sandboxing? (i.e. all namespacing, all MAC stuff, caps, yadda yadda */
2806 needs_setuid, /* Do we need to do the actual setresuid()/setresgid() calls? */
2807 needs_mount_namespace, /* Do we need to set up a mount namespace for this kernel? */
2808 needs_ambient_hack; /* Do we need to apply the ambient capabilities hack? */
2809#if HAVE_SELINUX1
2810 _cleanup_free___attribute__((cleanup(freep))) char *mac_selinux_context_net = NULL((void*)0);
2811 bool_Bool use_selinux = false0;
2812#endif
2813#if ENABLE_SMACK1
2814 bool_Bool use_smack = false0;
2815#endif
2816#if HAVE_APPARMOR0
2817 bool_Bool use_apparmor = false0;
2818#endif
2819 uid_t uid = UID_INVALID((uid_t) -1);
2820 gid_t gid = GID_INVALID((gid_t) -1);
2821 size_t n_fds;
2822 ExecDirectoryType dt;
2823 int secure_bits;
2824
2825 assert(unit)do { if ((__builtin_expect(!!(!(unit)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("unit"), "../src/core/execute.c", 2825, __PRETTY_FUNCTION__
); } while (0)
;
2826 assert(command)do { if ((__builtin_expect(!!(!(command)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("command"), "../src/core/execute.c", 2826
, __PRETTY_FUNCTION__); } while (0)
;
2827 assert(context)do { if ((__builtin_expect(!!(!(context)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("context"), "../src/core/execute.c", 2827
, __PRETTY_FUNCTION__); } while (0)
;
2828 assert(params)do { if ((__builtin_expect(!!(!(params)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("params"), "../src/core/execute.c", 2828
, __PRETTY_FUNCTION__); } while (0)
;
2829 assert(exit_status)do { if ((__builtin_expect(!!(!(exit_status)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("exit_status"), "../src/core/execute.c",
2829, __PRETTY_FUNCTION__); } while (0)
;
2830
2831 rename_process_from_path(command->path);
2832
2833 /* We reset exactly these signals, since they are the
2834 * only ones we set to SIG_IGN in the main daemon. All
2835 * others we leave untouched because we set them to
2836 * SIG_DFL or a valid handler initially, both of which
2837 * will be demoted to SIG_DFL. */
2838 (void) default_signals(SIGNALS_CRASH_HANDLER11,4,8,7,3,6,
2839 SIGNALS_IGNORE13, -1);
2840
2841 if (context->ignore_sigpipe)
2842 (void) ignore_signals(SIGPIPE13, -1);
2843
2844 r = reset_signal_mask();
2845 if (r < 0) {
2846 *exit_status = EXIT_SIGNAL_MASK;
2847 return log_unit_error_errno(unit, r, "Failed to set process signal mask: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 2847, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to set process signal mask: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 2847, __func__, "Failed to set process signal mask: %m"); }
)
;
2848 }
2849
2850 if (params->idle_pipe)
2851 do_idle_pipe_dance(params->idle_pipe);
2852
2853 /* Close fds we don't need very early to make sure we don't block init reexecution because it cannot bind its
2854 * sockets. Among the fds we close are the logging fds, and we want to keep them closed, so that we don't have
2855 * any fds open we don't really want open during the transition. In order to make logging work, we switch the
2856 * log subsystem into open_when_needed mode, so that it reopens the logs on every single log call. */
2857
2858 log_forget_fds();
2859 log_set_open_when_needed(true1);
2860
2861 /* In case anything used libc syslog(), close this here, too */
2862 closelog();
2863
2864 n_fds = n_socket_fds + n_storage_fds;
2865 r = close_remaining_fds(params, runtime, dcreds, user_lookup_fd, socket_fd, params->exec_fd, fds, n_fds);
2866 if (r < 0) {
2867 *exit_status = EXIT_FDS;
2868 return log_unit_error_errno(unit, r, "Failed to close unwanted file descriptors: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 2868, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to close unwanted file descriptors: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 2868, __func__, "Failed to close unwanted file descriptors: %m"
); })
;
2869 }
2870
2871 if (!context->same_pgrp)
2872 if (setsid() < 0) {
2873 *exit_status = EXIT_SETSID;
2874 return log_unit_error_errno(unit, errno, "Failed to create new process session: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 2874, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to create new process session: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 2874, __func__
, "Failed to create new process session: %m"); })
;
2875 }
2876
2877 exec_context_tty_reset(context, params);
2878
2879 if (unit_shall_confirm_spawn(unit)) {
2880 const char *vc = params->confirm_spawn;
2881 _cleanup_free___attribute__((cleanup(freep))) char *cmdline = NULL((void*)0);
2882
2883 cmdline = exec_command_line(argv);
2884 if (!cmdline) {
2885 *exit_status = EXIT_MEMORY;
2886 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/core/execute.c", 2886
, __func__)
;
2887 }
2888
2889 r = ask_for_confirmation(vc, unit, cmdline);
2890 if (r != CONFIRM_EXECUTE) {
2891 if (r == CONFIRM_PRETEND_SUCCESS) {
2892 *exit_status = EXIT_SUCCESS0;
2893 return 0;
2894 }
2895 *exit_status = EXIT_CONFIRM;
2896 log_unit_error(unit, "Execution cancelled by the user")({ const Unit *_u = (unit); _u ? log_object_internal(3, 0, "../src/core/execute.c"
, 2896, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Execution cancelled by the user") : log_internal_realm(((LOG_REALM_SYSTEMD
) << 10 | ((3))), 0, "../src/core/execute.c", 2896, __func__
, "Execution cancelled by the user"); })
;
2897 return -ECANCELED125;
2898 }
2899 }
2900
2901 if (context->dynamic_user && dcreds) {
2902 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **suggested_paths = NULL((void*)0);
2903
2904 /* Make sure we bypass our own NSS module for any NSS checks */
2905 if (putenv((char*) "SYSTEMD_NSS_DYNAMIC_BYPASS=1") != 0) {
2906 *exit_status = EXIT_USER;
2907 return log_unit_error_errno(unit, errno, "Failed to update environment: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 2907, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to update environment: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 2907, __func__
, "Failed to update environment: %m"); })
;
2908 }
2909
2910 r = compile_suggested_paths(context, params, &suggested_paths);
2911 if (r < 0) {
2912 *exit_status = EXIT_MEMORY;
2913 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/core/execute.c", 2913
, __func__)
;
2914 }
2915
2916 r = dynamic_creds_realize(dcreds, suggested_paths, &uid, &gid);
2917 if (r < 0) {
2918 *exit_status = EXIT_USER;
2919 if (r == -EILSEQ84) {
2920 log_unit_error(unit, "Failed to update dynamic user credentials: User or group with specified name already exists.")({ const Unit *_u = (unit); _u ? log_object_internal(3, 0, "../src/core/execute.c"
, 2920, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to update dynamic user credentials: User or group with specified name already exists."
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), 0, "../src/core/execute.c", 2920, __func__, "Failed to update dynamic user credentials: User or group with specified name already exists."
); })
;
2921 return -EOPNOTSUPP95;
2922 }
2923 return log_unit_error_errno(unit, r, "Failed to update dynamic user credentials: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 2923, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to update dynamic user credentials: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 2923, __func__, "Failed to update dynamic user credentials: %m"
); })
;
2924 }
2925
2926 if (!uid_is_valid(uid)) {
2927 *exit_status = EXIT_USER;
2928 log_unit_error(unit, "UID validation failed for \""UID_FMT"\"", uid)({ const Unit *_u = (unit); _u ? log_object_internal(3, 0, "../src/core/execute.c"
, 2928, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "UID validation failed for \"""%" "u""\"", uid) : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), 0, "../src/core/execute.c"
, 2928, __func__, "UID validation failed for \"""%" "u""\"", uid
); })
;
2929 return -ESRCH3;
2930 }
2931
2932 if (!gid_is_valid(gid)) {
2933 *exit_status = EXIT_USER;
2934 log_unit_error(unit, "GID validation failed for \""GID_FMT"\"", gid)({ const Unit *_u = (unit); _u ? log_object_internal(3, 0, "../src/core/execute.c"
, 2934, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "GID validation failed for \"""%" "u""\"", gid) : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), 0, "../src/core/execute.c"
, 2934, __func__, "GID validation failed for \"""%" "u""\"", gid
); })
;
2935 return -ESRCH3;
2936 }
2937
2938 if (dcreds->user)
2939 username = dcreds->user->name;
2940
2941 } else {
2942 r = get_fixed_user(context, &username, &uid, &gid, &home, &shell);
2943 if (r < 0) {
2944 *exit_status = EXIT_USER;
2945 return log_unit_error_errno(unit, r, "Failed to determine user credentials: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 2945, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to determine user credentials: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 2945, __func__, "Failed to determine user credentials: %m")
; })
;
2946 }
2947
2948 r = get_fixed_group(context, &groupname, &gid);
2949 if (r < 0) {
2950 *exit_status = EXIT_GROUP;
2951 return log_unit_error_errno(unit, r, "Failed to determine group credentials: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 2951, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to determine group credentials: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 2951, __func__, "Failed to determine group credentials: %m"
); })
;
2952 }
2953 }
2954
2955 /* Initialize user supplementary groups and get SupplementaryGroups= ones */
2956 r = get_supplementary_groups(context, username, groupname, gid,
2957 &supplementary_gids, &ngids);
2958 if (r < 0) {
2959 *exit_status = EXIT_GROUP;
2960 return log_unit_error_errno(unit, r, "Failed to determine supplementary groups: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 2960, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to determine supplementary groups: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 2960, __func__, "Failed to determine supplementary groups: %m"
); })
;
2961 }
2962
2963 r = send_user_lookup(unit, user_lookup_fd, uid, gid);
2964 if (r < 0) {
2965 *exit_status = EXIT_USER;
2966 return log_unit_error_errno(unit, r, "Failed to send user credentials to PID1: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 2966, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to send user credentials to PID1: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 2966, __func__, "Failed to send user credentials to PID1: %m"
); })
;
2967 }
2968
2969 user_lookup_fd = safe_close(user_lookup_fd);
2970
2971 r = acquire_home(context, uid, &home, &home_buffer);
2972 if (r < 0) {
2973 *exit_status = EXIT_CHDIR;
2974 return log_unit_error_errno(unit, r, "Failed to determine $HOME for user: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 2974, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to determine $HOME for user: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 2974, __func__, "Failed to determine $HOME for user: %m"); }
)
;
2975 }
2976
2977 /* If a socket is connected to STDIN/STDOUT/STDERR, we
2978 * must sure to drop O_NONBLOCK */
2979 if (socket_fd >= 0)
2980 (void) fd_nonblock(socket_fd, false0);
2981
2982 r = setup_input(context, params, socket_fd, named_iofds);
2983 if (r < 0) {
2984 *exit_status = EXIT_STDIN;
2985 return log_unit_error_errno(unit, r, "Failed to set up standard input: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 2985, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to set up standard input: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 2985, __func__, "Failed to set up standard input: %m"); })
;
2986 }
2987
2988 r = setup_output(unit, context, params, STDOUT_FILENO1, socket_fd, named_iofds, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
2989 if (r < 0) {
2990 *exit_status = EXIT_STDOUT;
2991 return log_unit_error_errno(unit, r, "Failed to set up standard output: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 2991, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to set up standard output: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 2991, __func__, "Failed to set up standard output: %m"); })
;
2992 }
2993
2994 r = setup_output(unit, context, params, STDERR_FILENO2, socket_fd, named_iofds, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
2995 if (r < 0) {
2996 *exit_status = EXIT_STDERR;
2997 return log_unit_error_errno(unit, r, "Failed to set up standard error output: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 2997, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to set up standard error output: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 2997, __func__, "Failed to set up standard error output: %m"
); })
;
2998 }
2999
3000 if (params->cgroup_path) {
3001 r = cg_attach_everywhere(params->cgroup_supported, params->cgroup_path, 0, NULL((void*)0), NULL((void*)0));
3002 if (r < 0) {
3003 *exit_status = EXIT_CGROUP;
3004 return log_unit_error_errno(unit, r, "Failed to attach to cgroup %s: %m", params->cgroup_path)({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3004, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to attach to cgroup %s: %m", params->cgroup_path
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), r, "../src/core/execute.c", 3004, __func__, "Failed to attach to cgroup %s: %m"
, params->cgroup_path); })
;
3005 }
3006 }
3007
3008 if (context->oom_score_adjust_set) {
3009 /* When we can't make this change due to EPERM, then let's silently skip over it. User namespaces
3010 * prohibit write access to this file, and we shouldn't trip up over that. */
3011 r = set_oom_score_adjust(context->oom_score_adjust);
3012 if (IN_SET(r, -EPERM, -EACCES)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){-1, -13})/sizeof(int)]; switch(r) { case
-1: case -13: _found = 1; break; default: break; } _found; }
)
)
3013 log_unit_debug_errno(unit, r, "Failed to adjust OOM setting, assuming containerized execution, ignoring: %m")({ const Unit *_u = (unit); _u ? log_object_internal(7, r, "../src/core/execute.c"
, 3013, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to adjust OOM setting, assuming containerized execution, ignoring: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7
))), r, "../src/core/execute.c", 3013, __func__, "Failed to adjust OOM setting, assuming containerized execution, ignoring: %m"
); })
;
3014 else if (r < 0) {
3015 *exit_status = EXIT_OOM_ADJUST;
3016 return log_unit_error_errno(unit, r, "Failed to adjust OOM setting: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3016, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to adjust OOM setting: %m") : log_internal_realm(((
LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3016, __func__, "Failed to adjust OOM setting: %m"); })
;
3017 }
3018 }
3019
3020 if (context->nice_set)
3021 if (setpriority(PRIO_PROCESSPRIO_PROCESS, 0, context->nice) < 0) {
3022 *exit_status = EXIT_NICE;
3023 return log_unit_error_errno(unit, errno, "Failed to set up process scheduling priority (nice level): %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 3023, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to set up process scheduling priority (nice level): %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 3023, __func__
, "Failed to set up process scheduling priority (nice level): %m"
); })
;
3024 }
3025
3026 if (context->cpu_sched_set) {
3027 struct sched_param param = {
3028 .sched_prioritysched_priority = context->cpu_sched_priority,
3029 };
3030
3031 r = sched_setscheduler(0,
3032 context->cpu_sched_policy |
3033 (context->cpu_sched_reset_on_fork ?
3034 SCHED_RESET_ON_FORK0x40000000 : 0),
3035 &param);
3036 if (r < 0) {
3037 *exit_status = EXIT_SETSCHEDULER;
3038 return log_unit_error_errno(unit, errno, "Failed to set up CPU scheduling: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 3038, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to set up CPU scheduling: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 3038, __func__
, "Failed to set up CPU scheduling: %m"); })
;
3039 }
3040 }
3041
3042 if (context->cpu_affinity_from_numa || context->cpu_set.set) {
3043 _cleanup_(cpu_set_reset)__attribute__((cleanup(cpu_set_reset))) CPUSet converted_cpu_set = {};
3044 const CPUSet *cpu_set;
3045
3046 if (context->cpu_affinity_from_numa) {
3047 r = exec_context_cpu_affinity_from_numa(context, &converted_cpu_set);
3048 if (r < 0) {
3049 *exit_status = EXIT_CPUAFFINITY;
3050 return log_unit_error_errno(unit, r, "Failed to derive CPU affinity mask from NUMA mask: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3050, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to derive CPU affinity mask from NUMA mask: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3050, __func__, "Failed to derive CPU affinity mask from NUMA mask: %m"
); })
;
3051 }
3052
3053 cpu_set = &converted_cpu_set;
3054 } else
3055 cpu_set = &context->cpu_set;
3056
3057 if (sched_setaffinity(0, cpu_set->allocated, cpu_set->set) < 0) {
3058 *exit_status = EXIT_CPUAFFINITY;
3059 return log_unit_error_errno(unit, errno, "Failed to set up CPU affinity: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 3059, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to set up CPU affinity: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 3059, __func__
, "Failed to set up CPU affinity: %m"); })
;
3060 }
3061 }
3062
3063 if (mpol_is_valid(numa_policy_get_type(&context->numa_policy))) {
3064 r = apply_numa_policy(&context->numa_policy);
3065 if (r == -EOPNOTSUPP95)
3066 log_unit_debug_errno(unit, r, "NUMA support not available, ignoring.")({ const Unit *_u = (unit); _u ? log_object_internal(7, r, "../src/core/execute.c"
, 3066, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "NUMA support not available, ignoring.") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((7))), r, "../src/core/execute.c"
, 3066, __func__, "NUMA support not available, ignoring."); }
)
;
3067 else if (r < 0) {
3068 *exit_status = EXIT_NUMA_POLICY;
3069 return log_unit_error_errno(unit, r, "Failed to set NUMA memory policy: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3069, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to set NUMA memory policy: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3069, __func__, "Failed to set NUMA memory policy: %m"); })
;
3070 }
3071 }
3072
3073 if (context->ioprio_set)
3074 if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
3075 *exit_status = EXIT_IOPRIO;
3076 return log_unit_error_errno(unit, errno, "Failed to set up IO scheduling priority: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 3076, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to set up IO scheduling priority: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 3076, __func__
, "Failed to set up IO scheduling priority: %m"); })
;
3077 }
3078
3079 if (context->timer_slack_nsec != NSEC_INFINITY((nsec_t) -1))
3080 if (prctl(PR_SET_TIMERSLACK29, context->timer_slack_nsec) < 0) {
3081 *exit_status = EXIT_TIMERSLACK;
3082 return log_unit_error_errno(unit, errno, "Failed to set up timer slack: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 3082, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to set up timer slack: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 3082, __func__
, "Failed to set up timer slack: %m"); })
;
3083 }
3084
3085 if (context->personality != PERSONALITY_INVALID0xffffffffLU) {
3086 r = safe_personality(context->personality);
3087 if (r < 0) {
3088 *exit_status = EXIT_PERSONALITY;
3089 return log_unit_error_errno(unit, r, "Failed to set up execution domain (personality): %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3089, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to set up execution domain (personality): %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3089, __func__, "Failed to set up execution domain (personality): %m"
); })
;
3090 }
3091 }
3092
3093 if (context->utmp_id)
3094 utmp_put_init_process(context->utmp_id, getpid_cached(), getsid(0),
3095 context->tty_path,
3096 context->utmp_mode == EXEC_UTMP_INIT ? INIT_PROCESS5 :
3097 context->utmp_mode == EXEC_UTMP_LOGIN ? LOGIN_PROCESS6 :
3098 USER_PROCESS7,
3099 username);
3100
3101 if (context->user) {
3102 r = chown_terminal(STDIN_FILENO0, uid);
3103 if (r < 0) {
3104 *exit_status = EXIT_STDIN;
3105 return log_unit_error_errno(unit, r, "Failed to change ownership of terminal: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3105, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to change ownership of terminal: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3105, __func__, "Failed to change ownership of terminal: %m"
); })
;
3106 }
3107 }
3108
3109 /* If delegation is enabled we'll pass ownership of the cgroup to the user of the new process. On cgroupsv1
3110 * this is only about systemd's own hierarchy, i.e. not the controller hierarchies, simply because that's not
3111 * safe. On cgroupsv2 there's only one hierarchy anyway, and delegation is safe there, hence in that case only
3112 * touch a single hierarchy too. */
3113 if (params->cgroup_path && context->user && (params->flags & EXEC_CGROUP_DELEGATE)) {
3114 r = cg_set_access(SYSTEMD_CGROUP_CONTROLLER"_systemd", params->cgroup_path, uid, gid);
3115 if (r < 0) {
3116 *exit_status = EXIT_CGROUP;
3117 return log_unit_error_errno(unit, r, "Failed to adjust control group access: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3117, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to adjust control group access: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3117, __func__, "Failed to adjust control group access: %m"
); })
;
3118 }
3119 }
3120
3121 for (dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) {
3122 r = setup_exec_directory(context, params, uid, gid, dt, exit_status);
3123 if (r < 0)
3124 return log_unit_error_errno(unit, r, "Failed to set up special execution directory in %s: %m", params->prefix[dt])({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3124, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to set up special execution directory in %s: %m", params
->prefix[dt]) : log_internal_realm(((LOG_REALM_SYSTEMD) <<
10 | ((3))), r, "../src/core/execute.c", 3124, __func__, "Failed to set up special execution directory in %s: %m"
, params->prefix[dt]); })
;
3125 }
3126
3127 r = build_environment(
3128 unit,
3129 context,
3130 params,
3131 n_fds,
3132 home,
3133 username,
3134 shell,
3135 journal_stream_dev,
3136 journal_stream_ino,
3137 &our_env);
3138 if (r < 0) {
3139 *exit_status = EXIT_MEMORY;
3140 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/core/execute.c", 3140
, __func__)
;
3141 }
3142
3143 r = build_pass_environment(context, &pass_env);
3144 if (r < 0) {
3145 *exit_status = EXIT_MEMORY;
3146 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/core/execute.c", 3146
, __func__)
;
3147 }
3148
3149 accum_env = strv_env_merge(5,
3150 params->environment,
3151 our_env,
3152 pass_env,
3153 context->environment,
3154 files_env,
3155 NULL((void*)0));
3156 if (!accum_env) {
3157 *exit_status = EXIT_MEMORY;
3158 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/core/execute.c", 3158
, __func__)
;
3159 }
3160 accum_env = strv_env_clean(accum_env)strv_env_clean_with_callback(accum_env, ((void*)0), ((void*)0
))
;
3161
3162 (void) umask(context->umask);
3163
3164 r = setup_keyring(unit, context, params, uid, gid);
3165 if (r < 0) {
3166 *exit_status = EXIT_KEYRING;
3167 return log_unit_error_errno(unit, r, "Failed to set up kernel keyring: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3167, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to set up kernel keyring: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3167, __func__, "Failed to set up kernel keyring: %m"); })
;
3168 }
3169
3170 /* We need sandboxing if the caller asked us to apply it and the command isn't explicitly excepted from it */
3171 needs_sandboxing = (params->flags & EXEC_APPLY_SANDBOXING) && !(command->flags & EXEC_COMMAND_FULLY_PRIVILEGED);
3172
3173 /* We need the ambient capability hack, if the caller asked us to apply it and the command is marked for it, and the kernel doesn't actually support ambient caps */
3174 needs_ambient_hack = (params->flags & EXEC_APPLY_SANDBOXING) && (command->flags & EXEC_COMMAND_AMBIENT_MAGIC) && !ambient_capabilities_supported();
3175
3176 /* We need setresuid() if the caller asked us to apply sandboxing and the command isn't explicitly excepted from either whole sandboxing or just setresuid() itself, and the ambient hack is not desired */
3177 if (needs_ambient_hack)
3178 needs_setuid = false0;
3179 else
3180 needs_setuid = (params->flags & EXEC_APPLY_SANDBOXING) && !(command->flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID));
3181
3182 if (needs_sandboxing) {
3183 /* MAC enablement checks need to be done before a new mount ns is created, as they rely on /sys being
3184 * present. The actual MAC context application will happen later, as late as possible, to avoid
3185 * impacting our own code paths. */
3186
3187#if HAVE_SELINUX1
3188 use_selinux = mac_selinux_use();
3189#endif
3190#if ENABLE_SMACK1
3191 use_smack = mac_smack_use();
3192#endif
3193#if HAVE_APPARMOR0
3194 use_apparmor = mac_apparmor_use();
3195#endif
3196 }
3197
3198 if (needs_setuid) {
3199 if (context->pam_name && username) {
3200 r = setup_pam(context->pam_name, username, uid, gid, context->tty_path, &accum_env, fds, n_fds);
3201 if (r < 0) {
3202 *exit_status = EXIT_PAM;
3203 return log_unit_error_errno(unit, r, "Failed to set up PAM session: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3203, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to set up PAM session: %m") : log_internal_realm(((
LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3203, __func__, "Failed to set up PAM session: %m"); })
;
3204 }
3205 }
3206 }
3207
3208 if (context->private_network && runtime && runtime->netns_storage_socket[0] >= 0) {
3209 if (ns_type_supported(NAMESPACE_NET)) {
3210 r = setup_netns(runtime->netns_storage_socket);
3211 if (r < 0) {
3212 *exit_status = EXIT_NETWORK;
3213 return log_unit_error_errno(unit, r, "Failed to set up network namespacing: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3213, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to set up network namespacing: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3213, __func__, "Failed to set up network namespacing: %m")
; })
;
3214 }
3215 } else
3216 log_unit_warning(unit, "PrivateNetwork=yes is configured, but the kernel does not support network namespaces, ignoring.")({ const Unit *_u = (unit); _u ? log_object_internal(4, 0, "../src/core/execute.c"
, 3216, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "PrivateNetwork=yes is configured, but the kernel does not support network namespaces, ignoring."
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((4
))), 0, "../src/core/execute.c", 3216, __func__, "PrivateNetwork=yes is configured, but the kernel does not support network namespaces, ignoring."
); })
;
3217 }
3218
3219 needs_mount_namespace = exec_needs_mount_namespace(context, params, runtime);
3220 if (needs_mount_namespace) {
3221 r = apply_mount_namespace(unit, command, context, params, runtime);
3222 if (r < 0) {
3223 *exit_status = EXIT_NAMESPACE;
3224 return log_unit_error_errno(unit, r, "Failed to set up mount namespacing: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3224, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to set up mount namespacing: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3224, __func__, "Failed to set up mount namespacing: %m"); }
)
;
3225 }
3226 }
3227
3228 /* Apply just after mount namespace setup */
3229 r = apply_working_directory(context, params, home, needs_mount_namespace, exit_status);
3230 if (r < 0)
3231 return log_unit_error_errno(unit, r, "Changing to the requested working directory failed: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3231, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Changing to the requested working directory failed: %m") :
log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3)))
, r, "../src/core/execute.c", 3231, __func__, "Changing to the requested working directory failed: %m"
); })
;
3232
3233 /* Drop groups as early as possbile */
3234 if (needs_setuid) {
3235 r = enforce_groups(gid, supplementary_gids, ngids);
3236 if (r < 0) {
3237 *exit_status = EXIT_GROUP;
3238 return log_unit_error_errno(unit, r, "Changing group credentials failed: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3238, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Changing group credentials failed: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3238, __func__, "Changing group credentials failed: %m"); }
)
;
3239 }
3240 }
3241
3242 if (needs_sandboxing) {
3243#if HAVE_SELINUX1
3244 if (use_selinux && params->selinux_context_net && socket_fd >= 0) {
3245 r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
3246 if (r < 0) {
3247 *exit_status = EXIT_SELINUX_CONTEXT;
3248 return log_unit_error_errno(unit, r, "Failed to determine SELinux context: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3248, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to determine SELinux context: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3248, __func__, "Failed to determine SELinux context: %m");
})
;
3249 }
3250 }
3251#endif
3252
3253 if (context->private_users) {
3254 r = setup_private_users(uid, gid);
3255 if (r < 0) {
3256 *exit_status = EXIT_USER;
3257 return log_unit_error_errno(unit, r, "Failed to set up user namespacing: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3257, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to set up user namespacing: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3257, __func__, "Failed to set up user namespacing: %m"); }
)
;
3258 }
3259 }
3260 }
3261
3262 /* We repeat the fd closing here, to make sure that nothing is leaked from the PAM modules. Note that we are
3263 * more aggressive this time since socket_fd and the netns fds we don't need anymore. We do keep the exec_fd
3264 * however if we have it as we want to keep it open until the final execve(). */
3265
3266 if (params->exec_fd >= 0) {
3267 exec_fd = params->exec_fd;
3268
3269 if (exec_fd < 3 + (int) n_fds) {
3270 int moved_fd;
3271
3272 /* Let's move the exec fd far up, so that it's outside of the fd range we want to pass to the
3273 * process we are about to execute. */
3274
3275 moved_fd = fcntl(exec_fd, F_DUPFD_CLOEXEC1030, 3 + (int) n_fds);
3276 if (moved_fd < 0) {
3277 *exit_status = EXIT_FDS;
3278 return log_unit_error_errno(unit, errno, "Couldn't move exec fd up: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 3278, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Couldn't move exec fd up: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 3278, __func__
, "Couldn't move exec fd up: %m"); })
;
3279 }
3280
3281 safe_close(exec_fd);
3282 exec_fd = moved_fd;
3283 } else {
3284 /* This fd should be FD_CLOEXEC already, but let's make sure. */
3285 r = fd_cloexec(exec_fd, true1);
3286 if (r < 0) {
3287 *exit_status = EXIT_FDS;
3288 return log_unit_error_errno(unit, r, "Failed to make exec fd FD_CLOEXEC: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3288, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to make exec fd FD_CLOEXEC: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3288, __func__, "Failed to make exec fd FD_CLOEXEC: %m"); }
)
;
3289 }
3290 }
3291
3292 fds_with_exec_fd = newa(int, n_fds + 1)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(int), n_fds + 1))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("!size_multiply_overflow(sizeof(int), n_fds + 1)"), "../src/core/execute.c"
, 3292, __PRETTY_FUNCTION__); } while (0); (int*) __builtin_alloca
(sizeof(int)*(n_fds + 1)); })
;
3293 memcpy(fds_with_exec_fd, fds, n_fds * sizeof(int));
3294 fds_with_exec_fd[n_fds] = exec_fd;
3295 n_fds_with_exec_fd = n_fds + 1;
3296 } else {
3297 fds_with_exec_fd = fds;
3298 n_fds_with_exec_fd = n_fds;
3299 }
3300
3301 r = close_all_fds(fds_with_exec_fd, n_fds_with_exec_fd);
3302 if (r >= 0)
3303 r = shift_fds(fds, n_fds);
3304 if (r >= 0)
3305 r = flags_fds(fds, n_socket_fds, n_storage_fds, context->non_blocking);
3306 if (r < 0) {
3307 *exit_status = EXIT_FDS;
3308 return log_unit_error_errno(unit, r, "Failed to adjust passed file descriptors: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3308, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to adjust passed file descriptors: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3308, __func__, "Failed to adjust passed file descriptors: %m"
); })
;
3309 }
3310
3311 /* At this point, the fds we want to pass to the program are all ready and set up, with O_CLOEXEC turned off
3312 * and at the right fd numbers. The are no other fds open, with one exception: the exec_fd if it is defined,
3313 * and it has O_CLOEXEC set, after all we want it to be closed by the execve(), so that our parent knows we
3314 * came this far. */
3315
3316 secure_bits = context->secure_bits;
3317
3318 if (needs_sandboxing) {
3319 uint64_t bset;
3320 int which_failed;
3321
3322 r = setrlimit_closest_all((const struct rlimit* const *) context->rlimit, &which_failed);
3323 if (r < 0) {
3324 *exit_status = EXIT_LIMITS;
3325 return log_unit_error_errno(unit, r, "Failed to adjust resource limit RLIMIT_%s: %m", rlimit_to_string(which_failed))({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3325, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to adjust resource limit RLIMIT_%s: %m", rlimit_to_string
(which_failed)) : log_internal_realm(((LOG_REALM_SYSTEMD) <<
10 | ((3))), r, "../src/core/execute.c", 3325, __func__, "Failed to adjust resource limit RLIMIT_%s: %m"
, rlimit_to_string(which_failed)); })
;
3326 }
3327
3328 /* Set the RTPRIO resource limit to 0, but only if nothing else was explicitly requested. */
3329 if (context->restrict_realtime && !context->rlimit[RLIMIT_RTPRIO__RLIMIT_RTPRIO]) {
3330 if (setrlimit(RLIMIT_RTPRIO__RLIMIT_RTPRIO, &RLIMIT_MAKE_CONST(0)((struct rlimit) { 0, 0 })) < 0) {
3331 *exit_status = EXIT_LIMITS;
3332 return log_unit_error_errno(unit, errno, "Failed to adjust RLIMIT_RTPRIO resource limit: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 3332, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to adjust RLIMIT_RTPRIO resource limit: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 3332, __func__
, "Failed to adjust RLIMIT_RTPRIO resource limit: %m"); })
;
3333 }
3334 }
3335
3336#if ENABLE_SMACK1
3337 /* LSM Smack needs the capability CAP_MAC_ADMIN to change the current execution security context of the
3338 * process. This is the latest place before dropping capabilities. Other MAC context are set later. */
3339 if (use_smack) {
3340 r = setup_smack(context, command);
3341 if (r < 0) {
3342 *exit_status = EXIT_SMACK_PROCESS_LABEL;
3343 return log_unit_error_errno(unit, r, "Failed to set SMACK process label: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3343, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to set SMACK process label: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3343, __func__, "Failed to set SMACK process label: %m"); }
)
;
3344 }
3345 }
3346#endif
3347
3348 bset = context->capability_bounding_set;
3349 /* If the ambient caps hack is enabled (which means the kernel can't do them, and the user asked for
3350 * our magic fallback), then let's add some extra caps, so that the service can drop privs of its own,
3351 * instead of us doing that */
3352 if (needs_ambient_hack)
3353 bset |= (UINT64_C(1)1UL << CAP_SETPCAP8) |
3354 (UINT64_C(1)1UL << CAP_SETUID7) |
3355 (UINT64_C(1)1UL << CAP_SETGID6);
3356
3357 if (!cap_test_all(bset)) {
3358 r = capability_bounding_set_drop(bset, false0);
3359 if (r < 0) {
3360 *exit_status = EXIT_CAPABILITIES;
3361 return log_unit_error_errno(unit, r, "Failed to drop capabilities: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3361, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to drop capabilities: %m") : log_internal_realm(((LOG_REALM_SYSTEMD
) << 10 | ((3))), r, "../src/core/execute.c", 3361, __func__
, "Failed to drop capabilities: %m"); })
;
3362 }
3363 }
3364
3365 /* This is done before enforce_user, but ambient set
3366 * does not survive over setresuid() if keep_caps is not set. */
3367 if (!needs_ambient_hack &&
3368 context->capability_ambient_set != 0) {
3369 r = capability_ambient_set_apply(context->capability_ambient_set, true1);
3370 if (r < 0) {
3371 *exit_status = EXIT_CAPABILITIES;
3372 return log_unit_error_errno(unit, r, "Failed to apply ambient capabilities (before UID change): %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3372, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to apply ambient capabilities (before UID change): %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), r, "../src/core/execute.c", 3372, __func__, "Failed to apply ambient capabilities (before UID change): %m"
); })
;
3373 }
3374 }
3375 }
3376
3377 if (needs_setuid) {
3378 if (context->user) {
3379 r = enforce_user(context, uid);
3380 if (r < 0) {
3381 *exit_status = EXIT_USER;
3382 return log_unit_error_errno(unit, r, "Failed to change UID to " UID_FMT ": %m", uid)({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3382, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to change UID to " "%" "u" ": %m", uid) : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3382, __func__, "Failed to change UID to " "%" "u" ": %m", uid
); })
;
3383 }
3384
3385 if (!needs_ambient_hack &&
3386 context->capability_ambient_set != 0) {
3387
3388 /* Fix the ambient capabilities after user change. */
3389 r = capability_ambient_set_apply(context->capability_ambient_set, false0);
3390 if (r < 0) {
3391 *exit_status = EXIT_CAPABILITIES;
3392 return log_unit_error_errno(unit, r, "Failed to apply ambient capabilities (after UID change): %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3392, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to apply ambient capabilities (after UID change): %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), r, "../src/core/execute.c", 3392, __func__, "Failed to apply ambient capabilities (after UID change): %m"
); })
;
3393 }
3394
3395 /* If we were asked to change user and ambient capabilities
3396 * were requested, we had to add keep-caps to the securebits
3397 * so that we would maintain the inherited capability set
3398 * through the setresuid(). Make sure that the bit is added
3399 * also to the context secure_bits so that we don't try to
3400 * drop the bit away next. */
3401
3402 secure_bits |= 1<<SECURE_KEEP_CAPS4;
3403 }
3404 }
3405 }
3406
3407 if (needs_sandboxing) {
3408 /* Apply other MAC contexts late, but before seccomp syscall filtering, as those should really be last to
3409 * influence our own codepaths as little as possible. Moreover, applying MAC contexts usually requires
3410 * syscalls that are subject to seccomp filtering, hence should probably be applied before the syscalls
3411 * are restricted. */
3412
3413#if HAVE_SELINUX1
3414 if (use_selinux) {
3415 char *exec_context = mac_selinux_context_net ?: context->selinux_context;
3416
3417 if (exec_context) {
3418 r = setexeccon(exec_context);
3419 if (r < 0) {
3420 *exit_status = EXIT_SELINUX_CONTEXT;
3421 return log_unit_error_errno(unit, r, "Failed to change SELinux context to %s: %m", exec_context)({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3421, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to change SELinux context to %s: %m", exec_context)
: log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3)
)), r, "../src/core/execute.c", 3421, __func__, "Failed to change SELinux context to %s: %m"
, exec_context); })
;
3422 }
3423 }
3424 }
3425#endif
3426
3427#if HAVE_APPARMOR0
3428 if (use_apparmor && context->apparmor_profile) {
3429 r = aa_change_onexec(context->apparmor_profile);
3430 if (r < 0 && !context->apparmor_profile_ignore) {
3431 *exit_status = EXIT_APPARMOR_PROFILE;
3432 return log_unit_error_errno(unit, errno, "Failed to prepare AppArmor profile change to %s: %m", context->apparmor_profile)({ const Unit *_u = (unit); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 3432, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to prepare AppArmor profile change to %s: %m"
, context->apparmor_profile) : log_internal_realm(((LOG_REALM_SYSTEMD
) << 10 | ((3))), (*__errno_location ()), "../src/core/execute.c"
, 3432, __func__, "Failed to prepare AppArmor profile change to %s: %m"
, context->apparmor_profile); })
;
3433 }
3434 }
3435#endif
3436
3437 /* PR_GET_SECUREBITS is not privileged, while PR_SET_SECUREBITS is. So to suppress potential EPERMs
3438 * we'll try not to call PR_SET_SECUREBITS unless necessary. */
3439 if (prctl(PR_GET_SECUREBITS27) != secure_bits)
3440 if (prctl(PR_SET_SECUREBITS28, secure_bits) < 0) {
3441 *exit_status = EXIT_SECUREBITS;
3442 return log_unit_error_errno(unit, errno, "Failed to set process secure bits: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 3442, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to set process secure bits: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 3442, __func__
, "Failed to set process secure bits: %m"); })
;
3443 }
3444
3445 if (context_has_no_new_privileges(context))
3446 if (prctl(PR_SET_NO_NEW_PRIVS38, 1, 0, 0, 0) < 0) {
3447 *exit_status = EXIT_NO_NEW_PRIVILEGES;
3448 return log_unit_error_errno(unit, errno, "Failed to disable new privileges: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 3448, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to disable new privileges: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 3448, __func__
, "Failed to disable new privileges: %m"); })
;
3449 }
3450
3451#if HAVE_SECCOMP1
3452 r = apply_address_families(unit, context);
3453 if (r < 0) {
3454 *exit_status = EXIT_ADDRESS_FAMILIES;
3455 return log_unit_error_errno(unit, r, "Failed to restrict address families: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3455, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to restrict address families: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3455, __func__, "Failed to restrict address families: %m");
})
;
3456 }
3457
3458 r = apply_memory_deny_write_execute(unit, context);
3459 if (r < 0) {
3460 *exit_status = EXIT_SECCOMP;
3461 return log_unit_error_errno(unit, r, "Failed to disable writing to executable memory: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3461, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to disable writing to executable memory: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3461, __func__, "Failed to disable writing to executable memory: %m"
); })
;
3462 }
3463
3464 r = apply_restrict_realtime(unit, context);
3465 if (r < 0) {
3466 *exit_status = EXIT_SECCOMP;
3467 return log_unit_error_errno(unit, r, "Failed to apply realtime restrictions: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3467, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to apply realtime restrictions: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3467, __func__, "Failed to apply realtime restrictions: %m"
); })
;
3468 }
3469
3470 r = apply_restrict_suid_sgid(unit, context);
3471 if (r < 0) {
3472 *exit_status = EXIT_SECCOMP;
3473 return log_unit_error_errno(unit, r, "Failed to apply SUID/SGID restrictions: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3473, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to apply SUID/SGID restrictions: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3473, __func__, "Failed to apply SUID/SGID restrictions: %m"
); })
;
3474 }
3475
3476 r = apply_restrict_namespaces(unit, context);
3477 if (r < 0) {
3478 *exit_status = EXIT_SECCOMP;
3479 return log_unit_error_errno(unit, r, "Failed to apply namespace restrictions: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3479, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to apply namespace restrictions: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3479, __func__, "Failed to apply namespace restrictions: %m"
); })
;
3480 }
3481
3482 r = apply_protect_sysctl(unit, context);
3483 if (r < 0) {
3484 *exit_status = EXIT_SECCOMP;
3485 return log_unit_error_errno(unit, r, "Failed to apply sysctl restrictions: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3485, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to apply sysctl restrictions: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3485, __func__, "Failed to apply sysctl restrictions: %m");
})
;
3486 }
3487
3488 r = apply_protect_kernel_modules(unit, context);
3489 if (r < 0) {
3490 *exit_status = EXIT_SECCOMP;
3491 return log_unit_error_errno(unit, r, "Failed to apply module loading restrictions: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3491, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to apply module loading restrictions: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3491, __func__, "Failed to apply module loading restrictions: %m"
); })
;
3492 }
3493
3494 r = apply_private_devices(unit, context);
3495 if (r < 0) {
3496 *exit_status = EXIT_SECCOMP;
3497 return log_unit_error_errno(unit, r, "Failed to set up private devices: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3497, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to set up private devices: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3497, __func__, "Failed to set up private devices: %m"); })
;
3498 }
3499
3500 r = apply_syscall_archs(unit, context);
3501 if (r < 0) {
3502 *exit_status = EXIT_SECCOMP;
3503 return log_unit_error_errno(unit, r, "Failed to apply syscall architecture restrictions: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3503, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to apply syscall architecture restrictions: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3503, __func__, "Failed to apply syscall architecture restrictions: %m"
); })
;
3504 }
3505
3506 r = apply_lock_personality(unit, context);
3507 if (r < 0) {
3508 *exit_status = EXIT_SECCOMP;
3509 return log_unit_error_errno(unit, r, "Failed to lock personalities: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3509, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to lock personalities: %m") : log_internal_realm(((
LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3509, __func__, "Failed to lock personalities: %m"); })
;
3510 }
3511
3512 /* This really should remain the last step before the execve(), to make sure our own code is unaffected
3513 * by the filter as little as possible. */
3514 r = apply_syscall_filter(unit, context, needs_ambient_hack);
3515 if (r < 0) {
3516 *exit_status = EXIT_SECCOMP;
3517 return log_unit_error_errno(unit, r, "Failed to apply system call filters: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3517, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to apply system call filters: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3517, __func__, "Failed to apply system call filters: %m");
})
;
3518 }
3519#endif
3520 }
3521
3522 if (!strv_isempty(context->unset_environment)) {
3523 char **ee = NULL((void*)0);
3524
3525 ee = strv_env_delete(accum_env, 1, context->unset_environment);
3526 if (!ee) {
3527 *exit_status = EXIT_MEMORY;
3528 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/core/execute.c", 3528
, __func__)
;
3529 }
3530
3531 strv_free_and_replace(accum_env, ee)({ strv_free(accum_env); (accum_env) = (ee); (ee) = ((void*)0
); 0; })
;
3532 }
3533
3534 final_argv = replace_env_argv(argv, accum_env);
3535 if (!final_argv) {
3536 *exit_status = EXIT_MEMORY;
3537 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/core/execute.c", 3537
, __func__)
;
3538 }
3539
3540 if (DEBUG_LOGGING(__builtin_expect(!!(log_get_max_level_realm(LOG_REALM_SYSTEMD
) >= 7),0))
) {
3541 _cleanup_free___attribute__((cleanup(freep))) char *line;
3542
3543 line = exec_command_line(final_argv);
3544 if (line)
3545 log_struct(LOG_DEBUG,log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (7)), 0
, "../src/core/execute.c", 3549, __func__, "EXECUTABLE=%s", command
->path, "MESSAGE=%s: " "Executing: %s", (unit)->id, line
, (unit)->manager->unit_log_format_string, (unit)->id
, (unit)->manager->invocation_log_format_string, (unit)
->invocation_id_string, ((void*)0))
3546 "EXECUTABLE=%s", command->path,log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (7)), 0
, "../src/core/execute.c", 3549, __func__, "EXECUTABLE=%s", command
->path, "MESSAGE=%s: " "Executing: %s", (unit)->id, line
, (unit)->manager->unit_log_format_string, (unit)->id
, (unit)->manager->invocation_log_format_string, (unit)
->invocation_id_string, ((void*)0))
3547 LOG_UNIT_MESSAGE(unit, "Executing: %s", line),log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (7)), 0
, "../src/core/execute.c", 3549, __func__, "EXECUTABLE=%s", command
->path, "MESSAGE=%s: " "Executing: %s", (unit)->id, line
, (unit)->manager->unit_log_format_string, (unit)->id
, (unit)->manager->invocation_log_format_string, (unit)
->invocation_id_string, ((void*)0))
3548 LOG_UNIT_ID(unit),log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (7)), 0
, "../src/core/execute.c", 3549, __func__, "EXECUTABLE=%s", command
->path, "MESSAGE=%s: " "Executing: %s", (unit)->id, line
, (unit)->manager->unit_log_format_string, (unit)->id
, (unit)->manager->invocation_log_format_string, (unit)
->invocation_id_string, ((void*)0))
3549 LOG_UNIT_INVOCATION_ID(unit))log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (7)), 0
, "../src/core/execute.c", 3549, __func__, "EXECUTABLE=%s", command
->path, "MESSAGE=%s: " "Executing: %s", (unit)->id, line
, (unit)->manager->unit_log_format_string, (unit)->id
, (unit)->manager->invocation_log_format_string, (unit)
->invocation_id_string, ((void*)0))
;
3550 }
3551
3552 if (exec_fd >= 0) {
3553 uint8_t hot = 1;
3554
3555 /* We have finished with all our initializations. Let's now let the manager know that. From this point
3556 * on, if the manager sees POLLHUP on the exec_fd, then execve() was successful. */
3557
3558 if (write(exec_fd, &hot, sizeof(hot)) < 0) {
3559 *exit_status = EXIT_EXEC;
3560 return log_unit_error_errno(unit, errno, "Failed to enable exec_fd: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 3560, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to enable exec_fd: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 3560, __func__
, "Failed to enable exec_fd: %m"); })
;
3561 }
3562 }
3563
3564 execve(command->path, final_argv, accum_env);
3565 r = -errno(*__errno_location ());
3566
3567 if (exec_fd >= 0) {
3568 uint8_t hot = 0;
3569
3570 /* The execve() failed. This means the exec_fd is still open. Which means we need to tell the manager
3571 * that POLLHUP on it no longer means execve() succeeded. */
3572
3573 if (write(exec_fd, &hot, sizeof(hot)) < 0) {
3574 *exit_status = EXIT_EXEC;
3575 return log_unit_error_errno(unit, errno, "Failed to disable exec_fd: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 3575, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to disable exec_fd: %m"
) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3
))), (*__errno_location ()), "../src/core/execute.c", 3575, __func__
, "Failed to disable exec_fd: %m"); })
;
3576 }
3577 }
3578
3579 if (r == -ENOENT2 && (command->flags & EXEC_COMMAND_IGNORE_FAILURE)) {
3580 log_struct_errno(LOG_INFO, r,log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (6)), r
, "../src/core/execute.c", 3586, __func__, "MESSAGE_ID=" "64"
"12" "57" "65" "1c" "1b" "4e" "c9" "a8" "62" "4d" "7a" "40" "a9"
"e1" "e7", (unit)->manager->unit_log_format_string, (unit
)->id, (unit)->manager->invocation_log_format_string
, (unit)->invocation_id_string, "MESSAGE=%s: " "Executable %s missing, skipping: %m"
, (unit)->id, command->path, "EXECUTABLE=%s", command->
path, ((void*)0))
3581 "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (6)), r
, "../src/core/execute.c", 3586, __func__, "MESSAGE_ID=" "64"
"12" "57" "65" "1c" "1b" "4e" "c9" "a8" "62" "4d" "7a" "40" "a9"
"e1" "e7", (unit)->manager->unit_log_format_string, (unit
)->id, (unit)->manager->invocation_log_format_string
, (unit)->invocation_id_string, "MESSAGE=%s: " "Executable %s missing, skipping: %m"
, (unit)->id, command->path, "EXECUTABLE=%s", command->
path, ((void*)0))
3582 LOG_UNIT_ID(unit),log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (6)), r
, "../src/core/execute.c", 3586, __func__, "MESSAGE_ID=" "64"
"12" "57" "65" "1c" "1b" "4e" "c9" "a8" "62" "4d" "7a" "40" "a9"
"e1" "e7", (unit)->manager->unit_log_format_string, (unit
)->id, (unit)->manager->invocation_log_format_string
, (unit)->invocation_id_string, "MESSAGE=%s: " "Executable %s missing, skipping: %m"
, (unit)->id, command->path, "EXECUTABLE=%s", command->
path, ((void*)0))
3583 LOG_UNIT_INVOCATION_ID(unit),log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (6)), r
, "../src/core/execute.c", 3586, __func__, "MESSAGE_ID=" "64"
"12" "57" "65" "1c" "1b" "4e" "c9" "a8" "62" "4d" "7a" "40" "a9"
"e1" "e7", (unit)->manager->unit_log_format_string, (unit
)->id, (unit)->manager->invocation_log_format_string
, (unit)->invocation_id_string, "MESSAGE=%s: " "Executable %s missing, skipping: %m"
, (unit)->id, command->path, "EXECUTABLE=%s", command->
path, ((void*)0))
3584 LOG_UNIT_MESSAGE(unit, "Executable %s missing, skipping: %m",log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (6)), r
, "../src/core/execute.c", 3586, __func__, "MESSAGE_ID=" "64"
"12" "57" "65" "1c" "1b" "4e" "c9" "a8" "62" "4d" "7a" "40" "a9"
"e1" "e7", (unit)->manager->unit_log_format_string, (unit
)->id, (unit)->manager->invocation_log_format_string
, (unit)->invocation_id_string, "MESSAGE=%s: " "Executable %s missing, skipping: %m"
, (unit)->id, command->path, "EXECUTABLE=%s", command->
path, ((void*)0))
3585 command->path),log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (6)), r
, "../src/core/execute.c", 3586, __func__, "MESSAGE_ID=" "64"
"12" "57" "65" "1c" "1b" "4e" "c9" "a8" "62" "4d" "7a" "40" "a9"
"e1" "e7", (unit)->manager->unit_log_format_string, (unit
)->id, (unit)->manager->invocation_log_format_string
, (unit)->invocation_id_string, "MESSAGE=%s: " "Executable %s missing, skipping: %m"
, (unit)->id, command->path, "EXECUTABLE=%s", command->
path, ((void*)0))
3586 "EXECUTABLE=%s", command->path)log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (6)), r
, "../src/core/execute.c", 3586, __func__, "MESSAGE_ID=" "64"
"12" "57" "65" "1c" "1b" "4e" "c9" "a8" "62" "4d" "7a" "40" "a9"
"e1" "e7", (unit)->manager->unit_log_format_string, (unit
)->id, (unit)->manager->invocation_log_format_string
, (unit)->invocation_id_string, "MESSAGE=%s: " "Executable %s missing, skipping: %m"
, (unit)->id, command->path, "EXECUTABLE=%s", command->
path, ((void*)0))
;
3587 return 0;
3588 }
3589
3590 *exit_status = EXIT_EXEC;
3591 return log_unit_error_errno(unit, r, "Failed to execute command: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3591, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to execute command: %m") : log_internal_realm(((LOG_REALM_SYSTEMD
) << 10 | ((3))), r, "../src/core/execute.c", 3591, __func__
, "Failed to execute command: %m"); })
;
3592}
3593
3594static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***l);
3595static int exec_context_named_iofds(const ExecContext *c, const ExecParameters *p, int named_iofds[3]);
3596
3597int exec_spawn(Unit *unit,
3598 ExecCommand *command,
3599 const ExecContext *context,
3600 const ExecParameters *params,
3601 ExecRuntime *runtime,
3602 DynamicCreds *dcreds,
3603 pid_t *ret) {
3604
3605 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **files_env = NULL((void*)0);
3606 int *fds = NULL((void*)0);
3607 size_t n_storage_fds = 0, n_socket_fds = 0;
3608 _cleanup_free___attribute__((cleanup(freep))) char *line = NULL((void*)0);
3609 int socket_fd, r;
3610 int named_iofds[3] = { -1, -1, -1 };
3611 char **argv;
3612 pid_t pid;
3613
3614 assert(unit)do { if ((__builtin_expect(!!(!(unit)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("unit"), "../src/core/execute.c", 3614, __PRETTY_FUNCTION__
); } while (0)
;
3615 assert(command)do { if ((__builtin_expect(!!(!(command)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("command"), "../src/core/execute.c", 3615
, __PRETTY_FUNCTION__); } while (0)
;
3616 assert(context)do { if ((__builtin_expect(!!(!(context)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("context"), "../src/core/execute.c", 3616
, __PRETTY_FUNCTION__); } while (0)
;
3617 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/core/execute.c", 3617, __PRETTY_FUNCTION__
); } while (0)
;
3618 assert(params)do { if ((__builtin_expect(!!(!(params)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("params"), "../src/core/execute.c", 3618
, __PRETTY_FUNCTION__); } while (0)
;
3619 assert(params->fds || (params->n_socket_fds + params->n_storage_fds <= 0))do { if ((__builtin_expect(!!(!(params->fds || (params->
n_socket_fds + params->n_storage_fds <= 0))),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("params->fds || (params->n_socket_fds + params->n_storage_fds <= 0)"
), "../src/core/execute.c", 3619, __PRETTY_FUNCTION__); } while
(0)
;
3620
3621 if (context->std_input == EXEC_INPUT_SOCKET ||
3622 context->std_output == EXEC_OUTPUT_SOCKET ||
3623 context->std_error == EXEC_OUTPUT_SOCKET) {
3624
3625 if (params->n_socket_fds > 1) {
3626 log_unit_error(unit, "Got more than one socket.")({ const Unit *_u = (unit); _u ? log_object_internal(3, 0, "../src/core/execute.c"
, 3626, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Got more than one socket.") : log_internal_realm(((LOG_REALM_SYSTEMD
) << 10 | ((3))), 0, "../src/core/execute.c", 3626, __func__
, "Got more than one socket."); })
;
3627 return -EINVAL22;
3628 }
3629
3630 if (params->n_socket_fds == 0) {
3631 log_unit_error(unit, "Got no socket.")({ const Unit *_u = (unit); _u ? log_object_internal(3, 0, "../src/core/execute.c"
, 3631, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Got no socket.") : log_internal_realm(((LOG_REALM_SYSTEMD)
<< 10 | ((3))), 0, "../src/core/execute.c", 3631, __func__
, "Got no socket."); })
;
3632 return -EINVAL22;
3633 }
3634
3635 socket_fd = params->fds[0];
3636 } else {
3637 socket_fd = -1;
3638 fds = params->fds;
3639 n_socket_fds = params->n_socket_fds;
3640 n_storage_fds = params->n_storage_fds;
3641 }
3642
3643 r = exec_context_named_iofds(context, params, named_iofds);
3644 if (r < 0)
3645 return log_unit_error_errno(unit, r, "Failed to load a named file descriptor: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3645, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to load a named file descriptor: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3645, __func__, "Failed to load a named file descriptor: %m"
); })
;
3646
3647 r = exec_context_load_environment(unit, context, &files_env);
3648 if (r < 0)
3649 return log_unit_error_errno(unit, r, "Failed to load environment files: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, r, "../src/core/execute.c"
, 3649, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to load environment files: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/execute.c"
, 3649, __func__, "Failed to load environment files: %m"); })
;
3650
3651 argv = params->argv ?: command->argv;
3652 line = exec_command_line(argv);
3653 if (!line)
3654 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/core/execute.c", 3654
, __func__)
;
3655
3656 log_struct(LOG_DEBUG,log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (7)), 0
, "../src/core/execute.c", 3660, __func__, "MESSAGE=%s: " "About to execute: %s"
, (unit)->id, line, "EXECUTABLE=%s", command->path, (unit
)->manager->unit_log_format_string, (unit)->id, (unit
)->manager->invocation_log_format_string, (unit)->invocation_id_string
, ((void*)0))
3657 LOG_UNIT_MESSAGE(unit, "About to execute: %s", line),log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (7)), 0
, "../src/core/execute.c", 3660, __func__, "MESSAGE=%s: " "About to execute: %s"
, (unit)->id, line, "EXECUTABLE=%s", command->path, (unit
)->manager->unit_log_format_string, (unit)->id, (unit
)->manager->invocation_log_format_string, (unit)->invocation_id_string
, ((void*)0))
3658 "EXECUTABLE=%s", command->path,log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (7)), 0
, "../src/core/execute.c", 3660, __func__, "MESSAGE=%s: " "About to execute: %s"
, (unit)->id, line, "EXECUTABLE=%s", command->path, (unit
)->manager->unit_log_format_string, (unit)->id, (unit
)->manager->invocation_log_format_string, (unit)->invocation_id_string
, ((void*)0))
3659 LOG_UNIT_ID(unit),log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (7)), 0
, "../src/core/execute.c", 3660, __func__, "MESSAGE=%s: " "About to execute: %s"
, (unit)->id, line, "EXECUTABLE=%s", command->path, (unit
)->manager->unit_log_format_string, (unit)->id, (unit
)->manager->invocation_log_format_string, (unit)->invocation_id_string
, ((void*)0))
3660 LOG_UNIT_INVOCATION_ID(unit))log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (7)), 0
, "../src/core/execute.c", 3660, __func__, "MESSAGE=%s: " "About to execute: %s"
, (unit)->id, line, "EXECUTABLE=%s", command->path, (unit
)->manager->unit_log_format_string, (unit)->id, (unit
)->manager->invocation_log_format_string, (unit)->invocation_id_string
, ((void*)0))
;
3661
3662 pid = fork();
3663 if (pid < 0)
3664 return log_unit_error_errno(unit, errno, "Failed to fork: %m")({ const Unit *_u = (unit); _u ? log_object_internal(3, (*__errno_location
()), "../src/core/execute.c", 3664, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Failed to fork: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), (*__errno_location
()), "../src/core/execute.c", 3664, __func__, "Failed to fork: %m"
); })
;
3665
3666 if (pid == 0) {
3667 int exit_status = EXIT_SUCCESS0;
3668
3669 r = exec_child(unit,
3670 command,
3671 context,
3672 params,
3673 runtime,
3674 dcreds,
3675 argv,
3676 socket_fd,
3677 named_iofds,
3678 fds,
3679 n_socket_fds,
3680 n_storage_fds,
3681 files_env,
3682 unit->manager->user_lookup_fds[1],
3683 &exit_status);
3684
3685 if (r < 0)
3686 log_struct_errno(LOG_ERR, r,log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (3)), r
, "../src/core/execute.c", 3693, __func__, "MESSAGE_ID=" "64"
"12" "57" "65" "1c" "1b" "4e" "c9" "a8" "62" "4d" "7a" "40" "a9"
"e1" "e7", (unit)->manager->unit_log_format_string, (unit
)->id, (unit)->manager->invocation_log_format_string
, (unit)->invocation_id_string, "MESSAGE=%s: " "Failed at step %s spawning %s: %m"
, (unit)->id, exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD
), command->path, "EXECUTABLE=%s", command->path, ((void
*)0))
3687 "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (3)), r
, "../src/core/execute.c", 3693, __func__, "MESSAGE_ID=" "64"
"12" "57" "65" "1c" "1b" "4e" "c9" "a8" "62" "4d" "7a" "40" "a9"
"e1" "e7", (unit)->manager->unit_log_format_string, (unit
)->id, (unit)->manager->invocation_log_format_string
, (unit)->invocation_id_string, "MESSAGE=%s: " "Failed at step %s spawning %s: %m"
, (unit)->id, exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD
), command->path, "EXECUTABLE=%s", command->path, ((void
*)0))
3688 LOG_UNIT_ID(unit),log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (3)), r
, "../src/core/execute.c", 3693, __func__, "MESSAGE_ID=" "64"
"12" "57" "65" "1c" "1b" "4e" "c9" "a8" "62" "4d" "7a" "40" "a9"
"e1" "e7", (unit)->manager->unit_log_format_string, (unit
)->id, (unit)->manager->invocation_log_format_string
, (unit)->invocation_id_string, "MESSAGE=%s: " "Failed at step %s spawning %s: %m"
, (unit)->id, exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD
), command->path, "EXECUTABLE=%s", command->path, ((void
*)0))
3689 LOG_UNIT_INVOCATION_ID(unit),log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (3)), r
, "../src/core/execute.c", 3693, __func__, "MESSAGE_ID=" "64"
"12" "57" "65" "1c" "1b" "4e" "c9" "a8" "62" "4d" "7a" "40" "a9"
"e1" "e7", (unit)->manager->unit_log_format_string, (unit
)->id, (unit)->manager->invocation_log_format_string
, (unit)->invocation_id_string, "MESSAGE=%s: " "Failed at step %s spawning %s: %m"
, (unit)->id, exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD
), command->path, "EXECUTABLE=%s", command->path, ((void
*)0))
3690 LOG_UNIT_MESSAGE(unit, "Failed at step %s spawning %s: %m",log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (3)), r
, "../src/core/execute.c", 3693, __func__, "MESSAGE_ID=" "64"
"12" "57" "65" "1c" "1b" "4e" "c9" "a8" "62" "4d" "7a" "40" "a9"
"e1" "e7", (unit)->manager->unit_log_format_string, (unit
)->id, (unit)->manager->invocation_log_format_string
, (unit)->invocation_id_string, "MESSAGE=%s: " "Failed at step %s spawning %s: %m"
, (unit)->id, exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD
), command->path, "EXECUTABLE=%s", command->path, ((void
*)0))
3691 exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD),log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (3)), r
, "../src/core/execute.c", 3693, __func__, "MESSAGE_ID=" "64"
"12" "57" "65" "1c" "1b" "4e" "c9" "a8" "62" "4d" "7a" "40" "a9"
"e1" "e7", (unit)->manager->unit_log_format_string, (unit
)->id, (unit)->manager->invocation_log_format_string
, (unit)->invocation_id_string, "MESSAGE=%s: " "Failed at step %s spawning %s: %m"
, (unit)->id, exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD
), command->path, "EXECUTABLE=%s", command->path, ((void
*)0))
3692 command->path),log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (3)), r
, "../src/core/execute.c", 3693, __func__, "MESSAGE_ID=" "64"
"12" "57" "65" "1c" "1b" "4e" "c9" "a8" "62" "4d" "7a" "40" "a9"
"e1" "e7", (unit)->manager->unit_log_format_string, (unit
)->id, (unit)->manager->invocation_log_format_string
, (unit)->invocation_id_string, "MESSAGE=%s: " "Failed at step %s spawning %s: %m"
, (unit)->id, exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD
), command->path, "EXECUTABLE=%s", command->path, ((void
*)0))
3693 "EXECUTABLE=%s", command->path)log_struct_internal(((LOG_REALM_SYSTEMD) << 10 | (3)), r
, "../src/core/execute.c", 3693, __func__, "MESSAGE_ID=" "64"
"12" "57" "65" "1c" "1b" "4e" "c9" "a8" "62" "4d" "7a" "40" "a9"
"e1" "e7", (unit)->manager->unit_log_format_string, (unit
)->id, (unit)->manager->invocation_log_format_string
, (unit)->invocation_id_string, "MESSAGE=%s: " "Failed at step %s spawning %s: %m"
, (unit)->id, exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD
), command->path, "EXECUTABLE=%s", command->path, ((void
*)0))
;
3694
3695 _exit(exit_status);
3696 }
3697
3698 log_unit_debug(unit, "Forked %s as "PID_FMT, command->path, pid)({ const Unit *_u = (unit); _u ? log_object_internal(7, 0, "../src/core/execute.c"
, 3698, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Forked %s as ""%" "i", command->path, pid) : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/core/execute.c"
, 3698, __func__, "Forked %s as ""%" "i", command->path, pid
); })
;
3699
3700 /* We add the new process to the cgroup both in the child (so
3701 * that we can be sure that no user code is ever executed
3702 * outside of the cgroup) and in the parent (so that we can be
3703 * sure that when we kill the cgroup the process will be
3704 * killed too). */
3705 if (params->cgroup_path)
3706 (void) cg_attach(SYSTEMD_CGROUP_CONTROLLER"_systemd", params->cgroup_path, pid);
3707
3708 exec_status_start(&command->exec_status, pid);
3709
3710 *ret = pid;
3711 return 0;
3712}
3713
3714void exec_context_init(ExecContext *c) {
3715 ExecDirectoryType i;
3716
3717 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 3717, __PRETTY_FUNCTION__
); } while (0)
;
3718
3719 c->umask = 0022;
3720 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0)(((IOPRIO_CLASS_BE) << 13) | 0);
3721 c->cpu_sched_policy = SCHED_OTHER0;
3722 c->syslog_priority = LOG_DAEMON(3<<3)|LOG_INFO6;
3723 c->syslog_level_prefix = true1;
3724 c->ignore_sigpipe = true1;
3725 c->timer_slack_nsec = NSEC_INFINITY((nsec_t) -1);
3726 c->personality = PERSONALITY_INVALID0xffffffffLU;
3727 for (i = 0; i < _EXEC_DIRECTORY_TYPE_MAX; i++)
3728 c->directories[i].mode = 0755;
3729 c->capability_bounding_set = CAP_ALL(uint64_t) -1;
3730 assert_cc(NAMESPACE_FLAGS_INITIAL != NAMESPACE_FLAGS_ALL)GCC diagnostic push ; GCC diagnostic ignored "-Wdeclaration-after-statement"
; struct _assert_struct_18 { char x[(((unsigned long) -1) !=
((unsigned long) (0x02000000| 0x08000000| 0x40000000| 0x00020000
| 0x20000000| 0x10000000| 0x04000000))) ? 0 : -1]; }; GCC diagnostic
pop
;
3731 c->restrict_namespaces = NAMESPACE_FLAGS_INITIAL((unsigned long) -1);
3732 c->log_level_max = -1;
3733 numa_policy_reset(&c->numa_policy);
3734}
3735
3736void exec_context_done(ExecContext *c) {
3737 ExecDirectoryType i;
3738 size_t l;
3739
3740 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 3740, __PRETTY_FUNCTION__
); } while (0)
;
3741
3742 c->environment = strv_free(c->environment);
3743 c->environment_files = strv_free(c->environment_files);
3744 c->pass_environment = strv_free(c->pass_environment);
3745 c->unset_environment = strv_free(c->unset_environment);
3746
3747 rlimit_free_all(c->rlimit);
3748
3749 for (l = 0; l < 3; l++) {
3750 c->stdio_fdname[l] = mfree(c->stdio_fdname[l]);
3751 c->stdio_file[l] = mfree(c->stdio_file[l]);
3752 }
3753
3754 c->working_directory = mfree(c->working_directory);
3755 c->root_directory = mfree(c->root_directory);
3756 c->root_image = mfree(c->root_image);
3757 c->tty_path = mfree(c->tty_path);
3758 c->syslog_identifier = mfree(c->syslog_identifier);
3759 c->user = mfree(c->user);
3760 c->group = mfree(c->group);
3761
3762 c->supplementary_groups = strv_free(c->supplementary_groups);
3763
3764 c->pam_name = mfree(c->pam_name);
3765
3766 c->read_only_paths = strv_free(c->read_only_paths);
3767 c->read_write_paths = strv_free(c->read_write_paths);
3768 c->inaccessible_paths = strv_free(c->inaccessible_paths);
3769
3770 bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
3771 c->bind_mounts = NULL((void*)0);
3772 c->n_bind_mounts = 0;
3773 temporary_filesystem_free_many(c->temporary_filesystems, c->n_temporary_filesystems);
3774 c->temporary_filesystems = NULL((void*)0);
3775 c->n_temporary_filesystems = 0;
3776
3777 cpu_set_reset(&c->cpu_set);
3778 numa_policy_reset(&c->numa_policy);
3779
3780 c->utmp_id = mfree(c->utmp_id);
3781 c->selinux_context = mfree(c->selinux_context);
3782 c->apparmor_profile = mfree(c->apparmor_profile);
3783 c->smack_process_label = mfree(c->smack_process_label);
3784
3785 c->syscall_filter = hashmap_free(c->syscall_filter);
3786 c->syscall_archs = set_free(c->syscall_archs);
3787 c->address_families = set_free(c->address_families);
3788
3789 for (i = 0; i < _EXEC_DIRECTORY_TYPE_MAX; i++)
3790 c->directories[i].paths = strv_free(c->directories[i].paths);
3791
3792 c->log_level_max = -1;
3793
3794 exec_context_free_log_extra_fields(c);
3795
3796 c->log_rate_limit_interval_usec = 0;
3797 c->log_rate_limit_burst = 0;
3798
3799 c->stdin_data = mfree(c->stdin_data);
3800 c->stdin_data_size = 0;
3801}
3802
3803int exec_context_destroy_runtime_directory(const ExecContext *c, const char *runtime_prefix) {
3804 char **i;
3805
3806 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 3806, __PRETTY_FUNCTION__
); } while (0)
;
3807
3808 if (!runtime_prefix)
3809 return 0;
3810
3811 STRV_FOREACH(i, c->directories[EXEC_DIRECTORY_RUNTIME].paths)for ((i) = (c->directories[EXEC_DIRECTORY_RUNTIME].paths);
(i) && *(i); (i)++)
{
3812 _cleanup_free___attribute__((cleanup(freep))) char *p;
3813
3814 p = strjoin(runtime_prefix, "/", *i)strjoin_real((runtime_prefix), "/", *i, ((void*)0));
3815 if (!p)
3816 return -ENOMEM12;
3817
3818 /* We execute this synchronously, since we need to be sure this is gone when we start the service
3819 * next. */
3820 (void) rm_rf(p, REMOVE_ROOT);
3821 }
3822
3823 return 0;
3824}
3825
3826static void exec_command_done(ExecCommand *c) {
3827 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 3827, __PRETTY_FUNCTION__
); } while (0)
;
3828
3829 c->path = mfree(c->path);
3830
3831 c->argv = strv_free(c->argv);
3832}
3833
3834void exec_command_done_array(ExecCommand *c, size_t n) {
3835 size_t i;
3836
3837 for (i = 0; i < n; i++)
3838 exec_command_done(c+i);
3839}
3840
3841ExecCommand* exec_command_free_list(ExecCommand *c) {
3842 ExecCommand *i;
3843
3844 while ((i = c)) {
3845 LIST_REMOVE(command, c, i)do { typeof(*(c)) **_head = &(c), *_item = (i); do { if (
(__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("_item"), "../src/core/execute.c", 3845, __PRETTY_FUNCTION__
); } while (0); if (_item->command_next) _item->command_next
->command_prev = _item->command_prev; if (_item->command_prev
) _item->command_prev->command_next = _item->command_next
; else { do { if ((__builtin_expect(!!(!(*_head == _item)),0)
)) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("*_head == _item"
), "../src/core/execute.c", 3845, __PRETTY_FUNCTION__); } while
(0); *_head = _item->command_next; } _item->command_next
= _item->command_prev = ((void*)0); } while (0)
;
3846 exec_command_done(i);
3847 free(i);
3848 }
3849
3850 return NULL((void*)0);
3851}
3852
3853void exec_command_free_array(ExecCommand **c, size_t n) {
3854 size_t i;
3855
3856 for (i = 0; i < n; i++)
3857 c[i] = exec_command_free_list(c[i]);
3858}
3859
3860typedef struct InvalidEnvInfo {
3861 const Unit *unit;
3862 const char *path;
3863} InvalidEnvInfo;
3864
3865static void invalid_env(const char *p, void *userdata) {
3866 InvalidEnvInfo *info = userdata;
3867
3868 log_unit_error(info->unit, "Ignoring invalid environment assignment '%s': %s", p, info->path)({ const Unit *_u = (info->unit); _u ? log_object_internal
(3, 0, "../src/core/execute.c", 3868, __func__, _u->manager
->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Ignoring invalid environment assignment '%s': %s"
, p, info->path) : log_internal_realm(((LOG_REALM_SYSTEMD)
<< 10 | ((3))), 0, "../src/core/execute.c", 3868, __func__
, "Ignoring invalid environment assignment '%s': %s", p, info
->path); })
;
3869}
3870
3871const char* exec_context_fdname(const ExecContext *c, int fd_index) {
3872 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 3872, __PRETTY_FUNCTION__
); } while (0)
;
3873
3874 switch (fd_index) {
3875
3876 case STDIN_FILENO0:
3877 if (c->std_input != EXEC_INPUT_NAMED_FD)
3878 return NULL((void*)0);
3879
3880 return c->stdio_fdname[STDIN_FILENO0] ?: "stdin";
3881
3882 case STDOUT_FILENO1:
3883 if (c->std_output != EXEC_OUTPUT_NAMED_FD)
3884 return NULL((void*)0);
3885
3886 return c->stdio_fdname[STDOUT_FILENO1] ?: "stdout";
3887
3888 case STDERR_FILENO2:
3889 if (c->std_error != EXEC_OUTPUT_NAMED_FD)
3890 return NULL((void*)0);
3891
3892 return c->stdio_fdname[STDERR_FILENO2] ?: "stderr";
3893
3894 default:
3895 return NULL((void*)0);
3896 }
3897}
3898
3899static int exec_context_named_iofds(const ExecContext *c, const ExecParameters *p, int named_iofds[3]) {
3900 size_t i, targets;
3901 const char* stdio_fdname[3];
3902 size_t n_fds;
3903
3904 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 3904, __PRETTY_FUNCTION__
); } while (0)
;
3905 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/core/execute.c", 3905, __PRETTY_FUNCTION__
); } while (0)
;
3906
3907 targets = (c->std_input == EXEC_INPUT_NAMED_FD) +
3908 (c->std_output == EXEC_OUTPUT_NAMED_FD) +
3909 (c->std_error == EXEC_OUTPUT_NAMED_FD);
3910
3911 for (i = 0; i < 3; i++)
3912 stdio_fdname[i] = exec_context_fdname(c, i);
3913
3914 n_fds = p->n_storage_fds + p->n_socket_fds;
3915
3916 for (i = 0; i < n_fds && targets > 0; i++)
3917 if (named_iofds[STDIN_FILENO0] < 0 &&
3918 c->std_input == EXEC_INPUT_NAMED_FD &&
3919 stdio_fdname[STDIN_FILENO0] &&
3920 streq(p->fd_names[i], stdio_fdname[STDIN_FILENO])(strcmp((p->fd_names[i]),(stdio_fdname[0])) == 0)) {
3921
3922 named_iofds[STDIN_FILENO0] = p->fds[i];
3923 targets--;
3924
3925 } else if (named_iofds[STDOUT_FILENO1] < 0 &&
3926 c->std_output == EXEC_OUTPUT_NAMED_FD &&
3927 stdio_fdname[STDOUT_FILENO1] &&
3928 streq(p->fd_names[i], stdio_fdname[STDOUT_FILENO])(strcmp((p->fd_names[i]),(stdio_fdname[1])) == 0)) {
3929
3930 named_iofds[STDOUT_FILENO1] = p->fds[i];
3931 targets--;
3932
3933 } else if (named_iofds[STDERR_FILENO2] < 0 &&
3934 c->std_error == EXEC_OUTPUT_NAMED_FD &&
3935 stdio_fdname[STDERR_FILENO2] &&
3936 streq(p->fd_names[i], stdio_fdname[STDERR_FILENO])(strcmp((p->fd_names[i]),(stdio_fdname[2])) == 0)) {
3937
3938 named_iofds[STDERR_FILENO2] = p->fds[i];
3939 targets--;
3940 }
3941
3942 return targets == 0 ? 0 : -ENOENT2;
3943}
3944
3945static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***l) {
3946 char **i, **r = NULL((void*)0);
3947
3948 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 3948, __PRETTY_FUNCTION__
); } while (0)
;
3949 assert(l)do { if ((__builtin_expect(!!(!(l)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("l"), "../src/core/execute.c", 3949, __PRETTY_FUNCTION__
); } while (0)
;
3950
3951 STRV_FOREACH(i, c->environment_files)for ((i) = (c->environment_files); (i) && *(i); (i
)++)
{
3952 char *fn;
3953 int k;
3954 unsigned n;
3955 bool_Bool ignore = false0;
3956 char **p;
3957 _cleanup_globfree___attribute__((cleanup(globfree))) glob_t pglob = {};
3958
3959 fn = *i;
3960
3961 if (fn[0] == '-') {
3962 ignore = true1;
3963 fn++;
3964 }
3965
3966 if (!path_is_absolute(fn)) {
3967 if (ignore)
3968 continue;
3969
3970 strv_free(r);
3971 return -EINVAL22;
3972 }
3973
3974 /* Filename supports globbing, take all matching files */
3975 k = safe_glob(fn, 0, &pglob);
3976 if (k < 0) {
3977 if (ignore)
3978 continue;
3979
3980 strv_free(r);
3981 return k;
3982 }
3983
3984 /* When we don't match anything, -ENOENT should be returned */
3985 assert(pglob.gl_pathc > 0)do { if ((__builtin_expect(!!(!(pglob.gl_pathc > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("pglob.gl_pathc > 0"), "../src/core/execute.c"
, 3985, __PRETTY_FUNCTION__); } while (0)
;
3986
3987 for (n = 0; n < pglob.gl_pathc; n++) {
3988 k = load_env_file(NULL((void*)0), pglob.gl_pathv[n], NULL((void*)0), &p);
3989 if (k < 0) {
3990 if (ignore)
3991 continue;
3992
3993 strv_free(r);
3994 return k;
3995 }
3996 /* Log invalid environment variables with filename */
3997 if (p) {
3998 InvalidEnvInfo info = {
3999 .unit = unit,
4000 .path = pglob.gl_pathv[n]
4001 };
4002
4003 p = strv_env_clean_with_callback(p, invalid_env, &info);
4004 }
4005
4006 if (!r)
4007 r = p;
4008 else {
4009 char **m;
4010
4011 m = strv_env_merge(2, r, p);
4012 strv_free(r);
4013 strv_free(p);
4014 if (!m)
4015 return -ENOMEM12;
4016
4017 r = m;
4018 }
4019 }
4020 }
4021
4022 *l = r;
4023
4024 return 0;
4025}
4026
4027static bool_Bool tty_may_match_dev_console(const char *tty) {
4028 _cleanup_free___attribute__((cleanup(freep))) char *resolved = NULL((void*)0);
4029
4030 if (!tty)
4031 return true1;
4032
4033 tty = skip_dev_prefix(tty);
4034
4035 /* trivial identity? */
4036 if (streq(tty, "console")(strcmp((tty),("console")) == 0))
4037 return true1;
4038
4039 if (resolve_dev_console(&resolved) < 0)
4040 return true1; /* if we could not resolve, assume it may */
4041
4042 /* "tty0" means the active VC, so it may be the same sometimes */
4043 return streq(resolved, tty)(strcmp((resolved),(tty)) == 0) || (streq(resolved, "tty0")(strcmp((resolved),("tty0")) == 0) && tty_is_vc(tty));
4044}
4045
4046bool_Bool exec_context_may_touch_console(const ExecContext *ec) {
4047
4048 return (ec->tty_reset ||
4049 ec->tty_vhangup ||
4050 ec->tty_vt_disallocate ||
4051 is_terminal_input(ec->std_input) ||
4052 is_terminal_output(ec->std_output) ||
4053 is_terminal_output(ec->std_error)) &&
4054 tty_may_match_dev_console(exec_context_tty_path(ec));
4055}
4056
4057static void strv_fprintf(FILE *f, char **l) {
4058 char **g;
4059
4060 assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("f"), "../src/core/execute.c", 4060, __PRETTY_FUNCTION__
); } while (0)
;
4061
4062 STRV_FOREACH(g, l)for ((g) = (l); (g) && *(g); (g)++)
4063 fprintf(f, " %s", *g);
4064}
4065
4066void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
4067 ExecDirectoryType dt;
4068 char **e, **d;
4069 unsigned i;
4070 int r;
4071
4072 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 4072, __PRETTY_FUNCTION__
); } while (0)
;
4073 assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("f"), "../src/core/execute.c", 4073, __PRETTY_FUNCTION__
); } while (0)
;
4074
4075 prefix = strempty(prefix);
4076
4077 fprintf(f,
4078 "%sUMask: %04o\n"
4079 "%sWorkingDirectory: %s\n"
4080 "%sRootDirectory: %s\n"
4081 "%sNonBlocking: %s\n"
4082 "%sPrivateTmp: %s\n"
4083 "%sPrivateDevices: %s\n"
4084 "%sProtectKernelTunables: %s\n"
4085 "%sProtectKernelModules: %s\n"
4086 "%sProtectControlGroups: %s\n"
4087 "%sPrivateNetwork: %s\n"
4088 "%sPrivateUsers: %s\n"
4089 "%sProtectHome: %s\n"
4090 "%sProtectSystem: %s\n"
4091 "%sMountAPIVFS: %s\n"
4092 "%sIgnoreSIGPIPE: %s\n"
4093 "%sMemoryDenyWriteExecute: %s\n"
4094 "%sRestrictRealtime: %s\n"
4095 "%sRestrictSUIDSGID: %s\n"
4096 "%sKeyringMode: %s\n",
4097 prefix, c->umask,
4098 prefix, c->working_directory ? c->working_directory : "/",
4099 prefix, c->root_directory ? c->root_directory : "/",
4100 prefix, yes_no(c->non_blocking),
4101 prefix, yes_no(c->private_tmp),
4102 prefix, yes_no(c->private_devices),
4103 prefix, yes_no(c->protect_kernel_tunables),
4104 prefix, yes_no(c->protect_kernel_modules),
4105 prefix, yes_no(c->protect_control_groups),
4106 prefix, yes_no(c->private_network),
4107 prefix, yes_no(c->private_users),
4108 prefix, protect_home_to_string(c->protect_home),
4109 prefix, protect_system_to_string(c->protect_system),
4110 prefix, yes_no(c->mount_apivfs),
4111 prefix, yes_no(c->ignore_sigpipe),
4112 prefix, yes_no(c->memory_deny_write_execute),
4113 prefix, yes_no(c->restrict_realtime),
4114 prefix, yes_no(c->restrict_suid_sgid),
4115 prefix, exec_keyring_mode_to_string(c->keyring_mode));
4116
4117 if (c->root_image)
4118 fprintf(f, "%sRootImage: %s\n", prefix, c->root_image);
4119
4120 STRV_FOREACH(e, c->environment)for ((e) = (c->environment); (e) && *(e); (e)++)
4121 fprintf(f, "%sEnvironment: %s\n", prefix, *e);
4122
4123 STRV_FOREACH(e, c->environment_files)for ((e) = (c->environment_files); (e) && *(e); (e
)++)
4124 fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
4125
4126 STRV_FOREACH(e, c->pass_environment)for ((e) = (c->pass_environment); (e) && *(e); (e)
++)
4127 fprintf(f, "%sPassEnvironment: %s\n", prefix, *e);
4128
4129 STRV_FOREACH(e, c->unset_environment)for ((e) = (c->unset_environment); (e) && *(e); (e
)++)
4130 fprintf(f, "%sUnsetEnvironment: %s\n", prefix, *e);
4131
4132 fprintf(f, "%sRuntimeDirectoryPreserve: %s\n", prefix, exec_preserve_mode_to_string(c->runtime_directory_preserve_mode));
4133
4134 for (dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) {
4135 fprintf(f, "%s%sMode: %04o\n", prefix, exec_directory_type_to_string(dt), c->directories[dt].mode);
4136
4137 STRV_FOREACH(d, c->directories[dt].paths)for ((d) = (c->directories[dt].paths); (d) && *(d)
; (d)++)
4138 fprintf(f, "%s%s: %s\n", prefix, exec_directory_type_to_string(dt), *d);
4139 }
4140
4141 if (c->nice_set)
4142 fprintf(f,
4143 "%sNice: %i\n",
4144 prefix, c->nice);
4145
4146 if (c->oom_score_adjust_set)
4147 fprintf(f,
4148 "%sOOMScoreAdjust: %i\n",
4149 prefix, c->oom_score_adjust);
4150
4151 for (i = 0; i < RLIM_NLIMITS__RLIM_NLIMITS; i++)
4152 if (c->rlimit[i]) {
4153 fprintf(f, "Limit%s%s: " RLIM_FMT"%" "l" "u" "\n",
4154 prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max);
4155 fprintf(f, "Limit%s%sSoft: " RLIM_FMT"%" "l" "u" "\n",
4156 prefix, rlimit_to_string(i), c->rlimit[i]->rlim_cur);
4157 }
4158
4159 if (c->ioprio_set) {
4160 _cleanup_free___attribute__((cleanup(freep))) char *class_str = NULL((void*)0);
4161
4162 r = ioprio_class_to_string_alloc(IOPRIO_PRIO_CLASS(c->ioprio)((c->ioprio) >> 13), &class_str);
4163 if (r >= 0)
4164 fprintf(f, "%sIOSchedulingClass: %s\n", prefix, class_str);
4165
4166 fprintf(f, "%sIOPriority: %lu\n", prefix, IOPRIO_PRIO_DATA(c->ioprio)((c->ioprio) & ((1UL << 13) - 1)));
4167 }
4168
4169 if (c->cpu_sched_set) {
4170 _cleanup_free___attribute__((cleanup(freep))) char *policy_str = NULL((void*)0);
4171
4172 r = sched_policy_to_string_alloc(c->cpu_sched_policy, &policy_str);
4173 if (r >= 0)
4174 fprintf(f, "%sCPUSchedulingPolicy: %s\n", prefix, policy_str);
4175
4176 fprintf(f,
4177 "%sCPUSchedulingPriority: %i\n"
4178 "%sCPUSchedulingResetOnFork: %s\n",
4179 prefix, c->cpu_sched_priority,
4180 prefix, yes_no(c->cpu_sched_reset_on_fork));
4181 }
4182
4183 if (c->cpu_set.set) {
4184 _cleanup_free___attribute__((cleanup(freep))) char *affinity = NULL((void*)0);
4185
4186 affinity = cpu_set_to_range_string(&c->cpu_set);
4187 fprintf(f, "%sCPUAffinity: %s\n", prefix, affinity);
4188 }
4189
4190 if (mpol_is_valid(numa_policy_get_type(&c->numa_policy))) {
4191 _cleanup_free___attribute__((cleanup(freep))) char *nodes = NULL((void*)0);
4192
4193 nodes = cpu_set_to_range_string(&c->numa_policy.nodes);
4194 fprintf(f, "%sNUMAPolicy: %s\n", prefix, mpol_to_string(numa_policy_get_type(&c->numa_policy)));
4195 fprintf(f, "%sNUMAMask: %s\n", prefix, strnull(nodes));
4196 }
4197
4198 if (c->timer_slack_nsec != NSEC_INFINITY((nsec_t) -1))
4199 fprintf(f, "%sTimerSlackNSec: "NSEC_FMT"%" "l" "u" "\n", prefix, c->timer_slack_nsec);
4200
4201 fprintf(f,
4202 "%sStandardInput: %s\n"
4203 "%sStandardOutput: %s\n"
4204 "%sStandardError: %s\n",
4205 prefix, exec_input_to_string(c->std_input),
4206 prefix, exec_output_to_string(c->std_output),
4207 prefix, exec_output_to_string(c->std_error));
4208
4209 if (c->std_input == EXEC_INPUT_NAMED_FD)
4210 fprintf(f, "%sStandardInputFileDescriptorName: %s\n", prefix, c->stdio_fdname[STDIN_FILENO0]);
4211 if (c->std_output == EXEC_OUTPUT_NAMED_FD)
4212 fprintf(f, "%sStandardOutputFileDescriptorName: %s\n", prefix, c->stdio_fdname[STDOUT_FILENO1]);
4213 if (c->std_error == EXEC_OUTPUT_NAMED_FD)
4214 fprintf(f, "%sStandardErrorFileDescriptorName: %s\n", prefix, c->stdio_fdname[STDERR_FILENO2]);
4215
4216 if (c->std_input == EXEC_INPUT_FILE)
4217 fprintf(f, "%sStandardInputFile: %s\n", prefix, c->stdio_file[STDIN_FILENO0]);
4218 if (c->std_output == EXEC_OUTPUT_FILE)
4219 fprintf(f, "%sStandardOutputFile: %s\n", prefix, c->stdio_file[STDOUT_FILENO1]);
4220 if (c->std_output == EXEC_OUTPUT_FILE_APPEND)
4221 fprintf(f, "%sStandardOutputFileToAppend: %s\n", prefix, c->stdio_file[STDOUT_FILENO1]);
4222 if (c->std_error == EXEC_OUTPUT_FILE)
4223 fprintf(f, "%sStandardErrorFile: %s\n", prefix, c->stdio_file[STDERR_FILENO2]);
4224 if (c->std_error == EXEC_OUTPUT_FILE_APPEND)
4225 fprintf(f, "%sStandardErrorFileToAppend: %s\n", prefix, c->stdio_file[STDERR_FILENO2]);
4226
4227 if (c->tty_path)
4228 fprintf(f,
4229 "%sTTYPath: %s\n"
4230 "%sTTYReset: %s\n"
4231 "%sTTYVHangup: %s\n"
4232 "%sTTYVTDisallocate: %s\n",
4233 prefix, c->tty_path,
4234 prefix, yes_no(c->tty_reset),
4235 prefix, yes_no(c->tty_vhangup),
4236 prefix, yes_no(c->tty_vt_disallocate));
4237
4238 if (IN_SET(c->std_output,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_KMSG, EXEC_OUTPUT_JOURNAL
, EXEC_OUTPUT_SYSLOG_AND_CONSOLE, EXEC_OUTPUT_KMSG_AND_CONSOLE
, EXEC_OUTPUT_JOURNAL_AND_CONSOLE})/sizeof(int)]; switch(c->
std_output) { case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_KMSG:
case EXEC_OUTPUT_JOURNAL: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE
: case EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
4239 EXEC_OUTPUT_SYSLOG,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_KMSG, EXEC_OUTPUT_JOURNAL
, EXEC_OUTPUT_SYSLOG_AND_CONSOLE, EXEC_OUTPUT_KMSG_AND_CONSOLE
, EXEC_OUTPUT_JOURNAL_AND_CONSOLE})/sizeof(int)]; switch(c->
std_output) { case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_KMSG:
case EXEC_OUTPUT_JOURNAL: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE
: case EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
4240 EXEC_OUTPUT_KMSG,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_KMSG, EXEC_OUTPUT_JOURNAL
, EXEC_OUTPUT_SYSLOG_AND_CONSOLE, EXEC_OUTPUT_KMSG_AND_CONSOLE
, EXEC_OUTPUT_JOURNAL_AND_CONSOLE})/sizeof(int)]; switch(c->
std_output) { case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_KMSG:
case EXEC_OUTPUT_JOURNAL: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE
: case EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
4241 EXEC_OUTPUT_JOURNAL,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_KMSG, EXEC_OUTPUT_JOURNAL
, EXEC_OUTPUT_SYSLOG_AND_CONSOLE, EXEC_OUTPUT_KMSG_AND_CONSOLE
, EXEC_OUTPUT_JOURNAL_AND_CONSOLE})/sizeof(int)]; switch(c->
std_output) { case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_KMSG:
case EXEC_OUTPUT_JOURNAL: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE
: case EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
4242 EXEC_OUTPUT_SYSLOG_AND_CONSOLE,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_KMSG, EXEC_OUTPUT_JOURNAL
, EXEC_OUTPUT_SYSLOG_AND_CONSOLE, EXEC_OUTPUT_KMSG_AND_CONSOLE
, EXEC_OUTPUT_JOURNAL_AND_CONSOLE})/sizeof(int)]; switch(c->
std_output) { case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_KMSG:
case EXEC_OUTPUT_JOURNAL: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE
: case EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
4243 EXEC_OUTPUT_KMSG_AND_CONSOLE,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_KMSG, EXEC_OUTPUT_JOURNAL
, EXEC_OUTPUT_SYSLOG_AND_CONSOLE, EXEC_OUTPUT_KMSG_AND_CONSOLE
, EXEC_OUTPUT_JOURNAL_AND_CONSOLE})/sizeof(int)]; switch(c->
std_output) { case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_KMSG:
case EXEC_OUTPUT_JOURNAL: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE
: case EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
4244 EXEC_OUTPUT_JOURNAL_AND_CONSOLE)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_KMSG, EXEC_OUTPUT_JOURNAL
, EXEC_OUTPUT_SYSLOG_AND_CONSOLE, EXEC_OUTPUT_KMSG_AND_CONSOLE
, EXEC_OUTPUT_JOURNAL_AND_CONSOLE})/sizeof(int)]; switch(c->
std_output) { case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_KMSG:
case EXEC_OUTPUT_JOURNAL: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE
: case EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
||
4245 IN_SET(c->std_error,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_KMSG, EXEC_OUTPUT_JOURNAL
, EXEC_OUTPUT_SYSLOG_AND_CONSOLE, EXEC_OUTPUT_KMSG_AND_CONSOLE
, EXEC_OUTPUT_JOURNAL_AND_CONSOLE})/sizeof(int)]; switch(c->
std_error) { case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_KMSG: case
EXEC_OUTPUT_JOURNAL: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE: case
EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
4246 EXEC_OUTPUT_SYSLOG,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_KMSG, EXEC_OUTPUT_JOURNAL
, EXEC_OUTPUT_SYSLOG_AND_CONSOLE, EXEC_OUTPUT_KMSG_AND_CONSOLE
, EXEC_OUTPUT_JOURNAL_AND_CONSOLE})/sizeof(int)]; switch(c->
std_error) { case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_KMSG: case
EXEC_OUTPUT_JOURNAL: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE: case
EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
4247 EXEC_OUTPUT_KMSG,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_KMSG, EXEC_OUTPUT_JOURNAL
, EXEC_OUTPUT_SYSLOG_AND_CONSOLE, EXEC_OUTPUT_KMSG_AND_CONSOLE
, EXEC_OUTPUT_JOURNAL_AND_CONSOLE})/sizeof(int)]; switch(c->
std_error) { case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_KMSG: case
EXEC_OUTPUT_JOURNAL: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE: case
EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
4248 EXEC_OUTPUT_JOURNAL,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_KMSG, EXEC_OUTPUT_JOURNAL
, EXEC_OUTPUT_SYSLOG_AND_CONSOLE, EXEC_OUTPUT_KMSG_AND_CONSOLE
, EXEC_OUTPUT_JOURNAL_AND_CONSOLE})/sizeof(int)]; switch(c->
std_error) { case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_KMSG: case
EXEC_OUTPUT_JOURNAL: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE: case
EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
4249 EXEC_OUTPUT_SYSLOG_AND_CONSOLE,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_KMSG, EXEC_OUTPUT_JOURNAL
, EXEC_OUTPUT_SYSLOG_AND_CONSOLE, EXEC_OUTPUT_KMSG_AND_CONSOLE
, EXEC_OUTPUT_JOURNAL_AND_CONSOLE})/sizeof(int)]; switch(c->
std_error) { case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_KMSG: case
EXEC_OUTPUT_JOURNAL: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE: case
EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
4250 EXEC_OUTPUT_KMSG_AND_CONSOLE,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_KMSG, EXEC_OUTPUT_JOURNAL
, EXEC_OUTPUT_SYSLOG_AND_CONSOLE, EXEC_OUTPUT_KMSG_AND_CONSOLE
, EXEC_OUTPUT_JOURNAL_AND_CONSOLE})/sizeof(int)]; switch(c->
std_error) { case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_KMSG: case
EXEC_OUTPUT_JOURNAL: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE: case
EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
4251 EXEC_OUTPUT_JOURNAL_AND_CONSOLE)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_KMSG, EXEC_OUTPUT_JOURNAL
, EXEC_OUTPUT_SYSLOG_AND_CONSOLE, EXEC_OUTPUT_KMSG_AND_CONSOLE
, EXEC_OUTPUT_JOURNAL_AND_CONSOLE})/sizeof(int)]; switch(c->
std_error) { case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_KMSG: case
EXEC_OUTPUT_JOURNAL: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE: case
EXEC_OUTPUT_KMSG_AND_CONSOLE: case EXEC_OUTPUT_JOURNAL_AND_CONSOLE
: _found = 1; break; default: break; } _found; })
) {
4252
4253 _cleanup_free___attribute__((cleanup(freep))) char *fac_str = NULL((void*)0), *lvl_str = NULL((void*)0);
4254
4255 r = log_facility_unshifted_to_string_alloc(c->syslog_priority >> 3, &fac_str);
4256 if (r >= 0)
4257 fprintf(f, "%sSyslogFacility: %s\n", prefix, fac_str);
4258
4259 r = log_level_to_string_alloc(LOG_PRI(c->syslog_priority)((c->syslog_priority) & 0x07), &lvl_str);
4260 if (r >= 0)
4261 fprintf(f, "%sSyslogLevel: %s\n", prefix, lvl_str);
4262 }
4263
4264 if (c->log_level_max >= 0) {
4265 _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0);
4266
4267 (void) log_level_to_string_alloc(c->log_level_max, &t);
4268
4269 fprintf(f, "%sLogLevelMax: %s\n", prefix, strna(t));
4270 }
4271
4272 if (c->log_rate_limit_interval_usec > 0) {
4273 char buf_timespan[FORMAT_TIMESPAN_MAX64];
4274
4275 fprintf(f,
4276 "%sLogRateLimitIntervalSec: %s\n",
4277 prefix, format_timespan(buf_timespan, sizeof(buf_timespan), c->log_rate_limit_interval_usec, USEC_PER_SEC((usec_t) 1000000ULL)));
4278 }
4279
4280 if (c->log_rate_limit_burst > 0)
4281 fprintf(f, "%sLogRateLimitBurst: %u\n", prefix, c->log_rate_limit_burst);
4282
4283 if (c->n_log_extra_fields > 0) {
4284 size_t j;
4285
4286 for (j = 0; j < c->n_log_extra_fields; j++) {
4287 fprintf(f, "%sLogExtraFields: ", prefix);
4288 fwrite(c->log_extra_fields[j].iov_base,
4289 1, c->log_extra_fields[j].iov_len,
4290 f);
4291 fputc('\n', f);
4292 }
4293 }
4294
4295 if (c->secure_bits) {
4296 _cleanup_free___attribute__((cleanup(freep))) char *str = NULL((void*)0);
4297
4298 r = secure_bits_to_string_alloc(c->secure_bits, &str);
4299 if (r >= 0)
4300 fprintf(f, "%sSecure Bits: %s\n", prefix, str);
4301 }
4302
4303 if (c->capability_bounding_set != CAP_ALL(uint64_t) -1) {
4304 _cleanup_free___attribute__((cleanup(freep))) char *str = NULL((void*)0);
4305
4306 r = capability_set_to_string_alloc(c->capability_bounding_set, &str);
4307 if (r >= 0)
4308 fprintf(f, "%sCapabilityBoundingSet: %s\n", prefix, str);
4309 }
4310
4311 if (c->capability_ambient_set != 0) {
4312 _cleanup_free___attribute__((cleanup(freep))) char *str = NULL((void*)0);
4313
4314 r = capability_set_to_string_alloc(c->capability_ambient_set, &str);
4315 if (r >= 0)
4316 fprintf(f, "%sAmbientCapabilities: %s\n", prefix, str);
4317 }
4318
4319 if (c->user)
4320 fprintf(f, "%sUser: %s\n", prefix, c->user);
4321 if (c->group)
4322 fprintf(f, "%sGroup: %s\n", prefix, c->group);
4323
4324 fprintf(f, "%sDynamicUser: %s\n", prefix, yes_no(c->dynamic_user));
4325
4326 if (!strv_isempty(c->supplementary_groups)) {
4327 fprintf(f, "%sSupplementaryGroups:", prefix);
4328 strv_fprintf(f, c->supplementary_groups);
4329 fputs("\n", f);
4330 }
4331
4332 if (c->pam_name)
4333 fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name);
4334
4335 if (!strv_isempty(c->read_write_paths)) {
4336 fprintf(f, "%sReadWritePaths:", prefix);
4337 strv_fprintf(f, c->read_write_paths);
4338 fputs("\n", f);
4339 }
4340
4341 if (!strv_isempty(c->read_only_paths)) {
4342 fprintf(f, "%sReadOnlyPaths:", prefix);
4343 strv_fprintf(f, c->read_only_paths);
4344 fputs("\n", f);
4345 }
4346
4347 if (!strv_isempty(c->inaccessible_paths)) {
4348 fprintf(f, "%sInaccessiblePaths:", prefix);
4349 strv_fprintf(f, c->inaccessible_paths);
4350 fputs("\n", f);
4351 }
4352
4353 if (c->n_bind_mounts > 0)
4354 for (i = 0; i < c->n_bind_mounts; i++)
4355 fprintf(f, "%s%s: %s%s:%s:%s\n", prefix,
4356 c->bind_mounts[i].read_only ? "BindReadOnlyPaths" : "BindPaths",
4357 c->bind_mounts[i].ignore_enoent ? "-": "",
4358 c->bind_mounts[i].source,
4359 c->bind_mounts[i].destination,
4360 c->bind_mounts[i].recursive ? "rbind" : "norbind");
4361
4362 if (c->n_temporary_filesystems > 0)
4363 for (i = 0; i < c->n_temporary_filesystems; i++) {
4364 TemporaryFileSystem *t = c->temporary_filesystems + i;
4365
4366 fprintf(f, "%sTemporaryFileSystem: %s%s%s\n", prefix,
4367 t->path,
4368 isempty(t->options) ? "" : ":",
4369 strempty(t->options));
4370 }
4371
4372 if (c->utmp_id)
4373 fprintf(f,
4374 "%sUtmpIdentifier: %s\n",
4375 prefix, c->utmp_id);
4376
4377 if (c->selinux_context)
4378 fprintf(f,
4379 "%sSELinuxContext: %s%s\n",
4380 prefix, c->selinux_context_ignore ? "-" : "", c->selinux_context);
4381
4382 if (c->apparmor_profile)
4383 fprintf(f,
4384 "%sAppArmorProfile: %s%s\n",
4385 prefix, c->apparmor_profile_ignore ? "-" : "", c->apparmor_profile);
4386
4387 if (c->smack_process_label)
4388 fprintf(f,
4389 "%sSmackProcessLabel: %s%s\n",
4390 prefix, c->smack_process_label_ignore ? "-" : "", c->smack_process_label);
4391
4392 if (c->personality != PERSONALITY_INVALID0xffffffffLU)
4393 fprintf(f,
4394 "%sPersonality: %s\n",
4395 prefix, strna(personality_to_string(c->personality)));
4396
4397 fprintf(f,
4398 "%sLockPersonality: %s\n",
4399 prefix, yes_no(c->lock_personality));
4400
4401 if (c->syscall_filter) {
4402#if HAVE_SECCOMP1
4403 Iterator j;
4404 void *id, *val;
4405 bool_Bool first = true1;
4406#endif
4407
4408 fprintf(f,
4409 "%sSystemCallFilter: ",
4410 prefix);
4411
4412 if (!c->syscall_whitelist)
4413 fputc('~', f);
4414
4415#if HAVE_SECCOMP1
4416 HASHMAP_FOREACH_KEY(val, id, c->syscall_filter, j)for ((j) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), .
next_key = ((void*)0) }); hashmap_iterate((c->syscall_filter
), &(j), (void**)&(val), (const void**) &(id)); )
{
4417 _cleanup_free___attribute__((cleanup(freep))) char *name = NULL((void*)0);
4418 const char *errno_name = NULL((void*)0);
4419 int num = PTR_TO_INT(val)((int) ((intptr_t) (val)));
4420
4421 if (first)
4422 first = false0;
4423 else
4424 fputc(' ', f);
4425
4426 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE0, PTR_TO_INT(id)((int) ((intptr_t) (id))) - 1);
4427 fputs(strna(name), f);
4428
4429 if (num >= 0) {
4430 errno_name = errno_to_name(num);
4431 if (errno_name)
4432 fprintf(f, ":%s", errno_name);
4433 else
4434 fprintf(f, ":%d", num);
4435 }
4436 }
4437#endif
4438
4439 fputc('\n', f);
4440 }
4441
4442 if (c->syscall_archs) {
4443#if HAVE_SECCOMP1
4444 Iterator j;
4445 void *id;
4446#endif
4447
4448 fprintf(f,
4449 "%sSystemCallArchitectures:",
4450 prefix);
4451
4452#if HAVE_SECCOMP1
4453 SET_FOREACH(id, c->syscall_archs, j)for ((j) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), .
next_key = ((void*)0) }); set_iterate((c->syscall_archs), &
(j), (void**)&(id)); )
4454 fprintf(f, " %s", strna(seccomp_arch_to_string(PTR_TO_UINT32(id)((uint32_t) ((uintptr_t) (id))) - 1)));
4455#endif
4456 fputc('\n', f);
4457 }
4458
4459 if (exec_context_restrict_namespaces_set(c)) {
4460 _cleanup_free___attribute__((cleanup(freep))) char *s = NULL((void*)0);
4461
4462 r = namespace_flags_to_string(c->restrict_namespaces, &s);
4463 if (r >= 0)
4464 fprintf(f, "%sRestrictNamespaces: %s\n",
4465 prefix, s);
4466 }
4467
4468 if (c->syscall_errno > 0) {
4469 const char *errno_name;
4470
4471 fprintf(f, "%sSystemCallErrorNumber: ", prefix);
4472
4473 errno_name = errno_to_name(c->syscall_errno);
4474 if (errno_name)
4475 fprintf(f, "%s\n", errno_name);
4476 else
4477 fprintf(f, "%d\n", c->syscall_errno);
4478 }
4479
4480 if (c->apparmor_profile)
4481 fprintf(f,
4482 "%sAppArmorProfile: %s%s\n",
4483 prefix, c->apparmor_profile_ignore ? "-" : "", c->apparmor_profile);
4484}
4485
4486bool_Bool exec_context_maintains_privileges(const ExecContext *c) {
4487 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 4487, __PRETTY_FUNCTION__
); } while (0)
;
4488
4489 /* Returns true if the process forked off would run under
4490 * an unchanged UID or as root. */
4491
4492 if (!c->user)
4493 return true1;
4494
4495 if (streq(c->user, "root")(strcmp((c->user),("root")) == 0) || streq(c->user, "0")(strcmp((c->user),("0")) == 0))
4496 return true1;
4497
4498 return false0;
4499}
4500
4501int exec_context_get_effective_ioprio(const ExecContext *c) {
4502 int p;
4503
4504 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 4504, __PRETTY_FUNCTION__
); } while (0)
;
4505
4506 if (c->ioprio_set)
4507 return c->ioprio;
4508
4509 p = ioprio_get(IOPRIO_WHO_PROCESS, 0);
4510 if (p < 0)
4511 return IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 4)(((IOPRIO_CLASS_BE) << 13) | 4);
4512
4513 return p;
4514}
4515
4516void exec_context_free_log_extra_fields(ExecContext *c) {
4517 size_t l;
4518
4519 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 4519, __PRETTY_FUNCTION__
); } while (0)
;
4520
4521 for (l = 0; l < c->n_log_extra_fields; l++)
4522 free(c->log_extra_fields[l].iov_base);
4523 c->log_extra_fields = mfree(c->log_extra_fields);
4524 c->n_log_extra_fields = 0;
4525}
4526
4527void exec_status_start(ExecStatus *s, pid_t pid) {
4528 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/core/execute.c", 4528, __PRETTY_FUNCTION__
); } while (0)
;
4529
4530 zero(*s)(({ size_t _l_ = (sizeof(*s)); void *_x_ = (&(*s)); _l_ ==
0 ? _x_ : memset(_x_, 0, _l_); }))
;
4531 s->pid = pid;
4532 dual_timestamp_get(&s->start_timestamp);
4533}
4534
4535void exec_status_exit(ExecStatus *s, const ExecContext *context, pid_t pid, int code, int status) {
4536 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/core/execute.c", 4536, __PRETTY_FUNCTION__
); } while (0)
;
4537
4538 if (s->pid && s->pid != pid)
4539 zero(*s)(({ size_t _l_ = (sizeof(*s)); void *_x_ = (&(*s)); _l_ ==
0 ? _x_ : memset(_x_, 0, _l_); }))
;
4540
4541 s->pid = pid;
4542 dual_timestamp_get(&s->exit_timestamp);
4543
4544 s->code = code;
4545 s->status = status;
4546
4547 if (context) {
4548 if (context->utmp_id)
4549 utmp_put_dead_process(context->utmp_id, pid, code, status);
4550
4551 exec_context_tty_reset(context, NULL((void*)0));
4552 }
4553}
4554
4555void exec_status_dump(const ExecStatus *s, FILE *f, const char *prefix) {
4556 char buf[FORMAT_TIMESTAMP_MAX(3+1+10+1+8+1+6+1+6+1)];
4557
4558 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/core/execute.c", 4558, __PRETTY_FUNCTION__
); } while (0)
;
4559 assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("f"), "../src/core/execute.c", 4559, __PRETTY_FUNCTION__
); } while (0)
;
4560
4561 if (s->pid <= 0)
4562 return;
4563
4564 prefix = strempty(prefix);
4565
4566 fprintf(f,
4567 "%sPID: "PID_FMT"%" "i""\n",
4568 prefix, s->pid);
4569
4570 if (dual_timestamp_is_set(&s->start_timestamp))
4571 fprintf(f,
4572 "%sStart Timestamp: %s\n",
4573 prefix, format_timestamp(buf, sizeof(buf), s->start_timestamp.realtime));
4574
4575 if (dual_timestamp_is_set(&s->exit_timestamp))
4576 fprintf(f,
4577 "%sExit Timestamp: %s\n"
4578 "%sExit Code: %s\n"
4579 "%sExit Status: %i\n",
4580 prefix, format_timestamp(buf, sizeof(buf), s->exit_timestamp.realtime),
4581 prefix, sigchld_code_to_string(s->code),
4582 prefix, s->status);
4583}
4584
4585static char *exec_command_line(char **argv) {
4586 size_t k;
4587 char *n, *p, **a;
4588 bool_Bool first = true1;
4589
4590 assert(argv)do { if ((__builtin_expect(!!(!(argv)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("argv"), "../src/core/execute.c", 4590, __PRETTY_FUNCTION__
); } while (0)
;
4591
4592 k = 1;
4593 STRV_FOREACH(a, argv)for ((a) = (argv); (a) && *(a); (a)++)
4594 k += strlen(*a)+3;
4595
4596 n = new(char, k)((char*) malloc_multiply(sizeof(char), (k)));
4597 if (!n)
4598 return NULL((void*)0);
4599
4600 p = n;
4601 STRV_FOREACH(a, argv)for ((a) = (argv); (a) && *(a); (a)++) {
4602
4603 if (!first)
4604 *(p++) = ' ';
4605 else
4606 first = false0;
4607
4608 if (strpbrk(*a, WHITESPACE" \t\n\r")) {
4609 *(p++) = '\'';
4610 p = stpcpy(p, *a);
4611 *(p++) = '\'';
4612 } else
4613 p = stpcpy(p, *a);
4614
4615 }
4616
4617 *p = 0;
4618
4619 /* FIXME: this doesn't really handle arguments that have
4620 * spaces and ticks in them */
4621
4622 return n;
4623}
4624
4625static void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
4626 _cleanup_free___attribute__((cleanup(freep))) char *cmd = NULL((void*)0);
4627 const char *prefix2;
4628
4629 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 4629, __PRETTY_FUNCTION__
); } while (0)
;
4630 assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("f"), "../src/core/execute.c", 4630, __PRETTY_FUNCTION__
); } while (0)
;
4631
4632 prefix = strempty(prefix);
4633 prefix2 = strjoina(prefix, "\t")({ const char *_appendees_[] = { prefix, "\t" }; char *_d_, *
_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
4634
4635 cmd = exec_command_line(c->argv);
4636 fprintf(f,
4637 "%sCommand Line: %s\n",
4638 prefix, cmd ? cmd : strerror(ENOMEM12));
4639
4640 exec_status_dump(&c->exec_status, f, prefix2);
4641}
4642
4643void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) {
4644 assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("f"), "../src/core/execute.c", 4644, __PRETTY_FUNCTION__
); } while (0)
;
4645
4646 prefix = strempty(prefix);
4647
4648 LIST_FOREACH(command, c, c)for ((c) = (c); (c); (c) = (c)->command_next)
4649 exec_command_dump(c, f, prefix);
4650}
4651
4652void exec_command_append_list(ExecCommand **l, ExecCommand *e) {
4653 ExecCommand *end;
4654
4655 assert(l)do { if ((__builtin_expect(!!(!(l)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("l"), "../src/core/execute.c", 4655, __PRETTY_FUNCTION__
); } while (0)
;
4656 assert(e)do { if ((__builtin_expect(!!(!(e)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("e"), "../src/core/execute.c", 4656, __PRETTY_FUNCTION__
); } while (0)
;
4657
4658 if (*l) {
4659 /* It's kind of important, that we keep the order here */
4660 LIST_FIND_TAIL(command, *l, end)do { typeof(*(*l)) *_item = (*l); if (!_item) (end) = ((void*
)0); else { while (_item->command_next) _item = _item->
command_next; (end) = _item; } } while (0)
;
4661 LIST_INSERT_AFTER(command, *l, end, e)do { typeof(*(*l)) **_head = &(*l), *_a = (end), *_b = (e
); do { if ((__builtin_expect(!!(!(_b)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("_b"), "../src/core/execute.c", 4661, __PRETTY_FUNCTION__
); } while (0); if (!_a) { if ((_b->command_next = *_head)
) _b->command_next->command_prev = _b; _b->command_prev
= ((void*)0); *_head = _b; } else { if ((_b->command_next
= _a->command_next)) _b->command_next->command_prev
= _b; _b->command_prev = _a; _a->command_next = _b; } }
while (0)
;
4662 } else
4663 *l = e;
4664}
4665
4666int exec_command_set(ExecCommand *c, const char *path, ...) {
4667 va_list ap;
4668 char **l, *p;
4669
4670 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 4670, __PRETTY_FUNCTION__
); } while (0)
;
4671 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/core/execute.c", 4671, __PRETTY_FUNCTION__
); } while (0)
;
4672
4673 va_start(ap, path)__builtin_va_start(ap, path);
4674 l = strv_new_ap(path, ap);
4675 va_end(ap)__builtin_va_end(ap);
4676
4677 if (!l)
4678 return -ENOMEM12;
4679
4680 p = strdup(path);
4681 if (!p) {
4682 strv_free(l);
4683 return -ENOMEM12;
4684 }
4685
4686 free(c->path);
4687 c->path = p;
4688
4689 return strv_free_and_replace(c->argv, l)({ strv_free(c->argv); (c->argv) = (l); (l) = ((void*)0
); 0; })
;
4690}
4691
4692int exec_command_append(ExecCommand *c, const char *path, ...) {
4693 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **l = NULL((void*)0);
4694 va_list ap;
4695 int r;
4696
4697 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 4697, __PRETTY_FUNCTION__
); } while (0)
;
4698 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/core/execute.c", 4698, __PRETTY_FUNCTION__
); } while (0)
;
4699
4700 va_start(ap, path)__builtin_va_start(ap, path);
4701 l = strv_new_ap(path, ap);
4702 va_end(ap)__builtin_va_end(ap);
4703
4704 if (!l)
4705 return -ENOMEM12;
4706
4707 r = strv_extend_strv(&c->argv, l, false0);
4708 if (r < 0)
4709 return r;
4710
4711 return 0;
4712}
4713
4714static void *remove_tmpdir_thread(void *p) {
4715 _cleanup_free___attribute__((cleanup(freep))) char *path = p;
4716
4717 (void) rm_rf(path, REMOVE_ROOT|REMOVE_PHYSICAL);
4718 return NULL((void*)0);
4719}
4720
4721static ExecRuntime* exec_runtime_free(ExecRuntime *rt, bool_Bool destroy) {
4722 int r;
4723
4724 if (!rt)
4725 return NULL((void*)0);
4726
4727 if (rt->manager)
4728 (void) hashmap_remove(rt->manager->exec_runtime_by_id, rt->id);
4729
4730 /* When destroy is true, then rm_rf tmp_dir and var_tmp_dir. */
4731 if (destroy && rt->tmp_dir) {
4732 log_debug("Spawning thread to nuke %s", rt->tmp_dir)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/core/execute.c", 4732, __func__, "Spawning thread to nuke %s"
, rt->tmp_dir) : -abs(_e); })
;
4733
4734 r = asynchronous_job(remove_tmpdir_thread, rt->tmp_dir);
4735 if (r < 0) {
4736 log_warning_errno(r, "Failed to nuke %s: %m", rt->tmp_dir)({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/core/execute.c", 4736, __func__, "Failed to nuke %s: %m"
, rt->tmp_dir) : -abs(_e); })
;
4737 free(rt->tmp_dir);
4738 }
4739
4740 rt->tmp_dir = NULL((void*)0);
4741 }
4742
4743 if (destroy && rt->var_tmp_dir) {
4744 log_debug("Spawning thread to nuke %s", rt->var_tmp_dir)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/core/execute.c", 4744, __func__, "Spawning thread to nuke %s"
, rt->var_tmp_dir) : -abs(_e); })
;
4745
4746 r = asynchronous_job(remove_tmpdir_thread, rt->var_tmp_dir);
4747 if (r < 0) {
4748 log_warning_errno(r, "Failed to nuke %s: %m", rt->var_tmp_dir)({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/core/execute.c", 4748, __func__, "Failed to nuke %s: %m"
, rt->var_tmp_dir) : -abs(_e); })
;
4749 free(rt->var_tmp_dir);
4750 }
4751
4752 rt->var_tmp_dir = NULL((void*)0);
4753 }
4754
4755 rt->id = mfree(rt->id);
4756 rt->tmp_dir = mfree(rt->tmp_dir);
4757 rt->var_tmp_dir = mfree(rt->var_tmp_dir);
4758 safe_close_pair(rt->netns_storage_socket);
4759 return mfree(rt);
4760}
4761
4762static void exec_runtime_freep(ExecRuntime **rt) {
4763 if (*rt)
4764 (void) exec_runtime_free(*rt, false0);
4765}
4766
4767static int exec_runtime_allocate(ExecRuntime **rt) {
4768 assert(rt)do { if ((__builtin_expect(!!(!(rt)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rt"), "../src/core/execute.c", 4768, __PRETTY_FUNCTION__
); } while (0)
;
4769
4770 *rt = new0(ExecRuntime, 1)((ExecRuntime*) calloc((1), sizeof(ExecRuntime)));
4771 if (!*rt)
4772 return -ENOMEM12;
4773
4774 (*rt)->netns_storage_socket[0] = (*rt)->netns_storage_socket[1] = -1;
4775 return 0;
4776}
4777
4778static int exec_runtime_add(
4779 Manager *m,
4780 const char *id,
4781 const char *tmp_dir,
4782 const char *var_tmp_dir,
4783 const int netns_storage_socket[2],
4784 ExecRuntime **ret) {
4785
4786 _cleanup_(exec_runtime_freep)__attribute__((cleanup(exec_runtime_freep))) ExecRuntime *rt = NULL((void*)0);
4787 int r;
4788
4789 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/core/execute.c", 4789, __PRETTY_FUNCTION__
); } while (0)
;
4790 assert(id)do { if ((__builtin_expect(!!(!(id)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("id"), "../src/core/execute.c", 4790, __PRETTY_FUNCTION__
); } while (0)
;
4791
4792 r = hashmap_ensure_allocated(&m->exec_runtime_by_id, &string_hash_ops)internal_hashmap_ensure_allocated(&m->exec_runtime_by_id
, &string_hash_ops )
;
4793 if (r < 0)
4794 return r;
4795
4796 r = exec_runtime_allocate(&rt);
4797 if (r < 0)
4798 return r;
4799
4800 rt->id = strdup(id);
4801 if (!rt->id)
4802 return -ENOMEM12;
4803
4804 if (tmp_dir) {
4805 rt->tmp_dir = strdup(tmp_dir);
4806 if (!rt->tmp_dir)
4807 return -ENOMEM12;
4808
4809 /* When tmp_dir is set, then we require var_tmp_dir is also set. */
4810 assert(var_tmp_dir)do { if ((__builtin_expect(!!(!(var_tmp_dir)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("var_tmp_dir"), "../src/core/execute.c",
4810, __PRETTY_FUNCTION__); } while (0)
;
4811 rt->var_tmp_dir = strdup(var_tmp_dir);
4812 if (!rt->var_tmp_dir)
4813 return -ENOMEM12;
4814 }
4815
4816 if (netns_storage_socket) {
4817 rt->netns_storage_socket[0] = netns_storage_socket[0];
4818 rt->netns_storage_socket[1] = netns_storage_socket[1];
4819 }
4820
4821 r = hashmap_put(m->exec_runtime_by_id, rt->id, rt);
4822 if (r < 0)
4823 return r;
4824
4825 rt->manager = m;
4826
4827 if (ret)
4828 *ret = rt;
4829
4830 /* do not remove created ExecRuntime object when the operation succeeds. */
4831 rt = NULL((void*)0);
4832 return 0;
4833}
4834
4835static int exec_runtime_make(Manager *m, const ExecContext *c, const char *id, ExecRuntime **ret) {
4836 _cleanup_free___attribute__((cleanup(freep))) char *tmp_dir = NULL((void*)0), *var_tmp_dir = NULL((void*)0);
4837 _cleanup_close_pair___attribute__((cleanup(close_pairp))) int netns_storage_socket[2] = {-1, -1};
4838 int r;
4839
4840 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/core/execute.c", 4840, __PRETTY_FUNCTION__
); } while (0)
;
4841 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/core/execute.c", 4841, __PRETTY_FUNCTION__
); } while (0)
;
4842 assert(id)do { if ((__builtin_expect(!!(!(id)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("id"), "../src/core/execute.c", 4842, __PRETTY_FUNCTION__
); } while (0)
;
4843
4844 /* It is not necessary to create ExecRuntime object. */
4845 if (!c->private_network && !c->private_tmp)
4846 return 0;
4847
4848 if (c->private_tmp) {
4849 r = setup_tmp_dirs(id, &tmp_dir, &var_tmp_dir);
4850 if (r < 0)
4851 return r;
4852 }
4853
4854 if (c->private_network) {
4855 if (socketpair(AF_UNIX1, SOCK_DGRAMSOCK_DGRAM|SOCK_CLOEXECSOCK_CLOEXEC, 0, netns_storage_socket) < 0)
4856 return -errno(*__errno_location ());
4857 }
4858
4859 r = exec_runtime_add(m, id, tmp_dir, var_tmp_dir, netns_storage_socket, ret);
4860 if (r < 0)
4861 return r;
4862
4863 /* Avoid cleanup */
4864 netns_storage_socket[0] = -1;
4865 netns_storage_socket[1] = -1;
4866 return 1;
4867}
4868
4869int exec_runtime_acquire(Manager *m, const ExecContext *c, const char *id, bool_Bool create, ExecRuntime **ret) {
4870 ExecRuntime *rt;
4871 int r;
4872
4873 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/core/execute.c", 4873, __PRETTY_FUNCTION__
); } while (0)
;
4874 assert(id)do { if ((__builtin_expect(!!(!(id)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("id"), "../src/core/execute.c", 4874, __PRETTY_FUNCTION__
); } while (0)
;
4875 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/core/execute.c", 4875, __PRETTY_FUNCTION__
); } while (0)
;
4876
4877 rt = hashmap_get(m->exec_runtime_by_id, id);
4878 if (rt)
4879 /* We already have a ExecRuntime object, let's increase the ref count and reuse it */
4880 goto ref;
4881
4882 if (!create)
4883 return 0;
4884
4885 /* If not found, then create a new object. */
4886 r = exec_runtime_make(m, c, id, &rt);
4887 if (r <= 0)
4888 /* When r == 0, it is not necessary to create ExecRuntime object. */
4889 return r;
4890
4891ref:
4892 /* increment reference counter. */
4893 rt->n_ref++;
4894 *ret = rt;
4895 return 1;
4896}
4897
4898ExecRuntime *exec_runtime_unref(ExecRuntime *rt, bool_Bool destroy) {
4899 if (!rt)
4900 return NULL((void*)0);
4901
4902 assert(rt->n_ref > 0)do { if ((__builtin_expect(!!(!(rt->n_ref > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rt->n_ref > 0"), "../src/core/execute.c"
, 4902, __PRETTY_FUNCTION__); } while (0)
;
4903
4904 rt->n_ref--;
4905 if (rt->n_ref > 0)
4906 return NULL((void*)0);
4907
4908 return exec_runtime_free(rt, destroy);
4909}
4910
4911int exec_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) {
4912 ExecRuntime *rt;
4913 Iterator i;
4914
4915 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/core/execute.c", 4915, __PRETTY_FUNCTION__
); } while (0)
;
4916 assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("f"), "../src/core/execute.c", 4916, __PRETTY_FUNCTION__
); } while (0)
;
4917 assert(fds)do { if ((__builtin_expect(!!(!(fds)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fds"), "../src/core/execute.c", 4917, __PRETTY_FUNCTION__
); } while (0)
;
4918
4919 HASHMAP_FOREACH(rt, m->exec_runtime_by_id, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), .
next_key = ((void*)0) }); hashmap_iterate((m->exec_runtime_by_id
), &(i), (void**)&(rt), ((void*)0)); )
{
4920 fprintf(f, "exec-runtime=%s", rt->id);
4921
4922 if (rt->tmp_dir)
4923 fprintf(f, " tmp-dir=%s", rt->tmp_dir);
4924
4925 if (rt->var_tmp_dir)
4926 fprintf(f, " var-tmp-dir=%s", rt->var_tmp_dir);
4927
4928 if (rt->netns_storage_socket[0] >= 0) {
4929 int copy;
4930
4931 copy = fdset_put_dup(fds, rt->netns_storage_socket[0]);
4932 if (copy < 0)
4933 return copy;
4934
4935 fprintf(f, " netns-socket-0=%i", copy);
4936 }
4937
4938 if (rt->netns_storage_socket[1] >= 0) {
4939 int copy;
4940
4941 copy = fdset_put_dup(fds, rt->netns_storage_socket[1]);
4942 if (copy < 0)
4943 return copy;
4944
4945 fprintf(f, " netns-socket-1=%i", copy);
4946 }
4947
4948 fputc('\n', f);
4949 }
4950
4951 return 0;
4952}
4953
4954int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value, FDSet *fds) {
4955 _cleanup_(exec_runtime_freep)__attribute__((cleanup(exec_runtime_freep))) ExecRuntime *rt_create = NULL((void*)0);
4956 ExecRuntime *rt;
4957 int r;
4958
4959 /* This is for the migration from old (v237 or earlier) deserialization text.
4960 * Due to the bug #7790, this may not work with the units that use JoinsNamespaceOf=.
4961 * Even if the ExecRuntime object originally created by the other unit, we cannot judge
4962 * so or not from the serialized text, then we always creates a new object owned by this. */
4963
4964 assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("u"), "../src/core/execute.c", 4964, __PRETTY_FUNCTION__
); } while (0)
;
4965 assert(key)do { if ((__builtin_expect(!!(!(key)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("key"), "../src/core/execute.c", 4965, __PRETTY_FUNCTION__
); } while (0)
;
4966 assert(value)do { if ((__builtin_expect(!!(!(value)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("value"), "../src/core/execute.c", 4966,
__PRETTY_FUNCTION__); } while (0)
;
4967
4968 /* Manager manages ExecRuntime objects by the unit id.
4969 * So, we omit the serialized text when the unit does not have id (yet?)... */
4970 if (isempty(u->id)) {
4971 log_unit_debug(u, "Invocation ID not found. Dropping runtime parameter.")({ const Unit *_u = (u); _u ? log_object_internal(7, 0, "../src/core/execute.c"
, 4971, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Invocation ID not found. Dropping runtime parameter.") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/core/execute.c"
, 4971, __func__, "Invocation ID not found. Dropping runtime parameter."
); })
;
4972 return 0;
4973 }
4974
4975 r = hashmap_ensure_allocated(&u->manager->exec_runtime_by_id, &string_hash_ops)internal_hashmap_ensure_allocated(&u->manager->exec_runtime_by_id
, &string_hash_ops )
;
4976 if (r < 0) {
4977 log_unit_debug_errno(u, r, "Failed to allocate storage for runtime parameter: %m")({ const Unit *_u = (u); _u ? log_object_internal(7, r, "../src/core/execute.c"
, 4977, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to allocate storage for runtime parameter: %m") : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((7))), r, "../src/core/execute.c"
, 4977, __func__, "Failed to allocate storage for runtime parameter: %m"
); })
;
4978 return 0;
4979 }
4980
4981 rt = hashmap_get(u->manager->exec_runtime_by_id, u->id);
4982 if (!rt) {
4983 r = exec_runtime_allocate(&rt_create);
4984 if (r < 0)
4985 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/core/execute.c", 4985
, __func__)
;
4986
4987 rt_create->id = strdup(u->id);
4988 if (!rt_create->id)
4989 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/core/execute.c", 4989
, __func__)
;
4990
4991 rt = rt_create;
4992 }
4993
4994 if (streq(key, "tmp-dir")(strcmp((key),("tmp-dir")) == 0)) {
4995 char *copy;
4996
4997 copy = strdup(value);
4998 if (!copy)
4999 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/core/execute.c", 4999
, __func__)
;
5000
5001 free_and_replace(rt->tmp_dir, copy)({ free(rt->tmp_dir); (rt->tmp_dir) = (copy); (copy) = (
(void*)0); 0; })
;
5002
5003 } else if (streq(key, "var-tmp-dir")(strcmp((key),("var-tmp-dir")) == 0)) {
5004 char *copy;
5005
5006 copy = strdup(value);
5007 if (!copy)
5008 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/core/execute.c", 5008
, __func__)
;
5009
5010 free_and_replace(rt->var_tmp_dir, copy)({ free(rt->var_tmp_dir); (rt->var_tmp_dir) = (copy); (
copy) = ((void*)0); 0; })
;
5011
5012 } else if (streq(key, "netns-socket-0")(strcmp((key),("netns-socket-0")) == 0)) {
5013 int fd;
5014
5015 if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) {
5016 log_unit_debug(u, "Failed to parse netns socket value: %s", value)({ const Unit *_u = (u); _u ? log_object_internal(7, 0, "../src/core/execute.c"
, 5016, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to parse netns socket value: %s", value) : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/core/execute.c"
, 5016, __func__, "Failed to parse netns socket value: %s", value
); })
;
5017 return 0;
5018 }
5019
5020 safe_close(rt->netns_storage_socket[0]);
5021 rt->netns_storage_socket[0] = fdset_remove(fds, fd);
5022
5023 } else if (streq(key, "netns-socket-1")(strcmp((key),("netns-socket-1")) == 0)) {
5024 int fd;
5025
5026 if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) {
5027 log_unit_debug(u, "Failed to parse netns socket value: %s", value)({ const Unit *_u = (u); _u ? log_object_internal(7, 0, "../src/core/execute.c"
, 5027, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to parse netns socket value: %s", value) : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/core/execute.c"
, 5027, __func__, "Failed to parse netns socket value: %s", value
); })
;
5028 return 0;
5029 }
5030
5031 safe_close(rt->netns_storage_socket[1]);
5032 rt->netns_storage_socket[1] = fdset_remove(fds, fd);
5033 } else
5034 return 0;
5035
5036 /* If the object is newly created, then put it to the hashmap which manages ExecRuntime objects. */
5037 if (rt_create) {
5038 r = hashmap_put(u->manager->exec_runtime_by_id, rt_create->id, rt_create);
5039 if (r < 0) {
5040 log_unit_debug_errno(u, r, "Failed to put runtime parameter to manager's storage: %m")({ const Unit *_u = (u); _u ? log_object_internal(7, r, "../src/core/execute.c"
, 5040, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to put runtime parameter to manager's storage: %m")
: log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7)
)), r, "../src/core/execute.c", 5040, __func__, "Failed to put runtime parameter to manager's storage: %m"
); })
;
5041 return 0;
5042 }
5043
5044 rt_create->manager = u->manager;
5045
5046 /* Avoid cleanup */
5047 rt_create = NULL((void*)0);
5048 }
5049
5050 return 1;
5051}
5052
5053void exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
5054 char *id = NULL((void*)0), *tmp_dir = NULL((void*)0), *var_tmp_dir = NULL((void*)0);
5055 int r, fd0 = -1, fd1 = -1;
5056 const char *p, *v = value;
5057 size_t n;
5058
5059 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/core/execute.c", 5059, __PRETTY_FUNCTION__
); } while (0)
;
5060 assert(value)do { if ((__builtin_expect(!!(!(value)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("value"), "../src/core/execute.c", 5060,
__PRETTY_FUNCTION__); } while (0)
;
5061 assert(fds)do { if ((__builtin_expect(!!(!(fds)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fds"), "../src/core/execute.c", 5061, __PRETTY_FUNCTION__
); } while (0)
;
5062
5063 n = strcspn(v, " ");
5064 id = strndupa(v, n)(__extension__ ({ const char *__old = (v); size_t __len = strnlen
(__old, (n)); char *__new = (char *) __builtin_alloca (__len
+ 1); __new[__len] = '\0'; (char *) memcpy (__new, __old, __len
); }))
;
5065 if (v[n] != ' ')
5066 goto finalize;
5067 p = v + n + 1;
5068
5069 v = startswith(p, "tmp-dir=");
5070 if (v) {
5071 n = strcspn(v, " ");
5072 tmp_dir = strndupa(v, n)(__extension__ ({ const char *__old = (v); size_t __len = strnlen
(__old, (n)); char *__new = (char *) __builtin_alloca (__len
+ 1); __new[__len] = '\0'; (char *) memcpy (__new, __old, __len
); }))
;
5073 if (v[n] != ' ')
5074 goto finalize;
5075 p = v + n + 1;
5076 }
5077
5078 v = startswith(p, "var-tmp-dir=");
5079 if (v) {
5080 n = strcspn(v, " ");
5081 var_tmp_dir = strndupa(v, n)(__extension__ ({ const char *__old = (v); size_t __len = strnlen
(__old, (n)); char *__new = (char *) __builtin_alloca (__len
+ 1); __new[__len] = '\0'; (char *) memcpy (__new, __old, __len
); }))
;
5082 if (v[n] != ' ')
5083 goto finalize;
5084 p = v + n + 1;
5085 }
5086
5087 v = startswith(p, "netns-socket-0=");
5088 if (v) {
5089 char *buf;
5090
5091 n = strcspn(v, " ");
5092 buf = strndupa(v, n)(__extension__ ({ const char *__old = (v); size_t __len = strnlen
(__old, (n)); char *__new = (char *) __builtin_alloca (__len
+ 1); __new[__len] = '\0'; (char *) memcpy (__new, __old, __len
); }))
;
5093 if (safe_atoi(buf, &fd0) < 0 || !fdset_contains(fds, fd0)) {
5094 log_debug("Unable to process exec-runtime netns fd specification.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/core/execute.c", 5094, __func__, "Unable to process exec-runtime netns fd specification."
) : -abs(_e); })
;
5095 return;
5096 }
5097 fd0 = fdset_remove(fds, fd0);
5098 if (v[n] != ' ')
5099 goto finalize;
5100 p = v + n + 1;
5101 }
5102
5103 v = startswith(p, "netns-socket-1=");
5104 if (v) {
5105 char *buf;
5106
5107 n = strcspn(v, " ");
5108 buf = strndupa(v, n)(__extension__ ({ const char *__old = (v); size_t __len = strnlen
(__old, (n)); char *__new = (char *) __builtin_alloca (__len
+ 1); __new[__len] = '\0'; (char *) memcpy (__new, __old, __len
); }))
;
5109 if (safe_atoi(buf, &fd1) < 0 || !fdset_contains(fds, fd1)) {
5110 log_debug("Unable to process exec-runtime netns fd specification.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/core/execute.c", 5110, __func__, "Unable to process exec-runtime netns fd specification."
) : -abs(_e); })
;
5111 return;
5112 }
5113 fd1 = fdset_remove(fds, fd1);
5114 }
5115
5116finalize:
5117
5118 r = exec_runtime_add(m, id, tmp_dir, var_tmp_dir, (int[]) { fd0, fd1 }, NULL((void*)0));
5119 if (r < 0) {
5120 log_debug_errno(r, "Failed to add exec-runtime: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/core/execute.c", 5120, __func__, "Failed to add exec-runtime: %m"
) : -abs(_e); })
;
5121 return;
5122 }
5123}
5124
5125void exec_runtime_vacuum(Manager *m) {
5126 ExecRuntime *rt;
5127 Iterator i;
5128
5129 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/core/execute.c", 5129, __PRETTY_FUNCTION__
); } while (0)
;
5130
5131 /* Free unreferenced ExecRuntime objects. This is used after manager deserialization process. */
5132
5133 HASHMAP_FOREACH(rt, m->exec_runtime_by_id, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), .
next_key = ((void*)0) }); hashmap_iterate((m->exec_runtime_by_id
), &(i), (void**)&(rt), ((void*)0)); )
{
5134 if (rt->n_ref > 0)
5135 continue;
5136
5137 (void) exec_runtime_free(rt, false0);
5138 }
5139}
5140
5141static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
5142 [EXEC_INPUT_NULL] = "null",
5143 [EXEC_INPUT_TTY] = "tty",
5144 [EXEC_INPUT_TTY_FORCE] = "tty-force",
5145 [EXEC_INPUT_TTY_FAIL] = "tty-fail",
5146 [EXEC_INPUT_SOCKET] = "socket",
5147 [EXEC_INPUT_NAMED_FD] = "fd",
5148 [EXEC_INPUT_DATA] = "data",
5149 [EXEC_INPUT_FILE] = "file",
5150};
5151
5152DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput)const char *exec_input_to_string(ExecInput i) { if (i < 0 ||
i >= (ExecInput) __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(exec_input_table), typeof(&*(exec_input_table))),
sizeof(exec_input_table)/sizeof((exec_input_table)[0]), ((void
)0)))) return ((void*)0); return exec_input_table[i]; } ExecInput
exec_input_from_string(const char *s) { return (ExecInput) string_table_lookup
(exec_input_table, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(exec_input_table), typeof(&*(exec_input_table))),
sizeof(exec_input_table)/sizeof((exec_input_table)[0]), ((void
)0))), s); }
;
5153
5154static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
5155 [EXEC_OUTPUT_INHERIT] = "inherit",
5156 [EXEC_OUTPUT_NULL] = "null",
5157 [EXEC_OUTPUT_TTY] = "tty",
5158 [EXEC_OUTPUT_SYSLOG] = "syslog",
5159 [EXEC_OUTPUT_SYSLOG_AND_CONSOLE] = "syslog+console",
5160 [EXEC_OUTPUT_KMSG] = "kmsg",
5161 [EXEC_OUTPUT_KMSG_AND_CONSOLE] = "kmsg+console",
5162 [EXEC_OUTPUT_JOURNAL] = "journal",
5163 [EXEC_OUTPUT_JOURNAL_AND_CONSOLE] = "journal+console",
5164 [EXEC_OUTPUT_SOCKET] = "socket",
5165 [EXEC_OUTPUT_NAMED_FD] = "fd",
5166 [EXEC_OUTPUT_FILE] = "file",
5167 [EXEC_OUTPUT_FILE_APPEND] = "append",
5168};
5169
5170DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput)const char *exec_output_to_string(ExecOutput i) { if (i < 0
|| i >= (ExecOutput) __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(exec_output_table), typeof
(&*(exec_output_table))), sizeof(exec_output_table)/sizeof
((exec_output_table)[0]), ((void)0)))) return ((void*)0); return
exec_output_table[i]; } ExecOutput exec_output_from_string(const
char *s) { return (ExecOutput) string_table_lookup(exec_output_table
, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(exec_output_table), typeof(&*(exec_output_table))
), sizeof(exec_output_table)/sizeof((exec_output_table)[0]), (
(void)0))), s); }
;
5171
5172static const char* const exec_utmp_mode_table[_EXEC_UTMP_MODE_MAX] = {
5173 [EXEC_UTMP_INIT] = "init",
5174 [EXEC_UTMP_LOGIN] = "login",
5175 [EXEC_UTMP_USER] = "user",
5176};
5177
5178DEFINE_STRING_TABLE_LOOKUP(exec_utmp_mode, ExecUtmpMode)const char *exec_utmp_mode_to_string(ExecUtmpMode i) { if (i <
0 || i >= (ExecUtmpMode) __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(exec_utmp_mode_table),
typeof(&*(exec_utmp_mode_table))), sizeof(exec_utmp_mode_table
)/sizeof((exec_utmp_mode_table)[0]), ((void)0)))) return ((void
*)0); return exec_utmp_mode_table[i]; } ExecUtmpMode exec_utmp_mode_from_string
(const char *s) { return (ExecUtmpMode) string_table_lookup(exec_utmp_mode_table
, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(exec_utmp_mode_table), typeof(&*(exec_utmp_mode_table
))), sizeof(exec_utmp_mode_table)/sizeof((exec_utmp_mode_table
)[0]), ((void)0))), s); }
;
5179
5180static const char* const exec_preserve_mode_table[_EXEC_PRESERVE_MODE_MAX] = {
5181 [EXEC_PRESERVE_NO] = "no",
5182 [EXEC_PRESERVE_YES] = "yes",
5183 [EXEC_PRESERVE_RESTART] = "restart",
5184};
5185
5186DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(exec_preserve_mode, ExecPreserveMode, EXEC_PRESERVE_YES)const char *exec_preserve_mode_to_string(ExecPreserveMode i) {
if (i < 0 || i >= (ExecPreserveMode) __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(exec_preserve_mode_table
), typeof(&*(exec_preserve_mode_table))), sizeof(exec_preserve_mode_table
)/sizeof((exec_preserve_mode_table)[0]), ((void)0)))) return (
(void*)0); return exec_preserve_mode_table[i]; } ExecPreserveMode
exec_preserve_mode_from_string(const char *s) { int b; if (!
s) return -1; b = parse_boolean(s); if (b == 0) return (ExecPreserveMode
) 0; else if (b > 0) return EXEC_PRESERVE_YES; return (ExecPreserveMode
) string_table_lookup(exec_preserve_mode_table, __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(exec_preserve_mode_table), typeof(&*(exec_preserve_mode_table
))), sizeof(exec_preserve_mode_table)/sizeof((exec_preserve_mode_table
)[0]), ((void)0))), s); }
;
5187
5188static const char* const exec_directory_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
5189 [EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectory",
5190 [EXEC_DIRECTORY_STATE] = "StateDirectory",
5191 [EXEC_DIRECTORY_CACHE] = "CacheDirectory",
5192 [EXEC_DIRECTORY_LOGS] = "LogsDirectory",
5193 [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectory",
5194};
5195
5196DEFINE_STRING_TABLE_LOOKUP(exec_directory_type, ExecDirectoryType)const char *exec_directory_type_to_string(ExecDirectoryType i
) { if (i < 0 || i >= (ExecDirectoryType) __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(exec_directory_type_table), typeof(&*(exec_directory_type_table
))), sizeof(exec_directory_type_table)/sizeof((exec_directory_type_table
)[0]), ((void)0)))) return ((void*)0); return exec_directory_type_table
[i]; } ExecDirectoryType exec_directory_type_from_string(const
char *s) { return (ExecDirectoryType) string_table_lookup(exec_directory_type_table
, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(exec_directory_type_table), typeof(&*(exec_directory_type_table
))), sizeof(exec_directory_type_table)/sizeof((exec_directory_type_table
)[0]), ((void)0))), s); }
;
5197
5198static const char* const exec_keyring_mode_table[_EXEC_KEYRING_MODE_MAX] = {
5199 [EXEC_KEYRING_INHERIT] = "inherit",
5200 [EXEC_KEYRING_PRIVATE] = "private",
5201 [EXEC_KEYRING_SHARED] = "shared",
5202};
5203
5204DEFINE_STRING_TABLE_LOOKUP(exec_keyring_mode, ExecKeyringMode)const char *exec_keyring_mode_to_string(ExecKeyringMode i) { if
(i < 0 || i >= (ExecKeyringMode) __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(exec_keyring_mode_table
), typeof(&*(exec_keyring_mode_table))), sizeof(exec_keyring_mode_table
)/sizeof((exec_keyring_mode_table)[0]), ((void)0)))) return (
(void*)0); return exec_keyring_mode_table[i]; } ExecKeyringMode
exec_keyring_mode_from_string(const char *s) { return (ExecKeyringMode
) string_table_lookup(exec_keyring_mode_table, __extension__ (
__builtin_choose_expr( !__builtin_types_compatible_p(typeof(exec_keyring_mode_table
), typeof(&*(exec_keyring_mode_table))), sizeof(exec_keyring_mode_table
)/sizeof((exec_keyring_mode_table)[0]), ((void)0))), s); }
;