chiark / gitweb /
path-util: Fix path_is_mount_point for parent mount points in symlink mode
authorMartin Pitt <martin.pitt@ubuntu.com>
Tue, 9 Jun 2015 14:16:56 +0000 (16:16 +0200)
committerSven Eden <yamakuzure@gmx.net>
Tue, 14 Mar 2017 09:01:48 +0000 (10:01 +0100)
When we have a structure like this:

  /bin -> /usr/bin
  /usr is a mount point

Then path_is_mount_point("/bin", AT_SYMLINK_FOLLOW) needs to look at the pair
/usr/bin and /usr, not at the pair / and /usr/bin, as the latter have different
mount IDs. But we only want to consider the base name, not any parent.

Thus we have to resolve the given path first to get the real parent when
allowing symlinks.

Bug: https://github.com/systemd/systemd/issues/61

src/shared/path-util.c

index be50a1865df9c7acfb2d55c9a95c969adc83e1d1..537705446a026eddd55750103747a9882ed5037c 100644 (file)
@@ -640,7 +640,7 @@ fallback_fstat:
 /* flags can be AT_SYMLINK_FOLLOW or 0 */
 int path_is_mount_point(const char *t, int flags) {
         _cleanup_close_ int fd = -1;
-        _cleanup_free_ char *parent = NULL;
+        _cleanup_free_ char *canonical = NULL, *parent = NULL;
         int r;
 
         assert(t);
@@ -648,7 +648,17 @@ int path_is_mount_point(const char *t, int flags) {
         if (path_equal(t, "/"))
                 return 1;
 
-        r = path_get_parent(t, &parent);
+        /* we need to resolve symlinks manually, we can't just rely on
+         * fd_is_mount_point() to do that for us; if we have a structure like
+         * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
+         * look at needs to be /usr, not /. */
+        if (flags & AT_SYMLINK_FOLLOW) {
+                canonical = canonicalize_file_name(t);
+                if (!canonical)
+                        return -errno;
+        }
+
+        r = path_get_parent(canonical ?: t, &parent);
         if (r < 0)
                 return r;
 
@@ -656,7 +666,7 @@ int path_is_mount_point(const char *t, int flags) {
         if (fd < 0)
                 return -errno;
 
-        return fd_is_mount_point(fd, basename(t), flags);
+        return fd_is_mount_point(fd, basename(canonical ?: t), flags);
 }
 
 int path_is_read_only_fs(const char *path) {