diff options
author | Lennart Poettering <lennart@poettering.net> | 2017-02-17 13:51:58 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-17 13:51:58 +0100 |
commit | e4363cd8ae9e0db02aeb4fa45cc785925e78c80e (patch) | |
tree | c1072ba3130a025250dc06df8b2ca2e726838a57 /src/machine/machine.c | |
parent | ea2aa0343f91f3cd2842129e94dbf05525732e7f (diff) | |
parent | aa10469e17bd145c5d5c8c9b93438a0ee74d1ecf (diff) |
Merge pull request #5333 from poettering/machined-copy-files-userns
machined userns fixes
Diffstat (limited to 'src/machine/machine.c')
-rw-r--r-- | src/machine/machine.c | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/src/machine/machine.c b/src/machine/machine.c index 067a7e2866..d3433d9b96 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -38,6 +38,7 @@ #include "parse-util.h" #include "process-util.h" #include "special.h" +#include "stdio-util.h" #include "string-table.h" #include "terminal-util.h" #include "unit-name.h" @@ -604,6 +605,96 @@ void machine_release_unit(Machine *m) { m->unit = mfree(m->unit); } +int machine_get_uid_shift(Machine *m, uid_t *ret) { + char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1]; + uid_t uid_base, uid_shift, uid_range; + gid_t gid_base, gid_shift, gid_range; + _cleanup_fclose_ FILE *f = NULL; + int k; + + assert(m); + assert(ret); + + /* Return the base UID/GID of the specified machine. Note that this only works for containers with simple + * mappings. In most cases setups should be simple like this, and administrators should only care about the + * basic offset a container has relative to the host. This is what this function exposes. + * + * If we encounter any more complex mappings we politely refuse this with ENXIO. */ + + if (m->class == MACHINE_HOST) { + *ret = 0; + return 0; + } + + if (m->class != MACHINE_CONTAINER) + return -EOPNOTSUPP; + + xsprintf(p, "/proc/" PID_FMT "/uid_map", m->leader); + f = fopen(p, "re"); + if (!f) { + if (errno == ENOENT) { + /* If the file doesn't exist, user namespacing is off in the kernel, return a zero mapping hence. */ + *ret = 0; + return 0; + } + + return -errno; + } + + /* Read the first line. There's at least one. */ + errno = 0; + k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT "\n", &uid_base, &uid_shift, &uid_range); + if (k != 3) { + if (ferror(f)) + return -errno; + + return -EBADMSG; + } + + /* Not a mapping starting at 0? Then it's a complex mapping we can't expose here. */ + if (uid_base != 0) + return -ENXIO; + /* Insist that at least the nobody user is mapped, everything else is weird, and hence complex, and we don't support it */ + if (uid_range < (uid_t) 65534U) + return -ENXIO; + + /* If there's more than one line, then we don't support this mapping. */ + if (fgetc(f) != EOF) + return -ENXIO; + + fclose(f); + + xsprintf(p, "/proc/" PID_FMT "/gid_map", m->leader); + f = fopen(p, "re"); + if (!f) + return -errno; + + /* Read the first line. There's at least one. */ + errno = 0; + k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT "\n", &gid_base, &gid_shift, &gid_range); + if (k != 3) { + if (ferror(f)) + return -errno; + + return -EBADMSG; + } + + /* If there's more than one line, then we don't support this file. */ + if (fgetc(f) != EOF) + return -ENXIO; + + /* If the UID and GID mapping doesn't match, we don't support this mapping. */ + if (uid_base != (uid_t) gid_base) + return -ENXIO; + if (uid_shift != (uid_t) gid_shift) + return -ENXIO; + if (uid_range != (uid_t) gid_range) + return -ENXIO; + + *ret = uid_shift; + return 0; +} + static const char* const machine_class_table[_MACHINE_CLASS_MAX] = { [MACHINE_CONTAINER] = "container", [MACHINE_VM] = "vm", |