> You lost all the original signed-off-by lines of the original, AND you > lost the authorship of the original commit. And you didn't cc: anyone > involved in the original patch, to get their review, or objection to it > being backported. Sorry for the rookie mistakes. I drafted another version and it is attached to the email. Can you please check whether it is OK? > Also, how did you test this change? is this something that you have > actually hit in real life? Yes. I encountered this when testing the latest v5.10.y branch. A minimal proof-of-concept code looks like this: ~~~ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> int main(void) { int fd = open("/sys/kernel/config", 0); if(!fork()) { while(1) lseek(fd, SEEK_CUR, 1); } while(1) unlinkat(fd, "file", 0); return 0; } ~~~
>From 366d165e876a14a5b25ad741fdcd8658aa7e690d Mon Sep 17 00:00:00 2001 From: Kyle Zeng <zengyhkyle@xxxxxxxxx> Date: Fri, 1 Sep 2023 17:41:14 -0700 Subject: [PATCH v5.10.y] configfs: fix a race in configfs_lookup() commit c42dd069be8dfc9b2239a5c89e73bbd08ab35de0 upstream. configfs: fix a race in configfs_lookup() When configfs_lookup() is executing list_for_each_entry(), it is possible that configfs_dir_lseek() is calling list_del(). Some unfortunate interleavings of them can cause a kernel NULL pointer dereference error Thread 1 Thread 2 //configfs_dir_lseek() //configfs_lookup() list_del(&cursor->s_sibling); list_for_each_entry(sd, ...) Fix this by grabbing configfs_dirent_lock in configfs_lookup() while iterating ->s_children. Signed-off-by: Sishuai Gong <sishuai@xxxxxxxxxx> Signed-off-by: Christoph Hellwig <hch@xxxxxx> Signed-off-by: Kyle Zeng <zengyhkyle@xxxxxxxxx> --- Please apply this patch to v5.10.y. This patch adapts the original patch to v5.10.y considering codebase change. The idea is to hold the configfs_dirent_lock when traversing ->s_children, which follows the core idea of the original patch. This patch has been tested against the v5.10.y stable tree. fs/configfs/dir.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 12388ed4faa5..0b7e9ab517d5 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -479,6 +479,7 @@ static struct dentry * configfs_lookup(struct inode *dir, if (!configfs_dirent_is_ready(parent_sd)) goto out; + spin_lock(&configfs_dirent_lock); list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { if (sd->s_type & CONFIGFS_NOT_PINNED) { const unsigned char * name = configfs_get_name(sd); @@ -491,6 +492,7 @@ static struct dentry * configfs_lookup(struct inode *dir, break; } } + spin_unlock(&configfs_dirent_lock); if (!found) { /* -- 2.34.1