Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ntfs: fix NULL dereference in ntfs_index_walk_down()

ntfs_index_walk_down() allocates ictx->ib when descending from the root
into an index allocation block. If that allocation fails, the old code
still passes the NULL buffer to ntfs_ib_read(), which can write through
it via ntfs_inode_attr_pread().

Allocate the index block into a temporary pointer and return -ENOMEM
before changing the index context on allocation failure. Also propagate
ERR_PTR() through ntfs_index_next() and ntfs_readdir() so walk-down
allocation or index block read failures are not mistaken for normal
index iteration inside the filesystem.

ntfs_readdir() keeps the existing userspace-visible behavior of
suppressing readdir errors after marking end_in_iterate; this change only
prevents the walk-down failure path from dereferencing NULL internally.

The failure was reproduced with failslab fail-nth injection on getdents64;
the original module hits a NULL pointer dereference in memcpy_orig through
ntfs_ib_read(), while the patched module reaches the same
ntfs_index_walk_down() allocation failure without crashing.

Fixes: 0a8ac0c1fa0b ("ntfs: update directory operations")
Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>

authored by

DaeMyung Kang and committed by
Namjae Jeon
b5198fcd 897d5401

+23 -7
+10 -3
fs/ntfs/dir.c
··· 911 911 912 912 if (next->flags & INDEX_ENTRY_NODE) { 913 913 next = ntfs_index_walk_down(next, ictx); 914 - if (!next) { 915 - err = -EIO; 914 + if (IS_ERR(next)) { 915 + err = PTR_ERR(next); 916 916 goto out; 917 917 } 918 918 } ··· 920 920 if (next && !(next->flags & INDEX_ENTRY_END)) 921 921 goto nextdir; 922 922 923 - while ((next = ntfs_index_next(next, ictx)) != NULL) { 923 + while (1) { 924 + next = ntfs_index_next(next, ictx); 925 + if (IS_ERR(next)) { 926 + err = PTR_ERR(next); 927 + goto out; 928 + } 929 + if (!next) 930 + break; 924 931 nextdir: 925 932 /* Check the consistency of an index entry */ 926 933 if (ntfs_index_entry_inconsistent(ictx, vol, next, COLLATION_FILE_NAME,
+13 -4
fs/ntfs/index.c
··· 1969 1969 struct index_entry *ntfs_index_walk_down(struct index_entry *ie, struct ntfs_index_context *ictx) 1970 1970 { 1971 1971 struct index_entry *entry; 1972 + struct index_block *ib; 1972 1973 s64 vcn; 1973 1974 1974 1975 entry = ie; 1975 1976 do { 1976 1977 vcn = ntfs_ie_get_vcn(entry); 1977 1978 if (ictx->is_in_root) { 1979 + ib = kvzalloc(ictx->block_size, GFP_NOFS); 1980 + if (!ib) 1981 + return ERR_PTR(-ENOMEM); 1978 1982 /* down from level zero */ 1979 1983 ictx->ir = NULL; 1980 - ictx->ib = kvzalloc(ictx->block_size, GFP_NOFS); 1984 + ictx->ib = ib; 1981 1985 ictx->pindex = 1; 1982 1986 ictx->is_in_root = false; 1983 1987 } else { ··· 1995 1991 ictx->entry = ntfs_ie_get_first(&ictx->ib->index); 1996 1992 entry = ictx->entry; 1997 1993 } else 1998 - entry = NULL; 1999 - } while (entry && (entry->flags & INDEX_ENTRY_NODE)); 1994 + entry = ERR_PTR(-EIO); 1995 + } while (!IS_ERR(entry) && (entry->flags & INDEX_ENTRY_NODE)); 2000 1996 2001 1997 return entry; 2002 1998 } ··· 2101 2097 2102 2098 /* walk down if it has a subnode */ 2103 2099 if (flags & INDEX_ENTRY_NODE) { 2104 - if (!ictx->ia_ni) 2100 + if (!ictx->ia_ni) { 2105 2101 ictx->ia_ni = ntfs_ia_open(ictx, ictx->idx_ni); 2102 + if (!ictx->ia_ni) 2103 + return ERR_PTR(-EIO); 2104 + } 2106 2105 2107 2106 next = ntfs_index_walk_down(next, ictx); 2107 + if (IS_ERR(next)) 2108 + return next; 2108 2109 } else { 2109 2110 2110 2111 /* walk up it has no subnode, nor data */