diff options
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | src/basic/fs-util.c | 17 | ||||
-rw-r--r-- | src/basic/fs-util.h | 1 | ||||
-rw-r--r-- | src/test/test-fs-util.c | 62 |
4 files changed, 80 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index 1018afea57..870b22cefc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1837,6 +1837,7 @@ test_util_SOURCES = \ src/test/test-util.c test_util_LDADD = \ + libsystemd-internal.la \ libsystemd-shared.la test_hexdecoct_SOURCES = \ diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index b239cf15cb..1e7c828e7b 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -561,6 +561,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, assert(path); + /* Either the file may be missing, or we return an fd to the final object, but both make no sense */ + if ((flags & (CHASE_NONEXISTENT|CHASE_OPEN)) == (CHASE_NONEXISTENT|CHASE_OPEN)) + return -EINVAL; + /* This is a lot like canonicalize_file_name(), but takes an additional "root" parameter, that allows following * symlinks relative to a root directory, instead of the root of the host. * @@ -816,6 +820,19 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, done = NULL; } + if (flags & CHASE_OPEN) { + int q; + + /* Return the O_PATH fd we currently are looking to the caller. It can translate it to a proper fd by + * opening /proc/self/fd/xyz. */ + + assert(fd >= 0); + q = fd; + fd = -1; + + return q; + } + return exists; } diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index f42dc06804..8d6703e8fd 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -82,6 +82,7 @@ enum { CHASE_NONEXISTENT = 1U << 1, /* If set, it's OK if the path doesn't actually exist. */ CHASE_NO_AUTOFS = 1U << 2, /* If set, return -EREMOTE if autofs mount point found */ CHASE_SAFE = 1U << 3, /* If set, return EPERM if we ever traverse from unprivileged to privileged files or directories */ + CHASE_OPEN = 1U << 4, /* If set, return an O_PATH object to the final component */ }; int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret); diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c index d3e7de35ee..3ccb4ed714 100644 --- a/src/test/test-fs-util.c +++ b/src/test/test-fs-util.c @@ -23,10 +23,13 @@ #include "fileio.h" #include "fd-util.h" #include "fs-util.h" +#include "io-util.h" +#include "hexdecoct.h" #include "macro.h" #include "mkdir.h" #include "path-util.h" #include "rm-rf.h" +#include "stdio-util.h" #include "string-util.h" #include "strv.h" #include "util.h" @@ -128,11 +131,45 @@ static void test_var_tmp(void) { } } +static int id128_read_fd(int fd, sd_id128_t *ret) { + char buf[33]; + ssize_t k; + unsigned j; + sd_id128_t t; + + assert_return(fd >= 0, -EINVAL); + + k = loop_read(fd, buf, 33, false); + if (k < 0) + return (int) k; + + if (k != 33) + return -EIO; + + if (buf[32] !='\n') + return -EIO; + + for (j = 0; j < 16; j++) { + int a, b; + + a = unhexchar(buf[j*2]); + b = unhexchar(buf[j*2+1]); + + if (a < 0 || b < 0) + return -EIO; + + t.bytes[j] = a << 4 | b; + } + + *ret = t; + return 0; +} + static void test_chase_symlinks(void) { _cleanup_free_ char *result = NULL; char temp[] = "/tmp/test-chase.XXXXXX"; const char *top, *p, *pslash, *q, *qslash; - int r; + int r, pfd; assert_se(mkdtemp(temp)); @@ -357,6 +394,29 @@ static void test_chase_symlinks(void) { assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0); } + p = strjoina(temp, "/machine-id-test"); + assert_se(symlink("/usr/../etc/./machine-id", p) >= 0); + + pfd = chase_symlinks(p, NULL, CHASE_OPEN, NULL); + if (pfd != -ENOENT) { + char procfs[sizeof("/proc/self/fd/") - 1 + DECIMAL_STR_MAX(pfd) + 1]; + _cleanup_close_ int fd = -1; + sd_id128_t a, b; + + assert_se(pfd >= 0); + + xsprintf(procfs, "/proc/self/fd/%i", pfd); + + fd = open(procfs, O_RDONLY|O_CLOEXEC); + assert_se(fd >= 0); + + safe_close(pfd); + + assert_se(id128_read_fd(fd, &a) >= 0); + assert_se(sd_id128_get_machine(&b) >= 0); + assert_se(sd_id128_equal(a, b)); + } + assert_se(rm_rf(temp, REMOVE_ROOT) >= 0); } |