From b2a331f2e0bfde290214c02e3c96f1599c715bfc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 31 Mar 2022 13:27:21 +0200 Subject: [PATCH 1/2] virt: simplify userns_has_mapping() by using fscanf() instead of scanf() And while we are at it, also fix propagation of an uninitialized errno error. --- src/basic/virt.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/basic/virt.c b/src/basic/virt.c index 284ad95277..3c210f6ab3 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -12,6 +12,7 @@ #include "cgroup-util.h" #include "dirent-util.h" #include "env-util.h" +#include "errno-util.h" #include "fd-util.h" #include "fileio.h" #include "macro.h" @@ -791,10 +792,7 @@ int detect_virtualization(void) { static int userns_has_mapping(const char *name) { _cleanup_fclose_ FILE *f = NULL; - _cleanup_free_ char *buf = NULL; - size_t n_allocated = 0; - ssize_t n; - uint32_t a, b, c; + uid_t a, b, c; int r; f = fopen(name, "re"); @@ -803,19 +801,17 @@ static int userns_has_mapping(const char *name) { return errno == ENOENT ? false : -errno; } - n = getline(&buf, &n_allocated, f); - if (n < 0) { - if (feof(f)) { - log_debug("%s is empty, we're in an uninitialized user namespace", name); - return true; - } + errno = 0; + r = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT "\n", &a, &b, &c); + if (r == EOF) { + if (ferror(f)) + return log_debug_errno(errno_or_else(EIO), "Failed to read %s: %m", name); - return log_debug_errno(errno, "Failed to read %s: %m", name); + log_debug("%s is empty, we're in an uninitialized user namespace", name); + return true; } - - r = sscanf(buf, "%"PRIu32" %"PRIu32" %"PRIu32, &a, &b, &c); - if (r < 3) - return log_debug_errno(errno, "Failed to parse %s: %m", name); + if (r != 3) + return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to parse %s: %m", name); if (a == 0 && b == 0 && c == UINT32_MAX) { /* The kernel calls mappings_overlap() and does not allow overlaps */ From 16fa47463ca549e4ab776026d0a4f7e37d4fd7f7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 31 Mar 2022 13:28:18 +0200 Subject: [PATCH 2/2] virt: use read_virtual_file() for reading /proc/self/setgroups --- src/basic/virt.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/basic/virt.c b/src/basic/virt.c index 3c210f6ab3..8cea4367a0 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -836,19 +836,18 @@ int running_in_userns(void) { if (r != 0) return r; - /* "setgroups" file was added in kernel v3.18-rc6-15-g9cc46516dd. It is also - * possible to compile a kernel without CONFIG_USER_NS, in which case "setgroups" - * also does not exist. We cannot distinguish those two cases, so assume that - * we're running on a stripped-down recent kernel, rather than on an old one, - * and if the file is not found, return false. - */ - r = read_one_line_file("/proc/self/setgroups", &line); + /* "setgroups" file was added in kernel v3.18-rc6-15-g9cc46516dd. It is also possible to compile a + * kernel without CONFIG_USER_NS, in which case "setgroups" also does not exist. We cannot + * distinguish those two cases, so assume that we're running on a stripped-down recent kernel, rather + * than on an old one, and if the file is not found, return false. */ + r = read_virtual_file("/proc/self/setgroups", SIZE_MAX, &line, NULL); if (r < 0) { log_debug_errno(r, "/proc/self/setgroups: %m"); return r == -ENOENT ? false : r; } - truncate_nl(line); + strstrip(line); /* remove trailing newline */ + r = streq(line, "deny"); /* See user_namespaces(7) for a description of this "setgroups" contents. */ log_debug("/proc/self/setgroups contains \"%s\", %s user namespace", line, r ? "in" : "not in");