diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2020-07-08 22:18:17 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-08 22:18:17 +0200 |
commit | 02b0109af5d7df805cd2f765a765e8f14f08527d (patch) | |
tree | 69f48a9c3464f3b04a30c781e7dbfc1a93089fa4 /src | |
parent | Merge pull request #16404 from keszybz/release-246-prep (diff) | |
parent | shared/install: do not require /dev/null to be present in chroots (diff) | |
download | systemd-02b0109af5d7df805cd2f765a765e8f14f08527d.tar.xz systemd-02b0109af5d7df805cd2f765a765e8f14f08527d.zip |
Merge pull request #15955 from anitazha/nullorempty
core: check null_or_empty_path for masked units instead of /dev/null
Diffstat (limited to 'src')
-rw-r--r-- | src/core/unit.c | 2 | ||||
-rw-r--r-- | src/shared/install.c | 31 | ||||
-rw-r--r-- | src/test/test-install-root.c | 18 |
3 files changed, 41 insertions, 10 deletions
diff --git a/src/core/unit.c b/src/core/unit.c index edc96537cb..2c09def06f 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -5955,7 +5955,7 @@ const char *unit_label_path(const Unit *u) { return NULL; /* If a unit is masked, then don't read the SELinux label of /dev/null, as that really makes no sense */ - if (path_equal(p, "/dev/null")) + if (null_or_empty_path(p) > 0) return NULL; return p; diff --git a/src/shared/install.c b/src/shared/install.c index bb2eff7387..fb5e166ff0 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1236,8 +1236,7 @@ static int unit_file_load( "%s: unit type %s cannot be templated, ignoring.", path, unit_type_to_string(type)); if (!(flags & SEARCH_LOAD)) { - r = lstat(path, &st); - if (r < 0) + if (lstat(path, &st) < 0) return -errno; if (null_or_empty(&st)) @@ -1324,26 +1323,40 @@ static int unit_file_load_or_readlink( const char *path, const char *root_dir, SearchFlags flags) { - - _cleanup_free_ char *target = NULL; + _cleanup_free_ char *resolved = NULL; + struct stat st; int r; r = unit_file_load(c, info, path, root_dir, flags); if (r != -ELOOP || (flags & SEARCH_DROPIN)) return r; - /* This is a symlink, let's read it. */ + r = chase_symlinks(path, root_dir, CHASE_WARN | CHASE_NONEXISTENT, &resolved, NULL); + if (r >= 0 && + root_dir && + path_equal_ptr(path_startswith(resolved, root_dir), "dev/null")) + /* When looking under root_dir, we can't expect /dev/ to be mounted, + * so let's see if the path is a (possibly dangling) symlink to /dev/null. */ + info->type = UNIT_FILE_TYPE_MASKED; - r = readlink_malloc(path, &target); - if (r < 0) - return r; + else if (r > 0 && + stat(resolved, &st) >= 0 && + null_or_empty(&st)) - if (path_equal(target, "/dev/null")) info->type = UNIT_FILE_TYPE_MASKED; + else { + _cleanup_free_ char *target = NULL; const char *bn; UnitType a, b; + /* This is a symlink, let's read it. We read the link again, because last time + * we followed the link until resolution, and here we need to do one step. */ + + r = readlink_malloc(path, &target); + if (r < 0) + return r; + bn = basename(target); if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) { diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index 515f14b8ca..f309160889 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -4,6 +4,7 @@ #include "alloc-util.h" #include "fileio.h" +#include "fs-util.h" #include "install.h" #include "mkdir.h" #include "rm-rf.h" @@ -23,6 +24,7 @@ static void test_basic_mask_and_enable(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) == -ENOENT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "e.service", NULL) == -ENOENT); p = strjoina(root, "/usr/lib/systemd/system/a.service"); assert_se(write_string_file(p, @@ -150,6 +152,22 @@ static void test_basic_mask_and_enable(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS); + + /* Test masking with relative symlinks */ + + p = strjoina(root, "/usr/lib/systemd/system/e.service"); + assert_se(symlink("../../../../../../dev/null", p) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "e.service", NULL) >= 0); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "e.service", &state) >= 0 && state == UNIT_FILE_MASKED); + + assert_se(unlink(p) == 0); + assert_se(symlink("/usr/../dev/null", p) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "e.service", NULL) >= 0); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "e.service", &state) >= 0 && state == UNIT_FILE_MASKED); + + assert_se(unlink(p) == 0); } static void test_linked_units(const char *root) { |