ovl: unbless lower st_ino of unverified origin
authorAmir Goldstein <amir73il@gmail.com>
Tue, 21 Nov 2017 11:55:51 +0000 (13:55 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Wed, 24 Jan 2018 10:25:52 +0000 (11:25 +0100)
On a malformed overlay, several redirected dirs can point to the same
dir on a lower layer. This presents a similar challenge as broken
hardlinks, because different objects in the overlay can return the same
st_ino/st_dev pair from stat(2).

For broken hardlinks, we do not provide constant st_ino on copy up to
avoid this inconsistency. When NFS export feature is enabled, apply
the same logic to files and directories with unverified lower origin.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/overlayfs/inode.c

index 94d2f8a..9658707 100644 (file)
@@ -105,12 +105,20 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
                         * Lower hardlinks may be broken on copy up to different
                         * upper files, so we cannot use the lower origin st_ino
                         * for those different files, even for the same fs case.
+                        *
+                        * Similarly, several redirected dirs can point to the
+                        * same dir on a lower layer. With the "verify_lower"
+                        * feature, we do not use the lower origin st_ino, if
+                        * we haven't verified that this redirect is unique.
+                        *
                         * With inodes index enabled, it is safe to use st_ino
-                        * of an indexed hardlinked origin. The index validates
-                        * that the upper hardlink is not broken.
+                        * of an indexed origin. The index validates that the
+                        * upper hardlink is not broken and that a redirected
+                        * dir is the only redirect to that origin.
                         */
-                       if (is_dir || lowerstat.nlink == 1 ||
-                           ovl_test_flag(OVL_INDEX, d_inode(dentry)))
+                       if (ovl_test_flag(OVL_INDEX, d_inode(dentry)) ||
+                           (!ovl_verify_lower(dentry->d_sb) &&
+                            (is_dir || lowerstat.nlink == 1)))
                                stat->ino = lowerstat.ino;
 
                        if (samefs)