Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <errno.h>
4 : #include <stdlib.h>
5 : #include <unistd.h>
6 :
7 : #include "alloc-util.h"
8 : #include "dev-setup.h"
9 : #include "label.h"
10 : #include "log.h"
11 : #include "nulstr-util.h"
12 : #include "path-util.h"
13 : #include "umask-util.h"
14 : #include "user-util.h"
15 :
16 0 : int dev_setup(const char *prefix, uid_t uid, gid_t gid) {
17 : static const char symlinks[] =
18 : "-/proc/kcore\0" "/dev/core\0"
19 : "/proc/self/fd\0" "/dev/fd\0"
20 : "/proc/self/fd/0\0" "/dev/stdin\0"
21 : "/proc/self/fd/1\0" "/dev/stdout\0"
22 : "/proc/self/fd/2\0" "/dev/stderr\0";
23 :
24 : const char *j, *k;
25 : int r;
26 :
27 0 : NULSTR_FOREACH_PAIR(j, k, symlinks) {
28 0 : _cleanup_free_ char *link_name = NULL;
29 : const char *n;
30 :
31 0 : if (j[0] == '-') {
32 0 : j++;
33 :
34 0 : if (access(j, F_OK) < 0)
35 0 : continue;
36 : }
37 :
38 0 : if (prefix) {
39 0 : link_name = path_join(prefix, k);
40 0 : if (!link_name)
41 0 : return -ENOMEM;
42 :
43 0 : n = link_name;
44 : } else
45 0 : n = k;
46 :
47 0 : r = symlink_label(j, n);
48 0 : if (r < 0)
49 0 : log_debug_errno(r, "Failed to symlink %s to %s: %m", j, n);
50 :
51 0 : if (uid != UID_INVALID || gid != GID_INVALID)
52 0 : if (lchown(n, uid, gid) < 0)
53 0 : log_debug_errno(errno, "Failed to chown %s: %m", n);
54 : }
55 :
56 0 : return 0;
57 : }
58 :
59 0 : int make_inaccessible_nodes(const char *root, uid_t uid, gid_t gid) {
60 : static const struct {
61 : const char *name;
62 : mode_t mode;
63 : } table[] = {
64 : { "/run/systemd", S_IFDIR | 0755 },
65 : { "/run/systemd/inaccessible", S_IFDIR | 0000 },
66 : { "/run/systemd/inaccessible/reg", S_IFREG | 0000 },
67 : { "/run/systemd/inaccessible/dir", S_IFDIR | 0000 },
68 : { "/run/systemd/inaccessible/fifo", S_IFIFO | 0000 },
69 : { "/run/systemd/inaccessible/sock", S_IFSOCK | 0000 },
70 :
71 : /* The following two are likely to fail if we lack the privs for it (for example in an userns
72 : * environment, if CAP_SYS_MKNOD is missing, or if a device node policy prohibit major/minor of 0
73 : * device nodes to be created). But that's entirely fine. Consumers of these files should carry
74 : * fallback to use a different node then, for example /run/systemd/inaccessible/sock, which is close
75 : * enough in behaviour and semantics for most uses. */
76 : { "/run/systemd/inaccessible/chr", S_IFCHR | 0000 },
77 : { "/run/systemd/inaccessible/blk", S_IFBLK | 0000 },
78 : };
79 :
80 0 : _cleanup_umask_ mode_t u;
81 : size_t i;
82 : int r;
83 :
84 0 : u = umask(0000);
85 :
86 : /* Set up inaccessible (and empty) file nodes of all types. This are used to as mount sources for over-mounting
87 : * ("masking") file nodes that shall become inaccessible and empty for specific containers or services. We try
88 : * to lock down these nodes as much as we can, but otherwise try to match them as closely as possible with the
89 : * underlying file, i.e. in the best case we offer the same node type as the underlying node. */
90 :
91 0 : for (i = 0; i < ELEMENTSOF(table); i++) {
92 0 : _cleanup_free_ char *path = NULL;
93 :
94 0 : path = path_join(root, table[i].name);
95 0 : if (!path)
96 0 : return log_oom();
97 :
98 0 : if (S_ISDIR(table[i].mode))
99 0 : r = mkdir(path, table[i].mode & 07777);
100 : else
101 0 : r = mknod(path, table[i].mode, makedev(0, 0));
102 0 : if (r < 0) {
103 0 : if (errno != EEXIST)
104 0 : log_debug_errno(errno, "Failed to create '%s', ignoring: %m", path);
105 0 : continue;
106 : }
107 :
108 0 : if (uid != UID_INVALID || gid != GID_INVALID) {
109 0 : if (lchown(path, uid, gid) < 0)
110 0 : log_debug_errno(errno, "Failed to chown '%s': %m", path);
111 : }
112 : }
113 :
114 0 : return 0;
115 : }
|