From: Chris Mason chattr +F or -F on an overlay directory can make the directory, or the whole mount, unusable. Lookups of the directory, and lookups in it, then fail. From code inspection, the caller only needs to own the directory. The upper filesystem must support casefolding: ext4 or f2fs with the casefold feature, or tmpfs with the casefold option. chattr +F and -F set and clear FS_CASEFOLD_FL, the casefold flag of a directory. The flag enables casefolding (case-insensitive name lookup) for the directory. All directories of an overlay must match the casefold state that was recorded at mount time, and ovl_lookup_single() enforces this: - A lookup in a directory that does not match fails with -ESTALE. - A lookup of the directory itself fails with -EREMOTE. ovl_fileattr_set() copies the directory up, which creates it in the upper layer if it only existed in a lower layer. It then passes FS_CASEFOLD_FL on to the upper filesystem. The upper filesystem accepts the change if the upper directory is empty, regardless of what the merged directory contains. The merged directory is the one that the user sees, with the names from the upper and the lower directories. After the change the upper directory no longer matches the mount. If the directory is the root of the overlay, the whole mount is affected. The flag can also change without chattr +F or -F. chattr reads all flags of a directory, changes one and writes all of them back. For a directory that only exists in a lower layer, overlayfs reads the flags from the lower filesystem. xfs with the ascii-ci feature reports FS_CASEFOLD_FL on every inode, but never sets S_CASEFOLD, the inode flag that overlayfs compares with the mount. So its directories count as not casefolded. With a lower layer on such an xfs and an upper layer on ext4 with the casefold feature, chattr +A on a lower-only directory therefore sets FS_CASEFOLD_FL on the new, empty upper directory. Reproduced as root on tmpfs and on ext4 with chattr +F or -F on an overlay directory whose upper directory was empty. Afterwards lookups below it failed with ESTALE, and lookups of the directory itself failed with EREMOTE. The chattr +A case was seen once, on a kernel with an earlier form of this patch that still passed the caller's flag on: lookups of the directory failed with EREMOTE. Fix this by returning -EOPNOTSUPP if FS_IOC_SETFLAGS, the only call that can change the flag, asks for a casefold flag on a directory that does not agree with the casefold state of the mount. This also refuses the chattr +A case above. Fixes: 083957f9614a ("ovl: support layers on case-folding capable filesystems") Cc: stable@vger.kernel.org Signed-off-by: Chris Mason [amir: check the flag against the casefold state of the mount instead of reading back the flags] Signed-off-by: Amir Goldstein --- fs/overlayfs/inode.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 7e1ac70c5d97b..e3aa0931bea9f 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -658,6 +658,14 @@ int ovl_fileattr_set(struct mnt_idmap *idmap, unsigned int flags; int err; + /* + * Lookup refuses a directory that does not agree with the casefold + * state of the mount. Only FS_IOC_SETFLAGS can ask for a change. + */ + if (S_ISDIR(inode->i_mode) && fa->flags_valid && + !!(fa->flags & FS_CASEFOLD_FL) != OVL_FS(inode->i_sb)->casefold) + return -EOPNOTSUPP; + err = ovl_copy_up(dentry); if (!err) { ovl_path_real(dentry, &upperpath); -- 2.55.0