178 lines
6.1 KiB
Diff
178 lines
6.1 KiB
Diff
From 81f83264e1127666cfc72cc998b69103ae44b881 Mon Sep 17 00:00:00 2001
|
|
From: Amir Goldstein <amir73il@gmail.com>
|
|
Date: Mon, 2 Jun 2025 19:17:02 +0200
|
|
Subject: [PATCH] ovl: support layers on case-folding capable filesystems
|
|
Content-Type: text/plain; charset="utf-8"
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Case folding is often applied to subtrees and not on an entire
|
|
filesystem.
|
|
|
|
Disallowing layers from filesystems that support case folding is over
|
|
limiting.
|
|
|
|
Replace the rule that case-folding capable are not allowed as layers
|
|
with a rule that case folded directories are not allowed in a merged
|
|
directory stack.
|
|
|
|
Should case folding be enabled on an underlying directory while
|
|
overlayfs is mounted the outcome is generally undefined.
|
|
|
|
Specifically in ovl_lookup(), we check the base underlying directory
|
|
and fail with -ESTALE and write a warning to kmsg if an underlying
|
|
directory case folding is enabled.
|
|
|
|
Suggested-by: Kent Overstreet <kent.overstreet@linux.dev>
|
|
Link: https://lore.kernel.org/linux-fsdevel/20250520051600.1903319-1-kent.overstreet@linux.dev/
|
|
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
|
|
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
|
|
Signed-off-by: Alexander Miroshnichenko <alex@millerson.name>
|
|
---
|
|
fs/overlayfs/namei.c | 31 ++++++++++++++++++++++++++++---
|
|
fs/overlayfs/overlayfs.h | 6 ++++++
|
|
fs/overlayfs/params.c | 10 ++++------
|
|
fs/overlayfs/util.c | 15 +++++++++++----
|
|
4 files changed, 49 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
|
|
index 2043f0369059..76d6248b625e 100644
|
|
--- a/fs/overlayfs/namei.c
|
|
+++ b/fs/overlayfs/namei.c
|
|
@@ -230,13 +230,26 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
|
|
struct dentry **ret, bool drop_negative)
|
|
{
|
|
struct ovl_fs *ofs = OVL_FS(d->sb);
|
|
- struct dentry *this;
|
|
+ struct dentry *this = NULL;
|
|
+ const char *warn;
|
|
struct path path;
|
|
int err;
|
|
bool last_element = !post[0];
|
|
bool is_upper = d->layer->idx == 0;
|
|
char val;
|
|
|
|
+ /*
|
|
+ * We allow filesystems that are case-folding capable but deny composing
|
|
+ * ovl stack from case-folded directories. If someone has enabled case
|
|
+ * folding on a directory on underlying layer, the warranty of the ovl
|
|
+ * stack is voided.
|
|
+ */
|
|
+ if (ovl_dentry_casefolded(base)) {
|
|
+ warn = "case folded parent";
|
|
+ err = -ESTALE;
|
|
+ goto out_warn;
|
|
+ }
|
|
+
|
|
this = ovl_lookup_positive_unlocked(d, name, base, namelen, drop_negative);
|
|
if (IS_ERR(this)) {
|
|
err = PTR_ERR(this);
|
|
@@ -246,10 +259,17 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
|
|
goto out_err;
|
|
}
|
|
|
|
+ if (ovl_dentry_casefolded(this)) {
|
|
+ warn = "case folded child";
|
|
+ err = -EREMOTE;
|
|
+ goto out_warn;
|
|
+ }
|
|
+
|
|
if (ovl_dentry_weird(this)) {
|
|
/* Don't support traversing automounts and other weirdness */
|
|
+ warn = "unsupported object type";
|
|
err = -EREMOTE;
|
|
- goto out_err;
|
|
+ goto out_warn;
|
|
}
|
|
|
|
path.dentry = this;
|
|
@@ -283,8 +303,9 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
|
|
} else {
|
|
if (ovl_lookup_trap_inode(d->sb, this)) {
|
|
/* Caught in a trap of overlapping layers */
|
|
+ warn = "overlapping layers";
|
|
err = -ELOOP;
|
|
- goto out_err;
|
|
+ goto out_warn;
|
|
}
|
|
|
|
if (last_element)
|
|
@@ -316,6 +337,10 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
|
|
this = NULL;
|
|
goto out;
|
|
|
|
+out_warn:
|
|
+ pr_warn_ratelimited("failed lookup in %s (%pd2, name='%.*s', err=%i): %s\n",
|
|
+ is_upper ? "upper" : "lower", base,
|
|
+ namelen, name, err, warn);
|
|
out_err:
|
|
dput(this);
|
|
return err;
|
|
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
|
|
index 497323128e5f..55806bd36faa 100644
|
|
--- a/fs/overlayfs/overlayfs.h
|
|
+++ b/fs/overlayfs/overlayfs.h
|
|
@@ -448,6 +448,12 @@ void ovl_dentry_init_reval(struct dentry *dentry, struct dentry *upperdentry,
|
|
void ovl_dentry_init_flags(struct dentry *dentry, struct dentry *upperdentry,
|
|
struct ovl_entry *oe, unsigned int mask);
|
|
bool ovl_dentry_weird(struct dentry *dentry);
|
|
+
|
|
+static inline bool ovl_dentry_casefolded(struct dentry *dentry)
|
|
+{
|
|
+ return sb_has_encoding(dentry->d_sb) && IS_CASEFOLDED(d_inode(dentry));
|
|
+}
|
|
+
|
|
enum ovl_path_type ovl_path_type(struct dentry *dentry);
|
|
void ovl_path_upper(struct dentry *dentry, struct path *path);
|
|
void ovl_path_lower(struct dentry *dentry, struct path *path);
|
|
diff --git a/fs/overlayfs/params.c b/fs/overlayfs/params.c
|
|
index f42488c01957..2b9b31524c38 100644
|
|
--- a/fs/overlayfs/params.c
|
|
+++ b/fs/overlayfs/params.c
|
|
@@ -282,13 +282,11 @@ static int ovl_mount_dir_check(struct fs_context *fc, const struct path *path,
|
|
return invalfc(fc, "%s is not a directory", name);
|
|
|
|
/*
|
|
- * Root dentries of case-insensitive capable filesystems might
|
|
- * not have the dentry operations set, but still be incompatible
|
|
- * with overlayfs. Check explicitly to prevent post-mount
|
|
- * failures.
|
|
+ * Allow filesystems that are case-folding capable but deny composing
|
|
+ * ovl stack from case-folded directories.
|
|
*/
|
|
- if (sb_has_encoding(path->mnt->mnt_sb))
|
|
- return invalfc(fc, "case-insensitive capable filesystem on %s not supported", name);
|
|
+ if (ovl_dentry_casefolded(path->dentry))
|
|
+ return invalfc(fc, "case-insensitive directory on %s not supported", name);
|
|
|
|
if (ovl_dentry_weird(path->dentry))
|
|
return invalfc(fc, "filesystem on %s not supported", name);
|
|
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
|
|
index dcccb4b4a66c..593c4da107d6 100644
|
|
--- a/fs/overlayfs/util.c
|
|
+++ b/fs/overlayfs/util.c
|
|
@@ -206,10 +206,17 @@ bool ovl_dentry_weird(struct dentry *dentry)
|
|
if (!d_can_lookup(dentry) && !d_is_file(dentry) && !d_is_symlink(dentry))
|
|
return true;
|
|
|
|
- return dentry->d_flags & (DCACHE_NEED_AUTOMOUNT |
|
|
- DCACHE_MANAGE_TRANSIT |
|
|
- DCACHE_OP_HASH |
|
|
- DCACHE_OP_COMPARE);
|
|
+ if (dentry->d_flags & (DCACHE_NEED_AUTOMOUNT | DCACHE_MANAGE_TRANSIT))
|
|
+ return true;
|
|
+
|
|
+ /*
|
|
+ * Allow filesystems that are case-folding capable but deny composing
|
|
+ * ovl stack from case-folded directories.
|
|
+ */
|
|
+ if (sb_has_encoding(dentry->d_sb))
|
|
+ return IS_CASEFOLDED(d_inode(dentry));
|
|
+
|
|
+ return dentry->d_flags & (DCACHE_OP_HASH | DCACHE_OP_COMPARE);
|
|
}
|
|
|
|
enum ovl_path_type ovl_path_type(struct dentry *dentry)
|
|
--
|
|
2.49.1
|
|
|