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.

Merge tag 'ntfs-for-7.1-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/ntfs

Pull ntfs fixes from Namjae Jeon:

- Fix a NULL pointer dereference in ntfs_index_walk_down() by
validating index block allocation

- Fix a memory leak of the symlink target string in
ntfs_reparse_set_wsl_symlink() during error paths

- Prevent VCN overflow and validate lowest_vcn in
ntfs_mapping_pairs_decompress() to avoid runlist corruption

- Fix a page reference leak in ntfs_write_iomap_end_resident()
when attribute search context allocation fails

- Fix an invalid PTR_ERR() usage on a valid folio pointer in
__ntfs_bitmap_set_bits_in_run()

- Correct directory link counting by dropping nlink only when
the MFT record link count reaches zero for WIN32/DOS aliases

- Fix an uninitialized variable in ntfs_mapping_pairs_decompress()
by returning an error pointer directly

* tag 'ntfs-for-7.1-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/ntfs:
ntfs: Use return instead of goto in ntfs_mapping_pairs_decompress()
ntfs: drop nlink once for WIN32/DOS aliases
ntfs: fix invalid PTR_ERR() usage in __ntfs_bitmap_set_bits_in_run()
ntfs: fix error handling in ntfs_write_iomap_end_resident()
ntfs: fix VCN overflow in ntfs_mapping_pairs_decompress()
ntfs: fix WSL symlink target leak on reparse failure
ntfs: fix NULL dereference in ntfs_index_walk_down()

