(void) mkdir_label("/run/systemd/system", 0755);
/* Also create /run/systemd/inaccessible nodes, so that we always have something to mount
- * inaccessible nodes from. */
- (void) make_inaccessible_nodes(NULL, UID_INVALID, GID_INVALID);
+ * inaccessible nodes from. If we run in a container the host might have created these for us already
+ * in /run/host/inaccessible/. Use those if we can, since tht way we likely get access to block/char
+ * device nodes that are inaccessible, and if userns is used to nodes that are on mounts owned by a
+ * userns outside the container and thus nicely read-only and not remountable. */
+ if (access("/run/host/inaccessible/", F_OK) < 0) {
+ if (errno != ENOENT)
+ log_debug_errno(errno, "Failed to check if /run/host/inaccessible exists, ignoring: %m");
+
+ (void) make_inaccessible_nodes("/run/systemd", UID_INVALID, GID_INVALID);
+ } else
+ (void) symlink("../host/inaccessible", "/run/systemd/inaccessible");
return 0;
}
}
int make_inaccessible_nodes(
- const char *runtime_dir,
+ const char *parent_dir,
uid_t uid,
gid_t gid) {
const char *name;
mode_t mode;
} table[] = {
- { "/systemd", S_IFDIR | 0755 },
- { "/systemd/inaccessible", S_IFDIR | 0000 },
- { "/systemd/inaccessible/reg", S_IFREG | 0000 },
- { "/systemd/inaccessible/dir", S_IFDIR | 0000 },
- { "/systemd/inaccessible/fifo", S_IFIFO | 0000 },
- { "/systemd/inaccessible/sock", S_IFSOCK | 0000 },
+ { "inaccessible", S_IFDIR | 0755 },
+ { "inaccessible/reg", S_IFREG | 0000 },
+ { "inaccessible/dir", S_IFDIR | 0000 },
+ { "inaccessible/fifo", S_IFIFO | 0000 },
+ { "inaccessible/sock", S_IFSOCK | 0000 },
/* The following two are likely to fail if we lack the privs for it (for example in an userns
* environment, if CAP_SYS_MKNOD is missing, or if a device node policy prohibit major/minor of 0
* device nodes to be created). But that's entirely fine. Consumers of these files should carry
* fallback to use a different node then, for example <root>/inaccessible/sock, which is close
* enough in behaviour and semantics for most uses. */
- { "/systemd/inaccessible/chr", S_IFCHR | 0000 },
- { "/systemd/inaccessible/blk", S_IFBLK | 0000 },
+ { "inaccessible/chr", S_IFCHR | 0000 },
+ { "inaccessible/blk", S_IFBLK | 0000 },
};
_cleanup_umask_ mode_t u;
- size_t i;
int r;
- if (!runtime_dir)
- runtime_dir = "/run";
+ if (!parent_dir)
+ parent_dir = "/run/systemd";
u = umask(0000);
* to lock down these nodes as much as we can, but otherwise try to match them as closely as possible with the
* underlying file, i.e. in the best case we offer the same node type as the underlying node. */
- for (i = 0; i < ELEMENTSOF(table); i++) {
+ for (size_t i = 0; i < ELEMENTSOF(table); i++) {
_cleanup_free_ char *path = NULL;
- path = path_join(runtime_dir, table[i].name);
+ path = path_join(parent_dir, table[i].name);
if (!path)
return log_oom();
else
r = mknod_label(path, table[i].mode, makedev(0, 0));
if (r < 0) {
- if (r != -EEXIST)
- log_debug_errno(r, "Failed to create '%s', ignoring: %m", path);
+ log_debug_errno(r, "Failed to create '%s', ignoring: %m", path);
continue;
}