fs/ext4/ext4.h | 2 +- fs/ext4/inline.c | 4 +++- fs/ext4/namei.c | 32 ++++++++++++++++++++++++++------ 3 files changed, 30 insertions(+), 8 deletions(-)
Syzbot reported a use-after-free in ext4_insert_dentry.
Before inserting the next directory entry, it is necessary to confirm
whether there is enough space in the next directory entry.
When the space is insufficient, it will not be inserted and an error code
-EINVAL will be returned.
Reported-by: syzbot+0c99c3f90699936c1e77@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=0c99c3f90699936c1e77
Signed-off-by: Edward Adam Davis <eadavis@qq.com>
---
fs/ext4/ext4.h | 2 +-
fs/ext4/inline.c | 4 +++-
fs/ext4/namei.c | 32 ++++++++++++++++++++++++++------
3 files changed, 30 insertions(+), 8 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 44b0d418143c..e07ac540ed00 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2834,7 +2834,7 @@ extern int ext4_find_dest_de(struct inode *dir, struct inode *inode,
void *buf, int buf_size,
struct ext4_filename *fname,
struct ext4_dir_entry_2 **dest_de);
-void ext4_insert_dentry(struct inode *dir, struct inode *inode,
+int ext4_insert_dentry(struct inode *dir, struct inode *inode,
struct ext4_dir_entry_2 *de,
int buf_size,
struct ext4_filename *fname);
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index 3536ca7e4fcc..e318b13459d1 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -1022,7 +1022,9 @@ static int ext4_add_dirent_to_inline(handle_t *handle,
EXT4_JTR_NONE);
if (err)
return err;
- ext4_insert_dentry(dir, inode, de, inline_size, fname);
+ err = ext4_insert_dentry(dir, inode, de, inline_size, fname);
+ if (err)
+ return err;
ext4_show_inline_dir(dir, iloc->bh, inline_start, inline_size);
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 790db7eac6c2..843d23391b0c 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2084,24 +2084,38 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
return 0;
}
-void ext4_insert_dentry(struct inode *dir,
+int ext4_check_next_dentry(struct inode *dir,
struct inode *inode,
struct ext4_dir_entry_2 *de,
int buf_size,
struct ext4_filename *fname)
{
-
int nlen, rlen;
nlen = ext4_dir_rec_len(de->name_len, dir);
rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
if (de->inode) {
- struct ext4_dir_entry_2 *de1 =
+ struct ext4_dir_entry_2 *nde =
(struct ext4_dir_entry_2 *)((char *)de + nlen);
- de1->rec_len = ext4_rec_len_to_disk(rlen - nlen, buf_size);
+ nde->rec_len = ext4_rec_len_to_disk(rlen - nlen, buf_size);
de->rec_len = ext4_rec_len_to_disk(nlen, buf_size);
- de = de1;
+ de = nde;
+ rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
+ return fname_len(fname) > rlen - EXT4_BASE_DIR_LEN;
}
+
+ return 0;
+}
+
+int ext4_insert_dentry(struct inode *dir,
+ struct inode *inode,
+ struct ext4_dir_entry_2 *de,
+ int buf_size,
+ struct ext4_filename *fname)
+{
+ if (ext4_check_next_dentry(dir, inode, de, buf_size, fname))
+ return -EINVAL;
+
de->file_type = EXT4_FT_UNKNOWN;
de->inode = cpu_to_le32(inode->i_ino);
ext4_set_de_type(inode->i_sb, de, inode->i_mode);
@@ -2114,6 +2128,8 @@ void ext4_insert_dentry(struct inode *dir,
EXT4_DIRENT_HASHES(de)->minor_hash =
cpu_to_le32(hinfo->minor_hash);
}
+
+ return 0;
}
/*
@@ -2151,7 +2167,11 @@ static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname,
}
/* By now the buffer is marked for journaling */
- ext4_insert_dentry(dir, inode, de, blocksize, fname);
+ err = ext4_insert_dentry(dir, inode, de, blocksize, fname);
+ if (err) {
+ ext4_std_error(dir->i_sb, err);
+ return err;
+ }
/*
* XXX shouldn't update any times until successful
--
2.43.0
Hi Edward,
kernel test robot noticed the following build warnings:
[auto build test WARNING on tytso-ext4/dev]
[also build test WARNING on linus/master v6.12-rc5 next-20241028]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Edward-Adam-Davis/ext4-Add-a-sanity-check-for-next-dentry-when-insert/20241027-191200
base: https://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git dev
patch link: https://lore.kernel.org/r/tencent_E4CFC65D09852ECE2EF28C83A7C3C6E41206%40qq.com
patch subject: [PATCH] ext4: Add a sanity check for next dentry when insert
config: x86_64-randconfig-121-20241028 (https://download.01.org/0day-ci/archive/20241028/202410282131.FBDMC1Gq-lkp@intel.com/config)
compiler: clang version 19.1.2 (https://github.com/llvm/llvm-project 7ba7d8e2f7b6445b60679da826210cdde29eaf8b)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241028/202410282131.FBDMC1Gq-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202410282131.FBDMC1Gq-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> fs/ext4/namei.c:2087:5: sparse: sparse: symbol 'ext4_check_next_dentry' was not declared. Should it be static?
fs/ext4/namei.c: note: in included file (through include/linux/mmzone.h, include/linux/gfp.h, include/linux/xarray.h, ...):
include/linux/page-flags.h:237:46: sparse: sparse: self-comparison always evaluates to false
include/linux/page-flags.h:237:46: sparse: sparse: self-comparison always evaluates to false
fs/ext4/namei.c: note: in included file:
fs/ext4/ext4.h:2429:9: sparse: sparse: self-comparison always evaluates to false
vim +/ext4_check_next_dentry +2087 fs/ext4/namei.c
2086
> 2087 int ext4_check_next_dentry(struct inode *dir,
2088 struct inode *inode,
2089 struct ext4_dir_entry_2 *de,
2090 int buf_size,
2091 struct ext4_filename *fname)
2092 {
2093 int nlen, rlen;
2094
2095 nlen = ext4_dir_rec_len(de->name_len, dir);
2096 rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
2097 if (de->inode) {
2098 struct ext4_dir_entry_2 *nde =
2099 (struct ext4_dir_entry_2 *)((char *)de + nlen);
2100 nde->rec_len = ext4_rec_len_to_disk(rlen - nlen, buf_size);
2101 de->rec_len = ext4_rec_len_to_disk(nlen, buf_size);
2102 de = nde;
2103 rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
2104 return fname_len(fname) > rlen - EXT4_BASE_DIR_LEN;
2105 }
2106
2107 return 0;
2108 }
2109
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Hi Edward,
kernel test robot noticed the following build warnings:
[auto build test WARNING on tytso-ext4/dev]
[also build test WARNING on linus/master v6.12-rc4 next-20241025]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Edward-Adam-Davis/ext4-Add-a-sanity-check-for-next-dentry-when-insert/20241027-191200
base: https://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git dev
patch link: https://lore.kernel.org/r/tencent_E4CFC65D09852ECE2EF28C83A7C3C6E41206%40qq.com
patch subject: [PATCH] ext4: Add a sanity check for next dentry when insert
config: x86_64-kexec (https://download.01.org/0day-ci/archive/20241027/202410272335.nwupXeQD-lkp@intel.com/config)
compiler: clang version 19.1.2 (https://github.com/llvm/llvm-project 7ba7d8e2f7b6445b60679da826210cdde29eaf8b)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241027/202410272335.nwupXeQD-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202410272335.nwupXeQD-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from fs/ext4/namei.c:29:
In file included from include/linux/pagemap.h:8:
In file included from include/linux/mm.h:2213:
include/linux/vmstat.h:504:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
504 | return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~ ^
505 | item];
| ~~~~
include/linux/vmstat.h:511:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
511 | return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~ ^
512 | NR_VM_NUMA_EVENT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~~
include/linux/vmstat.h:518:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
518 | return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
| ~~~~~~~~~~~ ^ ~~~
include/linux/vmstat.h:524:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
524 | return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~ ^
525 | NR_VM_NUMA_EVENT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~~
>> fs/ext4/namei.c:2087:5: warning: no previous prototype for function 'ext4_check_next_dentry' [-Wmissing-prototypes]
2087 | int ext4_check_next_dentry(struct inode *dir,
| ^
fs/ext4/namei.c:2087:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
2087 | int ext4_check_next_dentry(struct inode *dir,
| ^
| static
5 warnings generated.
vim +/ext4_check_next_dentry +2087 fs/ext4/namei.c
2086
> 2087 int ext4_check_next_dentry(struct inode *dir,
2088 struct inode *inode,
2089 struct ext4_dir_entry_2 *de,
2090 int buf_size,
2091 struct ext4_filename *fname)
2092 {
2093 int nlen, rlen;
2094
2095 nlen = ext4_dir_rec_len(de->name_len, dir);
2096 rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
2097 if (de->inode) {
2098 struct ext4_dir_entry_2 *nde =
2099 (struct ext4_dir_entry_2 *)((char *)de + nlen);
2100 nde->rec_len = ext4_rec_len_to_disk(rlen - nlen, buf_size);
2101 de->rec_len = ext4_rec_len_to_disk(nlen, buf_size);
2102 de = nde;
2103 rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
2104 return fname_len(fname) > rlen - EXT4_BASE_DIR_LEN;
2105 }
2106
2107 return 0;
2108 }
2109
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Hi Edward,
kernel test robot noticed the following build warnings:
[auto build test WARNING on tytso-ext4/dev]
[also build test WARNING on linus/master v6.12-rc4 next-20241025]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Edward-Adam-Davis/ext4-Add-a-sanity-check-for-next-dentry-when-insert/20241027-191200
base: https://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git dev
patch link: https://lore.kernel.org/r/tencent_E4CFC65D09852ECE2EF28C83A7C3C6E41206%40qq.com
patch subject: [PATCH] ext4: Add a sanity check for next dentry when insert
config: x86_64-rhel-8.3 (https://download.01.org/0day-ci/archive/20241027/202410272114.DrZ8huEU-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241027/202410272114.DrZ8huEU-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202410272114.DrZ8huEU-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> fs/ext4/namei.c:2087:5: warning: no previous prototype for 'ext4_check_next_dentry' [-Wmissing-prototypes]
2087 | int ext4_check_next_dentry(struct inode *dir,
| ^~~~~~~~~~~~~~~~~~~~~~
vim +/ext4_check_next_dentry +2087 fs/ext4/namei.c
2086
> 2087 int ext4_check_next_dentry(struct inode *dir,
2088 struct inode *inode,
2089 struct ext4_dir_entry_2 *de,
2090 int buf_size,
2091 struct ext4_filename *fname)
2092 {
2093 int nlen, rlen;
2094
2095 nlen = ext4_dir_rec_len(de->name_len, dir);
2096 rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
2097 if (de->inode) {
2098 struct ext4_dir_entry_2 *nde =
2099 (struct ext4_dir_entry_2 *)((char *)de + nlen);
2100 nde->rec_len = ext4_rec_len_to_disk(rlen - nlen, buf_size);
2101 de->rec_len = ext4_rec_len_to_disk(nlen, buf_size);
2102 de = nde;
2103 rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
2104 return fname_len(fname) > rlen - EXT4_BASE_DIR_LEN;
2105 }
2106
2107 return 0;
2108 }
2109
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Syzbot reported a use-after-free in ext4_insert_dentry.
Before copying the file name to the next directory entry, it is necessary to
confirm whether there is enough space in the next directory entry.
When the space is insufficient, it will not be inserted and an error code
-EINVAL will be returned.
Reported-by: syzbot+0c99c3f90699936c1e77@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=0c99c3f90699936c1e77
Signed-off-by: Edward Adam Davis <eadavis@qq.com>
---
V1 -> V2: change check_next_dentry to static and comments
fs/ext4/ext4.h | 2 +-
fs/ext4/inline.c | 4 +++-
fs/ext4/namei.c | 32 ++++++++++++++++++++++++++------
3 files changed, 30 insertions(+), 8 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 44b0d418143c..e07ac540ed00 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2834,7 +2834,7 @@ extern int ext4_find_dest_de(struct inode *dir, struct inode *inode,
void *buf, int buf_size,
struct ext4_filename *fname,
struct ext4_dir_entry_2 **dest_de);
-void ext4_insert_dentry(struct inode *dir, struct inode *inode,
+int ext4_insert_dentry(struct inode *dir, struct inode *inode,
struct ext4_dir_entry_2 *de,
int buf_size,
struct ext4_filename *fname);
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index 3536ca7e4fcc..e318b13459d1 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -1022,7 +1022,9 @@ static int ext4_add_dirent_to_inline(handle_t *handle,
EXT4_JTR_NONE);
if (err)
return err;
- ext4_insert_dentry(dir, inode, de, inline_size, fname);
+ err = ext4_insert_dentry(dir, inode, de, inline_size, fname);
+ if (err)
+ return err;
ext4_show_inline_dir(dir, iloc->bh, inline_start, inline_size);
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 790db7eac6c2..1c9fedf36fb0 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2084,24 +2084,38 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
return 0;
}
-void ext4_insert_dentry(struct inode *dir,
+static int check_next_dentry(struct inode *dir,
struct inode *inode,
struct ext4_dir_entry_2 *de,
int buf_size,
struct ext4_filename *fname)
{
-
int nlen, rlen;
nlen = ext4_dir_rec_len(de->name_len, dir);
rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
if (de->inode) {
- struct ext4_dir_entry_2 *de1 =
+ struct ext4_dir_entry_2 *nde =
(struct ext4_dir_entry_2 *)((char *)de + nlen);
- de1->rec_len = ext4_rec_len_to_disk(rlen - nlen, buf_size);
+ nde->rec_len = ext4_rec_len_to_disk(rlen - nlen, buf_size);
de->rec_len = ext4_rec_len_to_disk(nlen, buf_size);
- de = de1;
+ de = nde;
+ rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
+ return fname_len(fname) > rlen - EXT4_BASE_DIR_LEN;
}
+
+ return 0;
+}
+
+int ext4_insert_dentry(struct inode *dir,
+ struct inode *inode,
+ struct ext4_dir_entry_2 *de,
+ int buf_size,
+ struct ext4_filename *fname)
+{
+ if (check_next_dentry(dir, inode, de, buf_size, fname))
+ return -EINVAL;
+
de->file_type = EXT4_FT_UNKNOWN;
de->inode = cpu_to_le32(inode->i_ino);
ext4_set_de_type(inode->i_sb, de, inode->i_mode);
@@ -2114,6 +2128,8 @@ void ext4_insert_dentry(struct inode *dir,
EXT4_DIRENT_HASHES(de)->minor_hash =
cpu_to_le32(hinfo->minor_hash);
}
+
+ return 0;
}
/*
@@ -2151,7 +2167,11 @@ static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname,
}
/* By now the buffer is marked for journaling */
- ext4_insert_dentry(dir, inode, de, blocksize, fname);
+ err = ext4_insert_dentry(dir, inode, de, blocksize, fname);
+ if (err) {
+ ext4_std_error(dir->i_sb, err);
+ return err;
+ }
/*
* XXX shouldn't update any times until successful
--
2.43.0
Hello,
kernel test robot noticed "xfstests.generic.080.fail" on:
commit: d29093707e013ca381d404c4444413df49c719c1 ("[PATCH V2] ext4: Add a sanity check for next dentry when insert")
url: https://github.com/intel-lab-lkp/linux/commits/Edward-Adam-Davis/ext4-Add-a-sanity-check-for-next-dentry-when-insert/20241028-220910
base: https://git.kernel.org/cgit/linux/kernel/git/tytso/ext4.git dev
patch link: https://lore.kernel.org/all/tencent_2EB5A7DB06DD92D88651C9B3EED8AEF38C06@qq.com/
patch subject: [PATCH V2] ext4: Add a sanity check for next dentry when insert
in testcase: xfstests
version: xfstests-x86_64-891f4995-1_20241028
with following parameters:
disk: 4HDD
fs: ext4
fs2: smbv2
test: generic-080
config: x86_64-rhel-8.3-func
compiler: gcc-12
test machine: 4 threads Intel(R) Core(TM) i5-6500 CPU @ 3.20GHz (Skylake) with 32G memory
(please refer to attached dmesg/kmsg for entire log/backtrace)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <oliver.sang@intel.com>
| Closes: https://lore.kernel.org/oe-lkp/202411041103.a030928c-oliver.sang@intel.com
2024-10-31 17:45:57 mount /dev/sda1 /fs/sda1
2024-10-31 17:45:58 mkdir -p /smbv2//cifs/sda1
2024-10-31 17:45:58 export FSTYP=cifs
2024-10-31 17:45:58 export TEST_DEV=//localhost/fs/sda1
2024-10-31 17:45:58 export TEST_DIR=/smbv2//cifs/sda1
2024-10-31 17:45:58 export CIFS_MOUNT_OPTIONS=-ousername=root,password=pass,noperm,vers=2.0,mfsymlinks,actimeo=0
2024-10-31 17:45:58 echo generic/080
2024-10-31 17:45:58 ./check -E tests/cifs/exclude.incompatible-smb2.txt -E tests/cifs/exclude.very-slow.txt generic/080
FSTYP -- cifs
PLATFORM -- Linux/x86_64 lkp-skl-d05 6.12.0-rc1-00004-gd29093707e01 #1 SMP PREEMPT_DYNAMIC Wed Oct 30 22:27:17 CST 2024
generic/080 - output mismatch (see /lkp/benchmarks/xfstests/results//generic/080.out.bad)
--- tests/generic/080.out 2024-10-28 16:28:46.000000000 +0000
+++ /lkp/benchmarks/xfstests/results//generic/080.out.bad 2024-10-31 17:46:01.599410948 +0000
@@ -1,2 +1,3 @@
QA output created by 080
Silence is golden.
+rm: cannot remove '/smbv2/cifs/sda1/mmap_mtime_testfile': Permission denied
...
(Run 'diff -u /lkp/benchmarks/xfstests/tests/generic/080.out /lkp/benchmarks/xfstests/results//generic/080.out.bad' to see the entire diff)
Ran: generic/080
Failures: generic/080
Failed 1 of 1 tests
The kernel config and materials to reproduce are available at:
https://download.01.org/0day-ci/archive/20241104/202411041103.a030928c-oliver.sang@intel.com
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2026 Red Hat, Inc.