+72 -25
+11 -8
fs/ntfs/bitmap.c
··· 125 125 struct address_space *mapping; 126 126 struct folio *folio; 127 127 u8 *kaddr; 128 - int pos, len; 128 + int pos, len, err; 129 129 u8 bit; 130 130 struct ntfs_inode *ni = NTFS_I(vi); 131 131 struct ntfs_volume *vol = ni->vol; ··· 201 201 202 202 /* If we are not in the last page, deal with all subsequent pages. */ 203 203 while (index < end_index) { 204 - if (cnt <= 0) 204 + if (cnt <= 0) { 205 + err = -EIO; 205 206 goto rollback; 207 + } 206 208 207 209 /* Update @index and get the next folio. */ 208 210 folio_mark_dirty(folio); ··· 216 214 ntfs_error(vi->i_sb, 217 215 "Failed to map subsequent page (error %li), aborting.", 218 216 PTR_ERR(folio)); 217 + err = PTR_ERR(folio); 219 218 goto rollback; 220 219 } 221 220 ··· 268 265 * - @count - @cnt is the number of bits that have been modified 269 266 */ 270 267 if (is_rollback) 271 - return PTR_ERR(folio); 268 + return err; 272 269 if (count != cnt) 273 270 pos = __ntfs_bitmap_set_bits_in_run(vi, start_bit, count - cnt, 274 271 value ? 0 : 1, true); ··· 277 274 if (!pos) { 278 275 /* Rollback was successful. */ 279 276 ntfs_error(vi->i_sb, 280 - "Failed to map subsequent page (error %li), aborting.", 281 - PTR_ERR(folio)); 277 + "Failed to map subsequent page (error %i), aborting.", 278 + err); 282 279 } else { 283 280 /* Rollback failed. */ 284 281 ntfs_error(vi->i_sb, 285 - "Failed to map subsequent page (error %li) and rollback failed (error %i). Aborting and leaving inconsistent metadata. Unmount and run chkdsk.", 286 - PTR_ERR(folio), pos); 282 + "Failed to map subsequent page (error %i) and rollback failed (error %i). Aborting and leaving inconsistent metadata. Unmount and run chkdsk.", 283 + err, pos); 287 284 NVolSetErrors(NTFS_SB(vi->i_sb)); 288 285 } 289 - return PTR_ERR(folio); 286 + return err; 290 287 }
+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 */
+3 -3
fs/ntfs/iomap.c
··· 788 788 ctx = ntfs_attr_get_search_ctx(ni, NULL); 789 789 if (!ctx) { 790 790 written = -ENOMEM; 791 - mutex_unlock(&ni->mrec_lock); 792 - return written; 791 + goto err_out; 793 792 } 794 793 795 794 err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, ··· 809 810 memcpy(kattr + pos, iomap_inline_data(iomap, pos), written); 810 811 mark_mft_record_dirty(ctx->ntfs_ino); 811 812 err_out: 812 - ntfs_attr_put_search_ctx(ctx); 813 + if (ctx) 814 + ntfs_attr_put_search_ctx(ctx); 813 815 put_page(ipage); 814 816 mutex_unlock(&ni->mrec_lock); 815 817 return written;
+11 -2
fs/ntfs/namei.c
··· 945 945 946 946 ni_mrec = actx->base_mrec ? actx->base_mrec : actx->mrec; 947 947 ni_mrec->link_count = cpu_to_le16(le16_to_cpu(ni_mrec->link_count) - 1); 948 - drop_nlink(VFS_I(ni)); 948 + if (!S_ISDIR(VFS_I(ni)->i_mode)) 949 + drop_nlink(VFS_I(ni)); 949 950 950 951 mark_mft_record_dirty(ni); 951 952 if (looking_for_dos_name) { ··· 955 954 ntfs_attr_reinit_search_ctx(actx); 956 955 goto search; 957 956 } 957 + 958 + /* 959 + * For directories, Drop VFS nlink only when mft record link count 960 + * becomes zero. Because we fixes VFS nlink to 1 for directories. 961 + */ 962 + if (S_ISDIR(VFS_I(ni)->i_mode) && !le16_to_cpu(ni_mrec->link_count)) 963 + drop_nlink(VFS_I(ni)); 958 964 959 965 /* 960 966 * If hard link count is not equal to zero then we are done. In other ··· 1229 1221 } 1230 1222 /* Increment hard links count. */ 1231 1223 ni_mrec->link_count = cpu_to_le16(le16_to_cpu(ni_mrec->link_count) + 1); 1232 - inc_nlink(VFS_I(ni)); 1224 + if (!S_ISDIR(vi->i_mode)) 1225 + inc_nlink(VFS_I(ni)); 1233 1226 1234 1227 /* Done! */ 1235 1228 mark_mft_record_dirty(ni);
+3 -2
fs/ntfs/reparse.c
··· 505 505 struct reparse_point *reparse; 506 506 struct wsl_link_reparse_data *data; 507 507 508 - utarget = (char *)NULL; 509 508 len = ntfs_ucstonls(ni->vol, target, target_len, &utarget, 0); 510 509 if (len <= 0) 511 510 return -EINVAL; ··· 513 514 reparse = kvzalloc(reparse_len, GFP_NOFS); 514 515 if (!reparse) { 515 516 err = -ENOMEM; 516 - kvfree(utarget); 517 + kfree(utarget); 517 518 } else { 518 519 data = (struct wsl_link_reparse_data *)reparse->reparse_data; 519 520 reparse->reparse_tag = IO_REPARSE_TAG_LX_SYMLINK; ··· 527 528 kvfree(reparse); 528 529 if (!err) 529 530 ni->target = utarget; 531 + else 532 + kfree(utarget); 530 533 } 531 534 return err; 532 535 }
+21 -3
fs/ntfs/runlist.c
··· 15 15 * Copyright (c) 2007-2022 Jean-Pierre Andre 16 16 */ 17 17 18 + #include <linux/overflow.h> 19 + 18 20 #include "ntfs.h" 19 21 #include "attrib.h" 20 22 ··· 741 739 int rlsize; /* Size of runlist buffer. */ 742 740 u16 rlpos; /* Current runlist position in units of struct runlist_elements. */ 743 741 u8 b; /* Current byte offset in buf. */ 742 + u64 lowest_vcn; /* Raw on-disk lowest_vcn. */ 744 743 745 744 #ifdef DEBUG 746 745 /* Make sure attr exists and is non-resident. */ ··· 750 747 return ERR_PTR(-EINVAL); 751 748 } 752 749 #endif 750 + lowest_vcn = le64_to_cpu(attr->data.non_resident.lowest_vcn); 751 + /* Validate lowest_vcn from on-disk metadata to ensure it is sane. */ 752 + if (overflows_type(lowest_vcn, vcn)) { 753 + ntfs_error(vol->sb, "Invalid lowest_vcn in mapping pairs."); 754 + return ERR_PTR(-EIO); 755 + } 753 756 /* Start at vcn = lowest_vcn and lcn 0. */ 754 - vcn = le64_to_cpu(attr->data.non_resident.lowest_vcn); 757 + vcn = lowest_vcn; 755 758 lcn = 0; 756 759 /* Get start of the mapping pairs array. */ 757 760 buf = (u8 *)attr + ··· 832 823 * element. 833 824 */ 834 825 rl[rlpos].length = deltaxcn; 835 - /* Increment the current vcn by the current run length. */ 836 - vcn += deltaxcn; 826 + /* 827 + * Increment the current vcn by the current run length. 828 + * Guard against s64 overflow from a crafted mapping 829 + * pairs array to preserve the monotonically-increasing 830 + * vcn invariant. 831 + */ 832 + if (unlikely(check_add_overflow(vcn, deltaxcn, &vcn))) { 833 + ntfs_error(vol->sb, "VCN overflow in mapping pairs array."); 834 + goto err_out; 835 + } 836 + 837 837 /* 838 838 * There might be no lcn change at all, as is the case for 839 839 * sparse clusters on NTFS 3.0+, in which case we set the lcn