core: create inaccessible nodes for users when making runtime dirs
To support ProtectHome=y in a user namespace (which mounts the inaccessible nodes), the nodes need to be accessible by the user. Create these paths and devices in the user runtime directory so they can be used later if needed.
This commit is contained in:
@@ -61,20 +61,20 @@ int make_inaccessible_nodes(const char *root, uid_t uid, gid_t gid) {
|
||||
const char *name;
|
||||
mode_t mode;
|
||||
} table[] = {
|
||||
{ "/run/systemd", S_IFDIR | 0755 },
|
||||
{ "/run/systemd/inaccessible", S_IFDIR | 0000 },
|
||||
{ "/run/systemd/inaccessible/reg", S_IFREG | 0000 },
|
||||
{ "/run/systemd/inaccessible/dir", S_IFDIR | 0000 },
|
||||
{ "/run/systemd/inaccessible/fifo", S_IFIFO | 0000 },
|
||||
{ "/run/systemd/inaccessible/sock", S_IFSOCK | 0000 },
|
||||
{ "", S_IFDIR | 0755 },
|
||||
{ "/inaccessible", S_IFDIR | 0000 },
|
||||
{ "/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 /run/systemd/inaccessible/sock, which is close
|
||||
* fallback to use a different node then, for example <root>/inaccessible/sock, which is close
|
||||
* enough in behaviour and semantics for most uses. */
|
||||
{ "/run/systemd/inaccessible/chr", S_IFCHR | 0000 },
|
||||
{ "/run/systemd/inaccessible/blk", S_IFBLK | 0000 },
|
||||
{ "/inaccessible/chr", S_IFCHR | 0000 },
|
||||
{ "/inaccessible/blk", S_IFBLK | 0000 },
|
||||
};
|
||||
|
||||
_cleanup_umask_ mode_t u;
|
||||
|
||||
+46
-12
@@ -339,38 +339,72 @@ int repeat_unmount(const char *path, int flags) {
|
||||
}
|
||||
}
|
||||
|
||||
const char* mode_to_inaccessible_node(mode_t mode) {
|
||||
int mode_to_inaccessible_node(const char *runtime_dir, mode_t mode, char **dest) {
|
||||
/* This function maps a node type to a corresponding inaccessible file node. These nodes are created during
|
||||
* early boot by PID 1. In some cases we lacked the privs to create the character and block devices (maybe
|
||||
* because we run in an userns environment, or miss CAP_SYS_MKNOD, or run with a devices policy that excludes
|
||||
* device nodes with major and minor of 0), but that's fine, in that case we use an AF_UNIX file node instead,
|
||||
* which is not the same, but close enough for most uses. And most importantly, the kernel allows bind mounts
|
||||
* from socket nodes to any non-directory file nodes, and that's the most important thing that matters. */
|
||||
_cleanup_free_ char *d = NULL;
|
||||
const char *node = NULL;
|
||||
char *tmp;
|
||||
|
||||
assert(dest);
|
||||
|
||||
switch(mode & S_IFMT) {
|
||||
case S_IFREG:
|
||||
return "/run/systemd/inaccessible/reg";
|
||||
node = "/inaccessible/reg";
|
||||
break;
|
||||
|
||||
case S_IFDIR:
|
||||
return "/run/systemd/inaccessible/dir";
|
||||
node = "/inaccessible/dir";
|
||||
break;
|
||||
|
||||
case S_IFCHR:
|
||||
if (access("/run/systemd/inaccessible/chr", F_OK) == 0)
|
||||
return "/run/systemd/inaccessible/chr";
|
||||
return "/run/systemd/inaccessible/sock";
|
||||
d = path_join(runtime_dir, "/inaccessible/chr");
|
||||
if (!d)
|
||||
return log_oom();
|
||||
|
||||
if (access(d, F_OK) == 0) {
|
||||
*dest = TAKE_PTR(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
node = "/inaccessible/sock";
|
||||
break;
|
||||
|
||||
case S_IFBLK:
|
||||
if (access("/run/systemd/inaccessible/blk", F_OK) == 0)
|
||||
return "/run/systemd/inaccessible/blk";
|
||||
return "/run/systemd/inaccessible/sock";
|
||||
d = path_join(runtime_dir, "/inaccessible/blk");
|
||||
if (!d)
|
||||
return log_oom();
|
||||
|
||||
if (access(d, F_OK) == 0) {
|
||||
*dest = TAKE_PTR(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
node = "/inaccessible/sock";
|
||||
break;
|
||||
|
||||
case S_IFIFO:
|
||||
return "/run/systemd/inaccessible/fifo";
|
||||
node = "/inaccessible/fifo";
|
||||
break;
|
||||
|
||||
case S_IFSOCK:
|
||||
return "/run/systemd/inaccessible/sock";
|
||||
node = "/inaccessible/sock";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
if (!node)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = path_join(runtime_dir, node);
|
||||
if (!tmp)
|
||||
return log_oom();
|
||||
|
||||
*dest = tmp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FLAG(name) (flags & name ? STRINGIFY(name) "|" : "")
|
||||
|
||||
@@ -31,4 +31,4 @@ int mount_option_mangle(
|
||||
unsigned long *ret_mount_flags,
|
||||
char **ret_remaining_options);
|
||||
|
||||
const char* mode_to_inaccessible_node(mode_t mode);
|
||||
int mode_to_inaccessible_node(const char *runtime_dir, mode_t mode, char **dest);
|
||||
|
||||
Reference in New Issue
Block a user