]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fs-util: make chase_symlink() returns -ENOLINK when unsafe transitions are met
authorFranck Bui <fbui@suse.com>
Fri, 30 Nov 2018 14:13:44 +0000 (15:13 +0100)
committerFranck Bui <fbui@suse.com>
Mon, 10 Dec 2018 08:18:27 +0000 (09:18 +0100)
We previously returned -EPERM but it can be returned for various other reasons
too.

Let's use -ENOLINK instead as this value shouldn't be used currently. This
allows users of CHASE_SAFE to detect without any ambiguities when unsafe
transitions are encountered by chase_symlinks().

All current users of CHASE_SAFE that explicitly reacted on -EPERM have been
converted to react on -ENOLINK.

src/basic/fs-util.c
src/core/service.c
src/test/test-fs-util.c
src/tmpfiles/tmpfiles.c

index e45ad06491aaf375890f41ddc1c9a2bd9f39cf9a..f91d338507f8858c44a7083aed6ab96ef89f2e96 100644 (file)
@@ -649,12 +649,12 @@ static int log_unsafe_transition(int a, int b, const char *path, unsigned flags)
         _cleanup_free_ char *n1 = NULL, *n2 = NULL;
 
         if (!FLAGS_SET(flags, CHASE_WARN))
-                return -EPERM;
+                return -ENOLINK;
 
         (void) fd_get_path(a, &n1);
         (void) fd_get_path(b, &n2);
 
-        return log_warning_errno(SYNTHETIC_ERRNO(EPERM),
+        return log_warning_errno(SYNTHETIC_ERRNO(ENOLINK),
                                  "Detected unsafe path transition %s %s %s during canonicalization of %s.",
                                  n1, special_glyph(ARROW), n2, path);
 }
@@ -719,6 +719,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
          *    path is fully normalized, and == 0 for each normalization step. This may be combined with
          *    CHASE_NONEXISTENT, in which case 1 is returned when a component is not found.
          *
+         * 4. With CHASE_SAFE: in this case the path must not contain unsafe transitions, i.e. transitions from
+         *    unprivileged to privileged files or directories. In such cases the return value is -ENOLINK. If
+         *    CHASE_WARN is also set a warning describing the unsafe transition is emitted.
+         *
          * */
 
         /* A root directory of "/" or "" is identical to none */
index 964a7fd05725d62e057c5c4a1e292d9bb5992be1..1fafb33f2371dc6cbbf0d1d1fd3dd04f1863da5a 100644 (file)
@@ -934,8 +934,8 @@ static int service_load_pid_file(Service *s, bool may_warn) {
         prio = may_warn ? LOG_INFO : LOG_DEBUG;
 
         fd = chase_symlinks(s->pid_file, NULL, CHASE_OPEN|CHASE_SAFE, NULL);
-        if (fd == -EPERM) {
-                log_unit_full(UNIT(s), LOG_DEBUG, fd, "Permission denied while opening PID file or potentially unsafe symlink chain, will now retry with relaxed checks: %s", s->pid_file);
+        if (fd == -ENOLINK) {
+                log_unit_full(UNIT(s), LOG_DEBUG, fd, "Potentially unsafe symlink chain, will now retry with relaxed checks: %s", s->pid_file);
 
                 questionable_pid_file = true;
 
index d5f652c938395d3c72e7af72e49a9c7c49aa49c0..26980d939f4736a55ec3f9435d531bcdfb3e8495 100644 (file)
@@ -249,11 +249,11 @@ static void test_chase_symlinks(void) {
                 assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
 
                 assert_se(chown(q, 0, 0) >= 0);
-                assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -EPERM);
+                assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -ENOLINK);
 
                 assert_se(rmdir(q) >= 0);
                 assert_se(symlink("/etc/passwd", q) >= 0);
-                assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -EPERM);
+                assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -ENOLINK);
 
                 assert_se(chown(p, 0, 0) >= 0);
                 assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
index eeeb1d18506f4efacb07be4827ef2a59c55f295f..1f2caf5f7384fc2d8ef55b4a05091a33844976ca 100644 (file)
@@ -862,7 +862,7 @@ static int path_open_parent_safe(const char *path) {
                 return log_oom();
 
         fd = chase_symlinks(dn, NULL, CHASE_OPEN|CHASE_SAFE, NULL);
-        if (fd == -EPERM)
+        if (fd == -ENOLINK)
                 return log_error_errno(fd, "Unsafe symlinks encountered in %s, refusing.", path);
         if (fd < 0)
                 return log_error_errno(fd, "Failed to validate path %s: %m", path);
@@ -885,7 +885,7 @@ static int path_open_safe(const char *path) {
                                        path);
 
         fd = chase_symlinks(path, NULL, CHASE_OPEN|CHASE_SAFE|CHASE_NOFOLLOW, NULL);
-        if (fd == -EPERM)
+        if (fd == -ENOLINK)
                 return log_error_errno(fd, "Unsafe symlinks encountered in %s, refusing.", path);
         if (fd < 0)
                 return log_error_errno(fd, "Failed to validate path %s: %m", path);