]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/util.c
selinux: use raw variants of security_compute_create and setfscreatecon
[thirdparty/systemd.git] / src / basic / util.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <alloca.h>
21 #include <dirent.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <sched.h>
25 #include <signal.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/mman.h>
31 #include <sys/prctl.h>
32 #include <sys/statfs.h>
33 #include <sys/sysmacros.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36
37 #include "alloc-util.h"
38 #include "build.h"
39 #include "def.h"
40 #include "dirent-util.h"
41 #include "fd-util.h"
42 #include "fileio.h"
43 #include "formats-util.h"
44 #include "hashmap.h"
45 #include "hostname-util.h"
46 #include "log.h"
47 #include "macro.h"
48 #include "missing.h"
49 #include "parse-util.h"
50 #include "path-util.h"
51 #include "process-util.h"
52 #include "set.h"
53 #include "signal-util.h"
54 #include "stat-util.h"
55 #include "string-util.h"
56 #include "strv.h"
57 #include "time-util.h"
58 #include "user-util.h"
59 #include "util.h"
60
61 /* Put this test here for a lack of better place */
62 assert_cc(EAGAIN == EWOULDBLOCK);
63
64 int saved_argc = 0;
65 char **saved_argv = NULL;
66
67 size_t page_size(void) {
68 static thread_local size_t pgsz = 0;
69 long r;
70
71 if (_likely_(pgsz > 0))
72 return pgsz;
73
74 r = sysconf(_SC_PAGESIZE);
75 assert(r > 0);
76
77 pgsz = (size_t) r;
78 return pgsz;
79 }
80
81 static int do_execute(char **directories, usec_t timeout, char *argv[]) {
82 _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
83 _cleanup_set_free_free_ Set *seen = NULL;
84 char **directory;
85
86 /* We fork this all off from a child process so that we can
87 * somewhat cleanly make use of SIGALRM to set a time limit */
88
89 (void) reset_all_signal_handlers();
90 (void) reset_signal_mask();
91
92 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
93
94 pids = hashmap_new(NULL);
95 if (!pids)
96 return log_oom();
97
98 seen = set_new(&string_hash_ops);
99 if (!seen)
100 return log_oom();
101
102 STRV_FOREACH(directory, directories) {
103 _cleanup_closedir_ DIR *d;
104 struct dirent *de;
105
106 d = opendir(*directory);
107 if (!d) {
108 if (errno == ENOENT)
109 continue;
110
111 return log_error_errno(errno, "Failed to open directory %s: %m", *directory);
112 }
113
114 FOREACH_DIRENT(de, d, break) {
115 _cleanup_free_ char *path = NULL;
116 pid_t pid;
117 int r;
118
119 if (!dirent_is_file(de))
120 continue;
121
122 if (set_contains(seen, de->d_name)) {
123 log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory, de->d_name);
124 continue;
125 }
126
127 r = set_put_strdup(seen, de->d_name);
128 if (r < 0)
129 return log_oom();
130
131 path = strjoin(*directory, "/", de->d_name, NULL);
132 if (!path)
133 return log_oom();
134
135 if (null_or_empty_path(path)) {
136 log_debug("%s is empty (a mask).", path);
137 continue;
138 }
139
140 pid = fork();
141 if (pid < 0) {
142 log_error_errno(errno, "Failed to fork: %m");
143 continue;
144 } else if (pid == 0) {
145 char *_argv[2];
146
147 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
148
149 if (!argv) {
150 _argv[0] = path;
151 _argv[1] = NULL;
152 argv = _argv;
153 } else
154 argv[0] = path;
155
156 execv(path, argv);
157 return log_error_errno(errno, "Failed to execute %s: %m", path);
158 }
159
160 log_debug("Spawned %s as " PID_FMT ".", path, pid);
161
162 r = hashmap_put(pids, PID_TO_PTR(pid), path);
163 if (r < 0)
164 return log_oom();
165 path = NULL;
166 }
167 }
168
169 /* Abort execution of this process after the timout. We simply
170 * rely on SIGALRM as default action terminating the process,
171 * and turn on alarm(). */
172
173 if (timeout != USEC_INFINITY)
174 alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
175
176 while (!hashmap_isempty(pids)) {
177 _cleanup_free_ char *path = NULL;
178 pid_t pid;
179
180 pid = PTR_TO_PID(hashmap_first_key(pids));
181 assert(pid > 0);
182
183 path = hashmap_remove(pids, PID_TO_PTR(pid));
184 assert(path);
185
186 wait_for_terminate_and_warn(path, pid, true);
187 }
188
189 return 0;
190 }
191
192 void execute_directories(const char* const* directories, usec_t timeout, char *argv[]) {
193 pid_t executor_pid;
194 int r;
195 char *name;
196 char **dirs = (char**) directories;
197
198 assert(!strv_isempty(dirs));
199
200 name = basename(dirs[0]);
201 assert(!isempty(name));
202
203 /* Executes all binaries in the directories in parallel and waits
204 * for them to finish. Optionally a timeout is applied. If a file
205 * with the same name exists in more than one directory, the
206 * earliest one wins. */
207
208 executor_pid = fork();
209 if (executor_pid < 0) {
210 log_error_errno(errno, "Failed to fork: %m");
211 return;
212
213 } else if (executor_pid == 0) {
214 r = do_execute(dirs, timeout, argv);
215 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
216 }
217
218 wait_for_terminate_and_warn(name, executor_pid, true);
219 }
220
221 bool plymouth_running(void) {
222 return access("/run/plymouth/pid", F_OK) >= 0;
223 }
224
225 bool display_is_local(const char *display) {
226 assert(display);
227
228 return
229 display[0] == ':' &&
230 display[1] >= '0' &&
231 display[1] <= '9';
232 }
233
234 int socket_from_display(const char *display, char **path) {
235 size_t k;
236 char *f, *c;
237
238 assert(display);
239 assert(path);
240
241 if (!display_is_local(display))
242 return -EINVAL;
243
244 k = strspn(display+1, "0123456789");
245
246 f = new(char, strlen("/tmp/.X11-unix/X") + k + 1);
247 if (!f)
248 return -ENOMEM;
249
250 c = stpcpy(f, "/tmp/.X11-unix/X");
251 memcpy(c, display+1, k);
252 c[k] = 0;
253
254 *path = f;
255
256 return 0;
257 }
258
259 int block_get_whole_disk(dev_t d, dev_t *ret) {
260 char *p, *s;
261 int r;
262 unsigned n, m;
263
264 assert(ret);
265
266 /* If it has a queue this is good enough for us */
267 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
268 return -ENOMEM;
269
270 r = access(p, F_OK);
271 free(p);
272
273 if (r >= 0) {
274 *ret = d;
275 return 0;
276 }
277
278 /* If it is a partition find the originating device */
279 if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
280 return -ENOMEM;
281
282 r = access(p, F_OK);
283 free(p);
284
285 if (r < 0)
286 return -ENOENT;
287
288 /* Get parent dev_t */
289 if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
290 return -ENOMEM;
291
292 r = read_one_line_file(p, &s);
293 free(p);
294
295 if (r < 0)
296 return r;
297
298 r = sscanf(s, "%u:%u", &m, &n);
299 free(s);
300
301 if (r != 2)
302 return -EINVAL;
303
304 /* Only return this if it is really good enough for us. */
305 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
306 return -ENOMEM;
307
308 r = access(p, F_OK);
309 free(p);
310
311 if (r >= 0) {
312 *ret = makedev(m, n);
313 return 0;
314 }
315
316 return -ENOENT;
317 }
318
319 bool kexec_loaded(void) {
320 bool loaded = false;
321 char *s;
322
323 if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
324 if (s[0] == '1')
325 loaded = true;
326 free(s);
327 }
328 return loaded;
329 }
330
331 int prot_from_flags(int flags) {
332
333 switch (flags & O_ACCMODE) {
334
335 case O_RDONLY:
336 return PROT_READ;
337
338 case O_WRONLY:
339 return PROT_WRITE;
340
341 case O_RDWR:
342 return PROT_READ|PROT_WRITE;
343
344 default:
345 return -EINVAL;
346 }
347 }
348
349 int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
350 bool stdout_is_tty, stderr_is_tty;
351 pid_t parent_pid, agent_pid;
352 sigset_t ss, saved_ss;
353 unsigned n, i;
354 va_list ap;
355 char **l;
356
357 assert(pid);
358 assert(path);
359
360 /* Spawns a temporary TTY agent, making sure it goes away when
361 * we go away */
362
363 parent_pid = getpid();
364
365 /* First we temporarily block all signals, so that the new
366 * child has them blocked initially. This way, we can be sure
367 * that SIGTERMs are not lost we might send to the agent. */
368 assert_se(sigfillset(&ss) >= 0);
369 assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0);
370
371 agent_pid = fork();
372 if (agent_pid < 0) {
373 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
374 return -errno;
375 }
376
377 if (agent_pid != 0) {
378 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
379 *pid = agent_pid;
380 return 0;
381 }
382
383 /* In the child:
384 *
385 * Make sure the agent goes away when the parent dies */
386 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
387 _exit(EXIT_FAILURE);
388
389 /* Make sure we actually can kill the agent, if we need to, in
390 * case somebody invoked us from a shell script that trapped
391 * SIGTERM or so... */
392 (void) reset_all_signal_handlers();
393 (void) reset_signal_mask();
394
395 /* Check whether our parent died before we were able
396 * to set the death signal and unblock the signals */
397 if (getppid() != parent_pid)
398 _exit(EXIT_SUCCESS);
399
400 /* Don't leak fds to the agent */
401 close_all_fds(except, n_except);
402
403 stdout_is_tty = isatty(STDOUT_FILENO);
404 stderr_is_tty = isatty(STDERR_FILENO);
405
406 if (!stdout_is_tty || !stderr_is_tty) {
407 int fd;
408
409 /* Detach from stdout/stderr. and reopen
410 * /dev/tty for them. This is important to
411 * ensure that when systemctl is started via
412 * popen() or a similar call that expects to
413 * read EOF we actually do generate EOF and
414 * not delay this indefinitely by because we
415 * keep an unused copy of stdin around. */
416 fd = open("/dev/tty", O_WRONLY);
417 if (fd < 0) {
418 log_error_errno(errno, "Failed to open /dev/tty: %m");
419 _exit(EXIT_FAILURE);
420 }
421
422 if (!stdout_is_tty)
423 dup2(fd, STDOUT_FILENO);
424
425 if (!stderr_is_tty)
426 dup2(fd, STDERR_FILENO);
427
428 if (fd > 2)
429 close(fd);
430 }
431
432 /* Count arguments */
433 va_start(ap, path);
434 for (n = 0; va_arg(ap, char*); n++)
435 ;
436 va_end(ap);
437
438 /* Allocate strv */
439 l = alloca(sizeof(char *) * (n + 1));
440
441 /* Fill in arguments */
442 va_start(ap, path);
443 for (i = 0; i <= n; i++)
444 l[i] = va_arg(ap, char*);
445 va_end(ap);
446
447 execv(path, l);
448 _exit(EXIT_FAILURE);
449 }
450
451 bool in_initrd(void) {
452 static int saved = -1;
453 struct statfs s;
454
455 if (saved >= 0)
456 return saved;
457
458 /* We make two checks here:
459 *
460 * 1. the flag file /etc/initrd-release must exist
461 * 2. the root file system must be a memory file system
462 *
463 * The second check is extra paranoia, since misdetecting an
464 * initrd can have bad bad consequences due the initrd
465 * emptying when transititioning to the main systemd.
466 */
467
468 saved = access("/etc/initrd-release", F_OK) >= 0 &&
469 statfs("/", &s) >= 0 &&
470 is_temporary_fs(&s);
471
472 return saved;
473 }
474
475 /* hey glibc, APIs with callbacks without a user pointer are so useless */
476 void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
477 int (*compar) (const void *, const void *, void *), void *arg) {
478 size_t l, u, idx;
479 const void *p;
480 int comparison;
481
482 l = 0;
483 u = nmemb;
484 while (l < u) {
485 idx = (l + u) / 2;
486 p = (void *)(((const char *) base) + (idx * size));
487 comparison = compar(key, p, arg);
488 if (comparison < 0)
489 u = idx;
490 else if (comparison > 0)
491 l = idx + 1;
492 else
493 return (void *)p;
494 }
495 return NULL;
496 }
497
498 int on_ac_power(void) {
499 bool found_offline = false, found_online = false;
500 _cleanup_closedir_ DIR *d = NULL;
501
502 d = opendir("/sys/class/power_supply");
503 if (!d)
504 return errno == ENOENT ? true : -errno;
505
506 for (;;) {
507 struct dirent *de;
508 _cleanup_close_ int fd = -1, device = -1;
509 char contents[6];
510 ssize_t n;
511
512 errno = 0;
513 de = readdir(d);
514 if (!de && errno > 0)
515 return -errno;
516
517 if (!de)
518 break;
519
520 if (hidden_file(de->d_name))
521 continue;
522
523 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
524 if (device < 0) {
525 if (errno == ENOENT || errno == ENOTDIR)
526 continue;
527
528 return -errno;
529 }
530
531 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
532 if (fd < 0) {
533 if (errno == ENOENT)
534 continue;
535
536 return -errno;
537 }
538
539 n = read(fd, contents, sizeof(contents));
540 if (n < 0)
541 return -errno;
542
543 if (n != 6 || memcmp(contents, "Mains\n", 6))
544 continue;
545
546 safe_close(fd);
547 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
548 if (fd < 0) {
549 if (errno == ENOENT)
550 continue;
551
552 return -errno;
553 }
554
555 n = read(fd, contents, sizeof(contents));
556 if (n < 0)
557 return -errno;
558
559 if (n != 2 || contents[1] != '\n')
560 return -EIO;
561
562 if (contents[0] == '1') {
563 found_online = true;
564 break;
565 } else if (contents[0] == '0')
566 found_offline = true;
567 else
568 return -EIO;
569 }
570
571 return found_online || !found_offline;
572 }
573
574 bool id128_is_valid(const char *s) {
575 size_t i, l;
576
577 l = strlen(s);
578 if (l == 32) {
579
580 /* Simple formatted 128bit hex string */
581
582 for (i = 0; i < l; i++) {
583 char c = s[i];
584
585 if (!(c >= '0' && c <= '9') &&
586 !(c >= 'a' && c <= 'z') &&
587 !(c >= 'A' && c <= 'Z'))
588 return false;
589 }
590
591 } else if (l == 36) {
592
593 /* Formatted UUID */
594
595 for (i = 0; i < l; i++) {
596 char c = s[i];
597
598 if ((i == 8 || i == 13 || i == 18 || i == 23)) {
599 if (c != '-')
600 return false;
601 } else {
602 if (!(c >= '0' && c <= '9') &&
603 !(c >= 'a' && c <= 'z') &&
604 !(c >= 'A' && c <= 'Z'))
605 return false;
606 }
607 }
608
609 } else
610 return false;
611
612 return true;
613 }
614
615 int container_get_leader(const char *machine, pid_t *pid) {
616 _cleanup_free_ char *s = NULL, *class = NULL;
617 const char *p;
618 pid_t leader;
619 int r;
620
621 assert(machine);
622 assert(pid);
623
624 if (!machine_name_is_valid(machine))
625 return -EINVAL;
626
627 p = strjoina("/run/systemd/machines/", machine);
628 r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
629 if (r == -ENOENT)
630 return -EHOSTDOWN;
631 if (r < 0)
632 return r;
633 if (!s)
634 return -EIO;
635
636 if (!streq_ptr(class, "container"))
637 return -EIO;
638
639 r = parse_pid(s, &leader);
640 if (r < 0)
641 return r;
642 if (leader <= 1)
643 return -EIO;
644
645 *pid = leader;
646 return 0;
647 }
648
649 int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
650 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
651 int rfd = -1;
652
653 assert(pid >= 0);
654
655 if (mntns_fd) {
656 const char *mntns;
657
658 mntns = procfs_file_alloca(pid, "ns/mnt");
659 mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
660 if (mntnsfd < 0)
661 return -errno;
662 }
663
664 if (pidns_fd) {
665 const char *pidns;
666
667 pidns = procfs_file_alloca(pid, "ns/pid");
668 pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
669 if (pidnsfd < 0)
670 return -errno;
671 }
672
673 if (netns_fd) {
674 const char *netns;
675
676 netns = procfs_file_alloca(pid, "ns/net");
677 netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
678 if (netnsfd < 0)
679 return -errno;
680 }
681
682 if (userns_fd) {
683 const char *userns;
684
685 userns = procfs_file_alloca(pid, "ns/user");
686 usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
687 if (usernsfd < 0 && errno != ENOENT)
688 return -errno;
689 }
690
691 if (root_fd) {
692 const char *root;
693
694 root = procfs_file_alloca(pid, "root");
695 rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
696 if (rfd < 0)
697 return -errno;
698 }
699
700 if (pidns_fd)
701 *pidns_fd = pidnsfd;
702
703 if (mntns_fd)
704 *mntns_fd = mntnsfd;
705
706 if (netns_fd)
707 *netns_fd = netnsfd;
708
709 if (userns_fd)
710 *userns_fd = usernsfd;
711
712 if (root_fd)
713 *root_fd = rfd;
714
715 pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
716
717 return 0;
718 }
719
720 int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
721 if (userns_fd >= 0) {
722 /* Can't setns to your own userns, since then you could
723 * escalate from non-root to root in your own namespace, so
724 * check if namespaces equal before attempting to enter. */
725 _cleanup_free_ char *userns_fd_path = NULL;
726 int r;
727 if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
728 return -ENOMEM;
729
730 r = files_same(userns_fd_path, "/proc/self/ns/user");
731 if (r < 0)
732 return r;
733 if (r)
734 userns_fd = -1;
735 }
736
737 if (pidns_fd >= 0)
738 if (setns(pidns_fd, CLONE_NEWPID) < 0)
739 return -errno;
740
741 if (mntns_fd >= 0)
742 if (setns(mntns_fd, CLONE_NEWNS) < 0)
743 return -errno;
744
745 if (netns_fd >= 0)
746 if (setns(netns_fd, CLONE_NEWNET) < 0)
747 return -errno;
748
749 if (userns_fd >= 0)
750 if (setns(userns_fd, CLONE_NEWUSER) < 0)
751 return -errno;
752
753 if (root_fd >= 0) {
754 if (fchdir(root_fd) < 0)
755 return -errno;
756
757 if (chroot(".") < 0)
758 return -errno;
759 }
760
761 return reset_uid_gid();
762 }
763
764 uint64_t physical_memory(void) {
765 long mem;
766
767 /* We return this as uint64_t in case we are running as 32bit
768 * process on a 64bit kernel with huge amounts of memory */
769
770 mem = sysconf(_SC_PHYS_PAGES);
771 assert(mem > 0);
772
773 return (uint64_t) mem * (uint64_t) page_size();
774 }
775
776 int update_reboot_param_file(const char *param) {
777 int r = 0;
778
779 if (param) {
780 r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
781 if (r < 0)
782 return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m");
783 } else
784 (void) unlink(REBOOT_PARAM_FILE);
785
786 return 0;
787 }
788
789 int version(void) {
790 puts(PACKAGE_STRING "\n"
791 SYSTEMD_FEATURES);
792 return 0;
793 }