]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
make it easier to catch those who try to modify ->d_name
authorAl Viro <viro@zeniv.linux.org.uk>
Fri, 9 Feb 2024 19:57:43 +0000 (14:57 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Tue, 16 Sep 2025 01:08:33 +0000 (21:08 -0400)
Turn d_name into an anon union of const struct qstr d_name with
struct qstr __d_name.  Very few places need to modify it (all
in fs/dcache.c); those are switched to use of ->__d_name.

Note that ->d_name can actually change under you unless you have
the right locking environment; this const just prohibits accidentally
doing stores without being easily spotted.

Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/dcache.c
include/linux/dcache.h

index 60046ae23d5148730888da2250bd72df317d65ad..b4cd5e1321b3b217348ac7f4d962bb36ed89025c 100644 (file)
@@ -1717,13 +1717,13 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
                dname = dentry->d_shortname.string;
        }       
 
-       dentry->d_name.len = name->len;
-       dentry->d_name.hash = name->hash;
+       dentry->__d_name.len = name->len;
+       dentry->__d_name.hash = name->hash;
        memcpy(dname, name->name, name->len);
        dname[name->len] = 0;
 
        /* Make sure we always see the terminating NUL character */
-       smp_store_release(&dentry->d_name.name, dname); /* ^^^ */
+       smp_store_release(&dentry->__d_name.name, dname); /* ^^^ */
 
        dentry->d_flags = 0;
        lockref_init(&dentry->d_lockref);
@@ -2743,15 +2743,15 @@ static void swap_names(struct dentry *dentry, struct dentry *target)
                        /*
                         * Both external: swap the pointers
                         */
-                       swap(target->d_name.name, dentry->d_name.name);
+                       swap(target->__d_name.name, dentry->__d_name.name);
                } else {
                        /*
                         * dentry:internal, target:external.  Steal target's
                         * storage and make target internal.
                         */
-                       dentry->d_name.name = target->d_name.name;
+                       dentry->__d_name.name = target->__d_name.name;
                        target->d_shortname = dentry->d_shortname;
-                       target->d_name.name = target->d_shortname.string;
+                       target->__d_name.name = target->d_shortname.string;
                }
        } else {
                if (unlikely(dname_external(dentry))) {
@@ -2759,9 +2759,9 @@ static void swap_names(struct dentry *dentry, struct dentry *target)
                         * dentry:external, target:internal.  Give dentry's
                         * storage to target and make dentry internal
                         */
-                       target->d_name.name = dentry->d_name.name;
+                       target->__d_name.name = dentry->__d_name.name;
                        dentry->d_shortname = target->d_shortname;
-                       dentry->d_name.name = dentry->d_shortname.string;
+                       dentry->__d_name.name = dentry->d_shortname.string;
                } else {
                        /*
                         * Both are internal.
@@ -2771,7 +2771,7 @@ static void swap_names(struct dentry *dentry, struct dentry *target)
                                     target->d_shortname.words[i]);
                }
        }
-       swap(dentry->d_name.hash_len, target->d_name.hash_len);
+       swap(dentry->__d_name.hash_len, target->__d_name.hash_len);
 }
 
 static void copy_name(struct dentry *dentry, struct dentry *target)
@@ -2781,11 +2781,11 @@ static void copy_name(struct dentry *dentry, struct dentry *target)
                old_name = external_name(dentry);
        if (unlikely(dname_external(target))) {
                atomic_inc(&external_name(target)->count);
-               dentry->d_name = target->d_name;
+               dentry->__d_name = target->__d_name;
        } else {
                dentry->d_shortname = target->d_shortname;
-               dentry->d_name.name = dentry->d_shortname.string;
-               dentry->d_name.hash_len = target->d_name.hash_len;
+               dentry->__d_name.name = dentry->d_shortname.string;
+               dentry->__d_name.hash_len = target->__d_name.hash_len;
        }
        if (old_name && likely(atomic_dec_and_test(&old_name->count)))
                kfree_rcu(old_name, head);
@@ -3133,7 +3133,7 @@ void d_mark_tmpfile(struct file *file, struct inode *inode)
                !d_unlinked(dentry));
        spin_lock(&dentry->d_parent->d_lock);
        spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
-       dentry->d_name.len = sprintf(dentry->d_shortname.string, "#%llu",
+       dentry->__d_name.len = sprintf(dentry->d_shortname.string, "#%llu",
                                (unsigned long long)inode->i_ino);
        spin_unlock(&dentry->d_lock);
        spin_unlock(&dentry->d_parent->d_lock);
index cc3e1c1a3454460a672cf86b5d5a248f4e840719..c83e02b9438940e2cf5c94a0a9aba8d401ee0b77 100644 (file)
@@ -95,7 +95,10 @@ struct dentry {
        seqcount_spinlock_t d_seq;      /* per dentry seqlock */
        struct hlist_bl_node d_hash;    /* lookup hash list */
        struct dentry *d_parent;        /* parent directory */
-       struct qstr d_name;
+       union {
+       struct qstr __d_name;           /* for use ONLY in fs/dcache.c */
+       const struct qstr d_name;
+       };
        struct inode *d_inode;          /* Where the name belongs to - NULL is
                                         * negative */
        union shortname_store d_shortname;