summaryrefslogtreecommitdiffstats
path: root/src/shared/dev-setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/dev-setup.c')
-rw-r--r--src/shared/dev-setup.c64
1 files changed, 41 insertions, 23 deletions
diff --git a/src/shared/dev-setup.c b/src/shared/dev-setup.c
index f7ed161..4b4b625 100644
--- a/src/shared/dev-setup.c
+++ b/src/shared/dev-setup.c
@@ -7,6 +7,7 @@
#include "alloc-util.h"
#include "dev-setup.h"
#include "fd-util.h"
+#include "fs-util.h"
#include "label-util.h"
#include "lock-util.h"
#include "log.h"
@@ -21,13 +22,15 @@ int lock_dev_console(void) {
_cleanup_close_ int fd = -EBADF;
int r;
- fd = open_terminal("/dev/console", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+ /* NB: We do not use O_NOFOLLOW here, because some container managers might place a symlink to some
+ * pty in /dev/console, in which case it should be fine to lock the target TTY. */
+ fd = open_terminal("/dev/console", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return fd;
r = lock_generic(fd, LOCK_BSD, LOCK_EX);
if (r < 0)
- return log_error_errno(r, "Failed to lock /dev/console: %m");
+ return r;
return TAKE_FD(fd);
}
@@ -79,15 +82,11 @@ int make_inaccessible_nodes(
uid_t uid,
gid_t gid) {
- static const struct {
- const char *name;
- mode_t mode;
- } table[] = {
- { "inaccessible", S_IFDIR | 0755 },
- { "inaccessible/reg", S_IFREG | 0000 },
- { "inaccessible/dir", S_IFDIR | 0000 },
- { "inaccessible/fifo", S_IFIFO | 0000 },
- { "inaccessible/sock", S_IFSOCK | 0000 },
+ static const mode_t table[] = {
+ S_IFREG,
+ S_IFDIR,
+ S_IFIFO,
+ S_IFSOCK,
/* 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 prohibits creation of
@@ -95,10 +94,13 @@ int make_inaccessible_nodes(
* should implement falling back to use a different node then, for example
* <root>/inaccessible/sock, which is close enough in behaviour and semantics for most uses.
*/
- { "inaccessible/chr", S_IFCHR | 0000 },
- { "inaccessible/blk", S_IFBLK | 0000 },
+ S_IFCHR,
+ S_IFBLK,
+
+ /* NB: S_IFLNK is not listed here, as there is no such thing as an inaccessible symlink */
};
+ _cleanup_close_ int parent_fd = -EBADF, inaccessible_fd = -EBADF;
int r;
if (!parent_dir)
@@ -106,32 +108,48 @@ int make_inaccessible_nodes(
BLOCK_WITH_UMASK(0000);
+ parent_fd = open(parent_dir, O_DIRECTORY|O_CLOEXEC|O_PATH, 0);
+ if (parent_fd < 0)
+ return -errno;
+
+ inaccessible_fd = open_mkdir_at_full(parent_fd, "inaccessible", O_CLOEXEC, XO_LABEL, 0755);
+ if (inaccessible_fd < 0)
+ return inaccessible_fd;
+
/* Set up inaccessible (and empty) file nodes of all types. This are used to as mount sources for over-mounting
* ("masking") file nodes that shall become inaccessible and empty for specific containers or services. We try
* 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 (size_t i = 0; i < ELEMENTSOF(table); i++) {
+ FOREACH_ELEMENT(m, table) {
_cleanup_free_ char *path = NULL;
+ mode_t inode_type = *m;
+ const char *fn;
- path = path_join(parent_dir, table[i].name);
+ fn = inode_type_to_string(inode_type);
+ path = path_join(parent_dir, fn);
if (!path)
return log_oom();
- if (S_ISDIR(table[i].mode))
- r = mkdir_label(path, table[i].mode & 07777);
+ if (S_ISDIR(inode_type))
+ r = mkdirat_label(inaccessible_fd, fn, 0000);
else
- r = mknod_label(path, table[i].mode, makedev(0, 0));
- if (r < 0) {
+ r = mknodat_label(inaccessible_fd, fn, inode_type | 0000, makedev(0, 0));
+ if (r == -EEXIST) {
+ if (fchmodat(inaccessible_fd, fn, 0000, AT_SYMLINK_NOFOLLOW) < 0)
+ log_debug_errno(errno, "Failed to adjust access mode of existing inode '%s', ignoring: %m", path);
+ } else if (r < 0) {
log_debug_errno(r, "Failed to create '%s', ignoring: %m", path);
continue;
}
- if (uid != UID_INVALID || gid != GID_INVALID) {
- if (lchown(path, uid, gid) < 0)
- log_debug_errno(errno, "Failed to chown '%s': %m", path);
- }
+ if (uid_is_valid(uid) || gid_is_valid(gid))
+ if (fchownat(inaccessible_fd, fn, uid, gid, AT_SYMLINK_NOFOLLOW) < 0)
+ log_debug_errno(errno, "Failed to chown '%s', ignoring: %m", path);
}
+ if (fchmod(inaccessible_fd, 0555) < 0)
+ log_debug_errno(errno, "Failed to mark inaccessible directory read-only, ignoring: %m");
+
return 0;
}