diff options
| author | Mark Brown <broonie@kernel.org> | 2026-10-30 10:54:13 +0000 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-10-30 10:54:13 +0000 |
| commit | 2f3fc992562134fbfcb97c23d5caeb14358f019a (patch) | |
| tree | ef309ac60886b408fc7f0ffa8b207e354a376c8e | |
| parent | 69c598196a097aceb15ecbd8fef593cc54bc3966 (diff) | |
| parent | 564c7753647731d19170914c1c637d3b33d88d3b (diff) | |
| download | linux-next-2f3fc992562134fbfcb97c23d5caeb14358f019a.tar.gz linux-next-2f3fc992562134fbfcb97c23d5caeb14358f019a.zip | |
Merge branch 'ntfs-next' of https://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/ntfs.git
| -rw-r--r-- | fs/ntfs/index.c | 41 | ||||
| -rw-r--r-- | fs/ntfs/index.h | 1 | ||||
| -rw-r--r-- | fs/ntfs/inode.c | 38 | ||||
| -rw-r--r-- | fs/ntfs/namei.c | 6 |
4 files changed, 73 insertions, 13 deletions
diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c index 66411a712b14..322cb371dbb3 100644 --- a/fs/ntfs/index.c +++ b/fs/ntfs/index.c @@ -14,6 +14,8 @@ * Copyright (c) 2007-2021 Jean-Pierre Andre */ +#include <linux/overflow.h> + #include "collate.h" #include "index.h" #include "ntfs.h" @@ -255,6 +257,32 @@ static s64 ntfs_ie_get_vcn(struct index_entry *ie) return le64_to_cpup(ntfs_ie_get_vcn_addr(ie)); } +static int ntfs_index_entry_vcn_inconsistent(const struct ntfs_volume *vol, + struct index_entry *ie, + u8 vcn_size_bits, u64 inum) +{ + s64 vcn, pos; + + if (le16_to_cpu(ie->length) < + sizeof(struct index_entry_header) + sizeof(s64)) { + ntfs_error(vol->sb, + "Index entry with node flag has no VCN in inode %llu.", + (unsigned long long)inum); + return -EIO; + } + + vcn = ntfs_ie_get_vcn(ie); + if (vcn < 0 || + check_shl_overflow(vcn, vcn_size_bits, &pos)) { + ntfs_error(vol->sb, + "Invalid index entry VCN %lld in inode %llu.", + vcn, (unsigned long long)inum); + return -EIO; + } + + return 0; +} + static struct index_entry *ntfs_ie_get_first(struct index_header *ih) { return (struct index_entry *)((u8 *)ih + le32_to_cpu(ih->entries_offset)); @@ -326,10 +354,13 @@ static int ntfs_index_header_inconsistent(struct ntfs_volume *vol, int ntfs_index_entries_inconsistent(const struct ntfs_volume *vol, const struct index_header *ih, + u32 block_size, __le32 collation_rule, u64 inum) { struct index_entry *ie; u8 *index_end = (u8 *)ih + le32_to_cpu(ih->index_length); + u8 vcn_size_bits = vol->cluster_size <= block_size ? + vol->cluster_size_bits : NTFS_BLOCK_SIZE_BITS; for (ie = ntfs_ie_get_first((struct index_header *)ih); ; ie = ntfs_ie_get_next(ie)) { @@ -348,6 +379,11 @@ int ntfs_index_entries_inconsistent(const struct ntfs_volume *vol, return -EIO; } + if ((ie->flags & INDEX_ENTRY_NODE) && + ntfs_index_entry_vcn_inconsistent(vol, ie, + vcn_size_bits, inum)) + return -EIO; + if (ntfs_ie_end(ie)) break; @@ -566,7 +602,8 @@ int ntfs_index_block_inconsistent(struct ntfs_volume *vol, return -EIO; } - if (ntfs_index_entries_inconsistent(vol, &ib->index, cr, inum)) + if (ntfs_index_entries_inconsistent(vol, &ib->index, block_size, + cr, inum)) return -EIO; return 0; } @@ -1547,9 +1584,9 @@ static int ntfs_ih_insert(struct index_header *ih, struct index_entry *orig_ie, ie_node = ntfs_ie_get_by_pos(ih, pos); old_vcn = ntfs_ie_get_vcn(ie_node); ntfs_ie_set_vcn(ie_node, new_vcn); + ntfs_ie_set_vcn(ie, old_vcn); ntfs_ie_insert(ih, ie, ie_node); - ntfs_ie_set_vcn(ie_node, old_vcn); out: kfree(ie); return ret; diff --git a/fs/ntfs/index.h b/fs/ntfs/index.h index a898e348f2c9..bc2f1bbdfba4 100644 --- a/fs/ntfs/index.h +++ b/fs/ntfs/index.h @@ -98,6 +98,7 @@ int ntfs_index_block_inconsistent(struct ntfs_volume *vol, __le32 cr, u64 inum); int ntfs_index_entries_inconsistent(const struct ntfs_volume *vol, const struct index_header *ih, + u32 block_size, __le32 collation_rule, u64 inum); struct ntfs_index_context *ntfs_index_ctx_get(struct ntfs_inode *ni, __le16 *name, u32 name_len); diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 206db4e99ef1..62dd5bd5bb81 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -1034,6 +1034,7 @@ view_index_meta: le16_to_cpu(a->data.resident.value_offset)); if (ntfs_index_root_inconsistent(ni->vol, a, ir, ni->mft_no) || ntfs_index_entries_inconsistent(ni->vol, &ir->index, + le32_to_cpu(ir->index_block_size), ir->collation_rule, ni->mft_no)) { ntfs_error(vi->i_sb, "Directory index is corrupt."); goto unm_err_out; @@ -1684,6 +1685,7 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi) ir = (struct index_root *)((u8 *)a + le16_to_cpu(a->data.resident.value_offset)); if (ntfs_index_root_inconsistent(vol, a, ir, ni->mft_no) || ntfs_index_entries_inconsistent(vol, &ir->index, + le32_to_cpu(ir->index_block_size), ir->collation_rule, ni->mft_no)) { ntfs_error(vi->i_sb, "Index is corrupt."); goto unm_err_out; @@ -2554,8 +2556,12 @@ int ntfs_show_options(struct seq_file *sf, struct dentry *root) return 0; } -int ntfs_extend_initialized_size(struct inode *vi, const loff_t offset, - const loff_t new_size) +/* + * The caller must hold @vi's mapping invalidate lock. + */ +static int __ntfs_extend_initialized_size(struct inode *vi, + const loff_t offset, + const loff_t new_size) { struct ntfs_inode *ni = NTFS_I(vi); struct ntfs_inode *mrec_ni = ntfs_base_inode(ni); @@ -2563,10 +2569,11 @@ int ntfs_extend_initialized_size(struct inode *vi, const loff_t offset, unsigned long flags; int err = 0; + lockdep_assert_held_write(&vi->i_mapping->invalidate_lock); + if (!NInoNonResident(ni)) return -EINVAL; - filemap_invalidate_lock(vi->i_mapping); read_lock_irqsave(&ni->size_lock, flags); old_init_size = ni->initialized_size; read_unlock_irqrestore(&ni->size_lock, flags); @@ -2599,9 +2606,17 @@ int ntfs_extend_initialized_size(struct inode *vi, const loff_t offset, mutex_lock(&mrec_ni->mrec_lock); err = ntfs_attr_set_initialized_size(ni, new_size); mutex_unlock(&mrec_ni->mrec_lock); - if (err) - truncate_setsize(vi, old_init_size); out: + return err; +} + +int ntfs_extend_initialized_size(struct inode *vi, const loff_t offset, + const loff_t new_size) +{ + int err; + + filemap_invalidate_lock(vi->i_mapping); + err = __ntfs_extend_initialized_size(vi, offset, new_size); filemap_invalidate_unlock(vi->i_mapping); return err; } @@ -3715,11 +3730,11 @@ s64 ntfs_inode_attr_pread(struct inode *vi, s64 pos, s64 count, u8 *buf) } } isize = i_size_read(vi); - if (pos > isize) { + if (pos < 0 || pos > isize) { mutex_unlock(&mrec_ni->mrec_lock); return -EINVAL; } - if (pos + count > isize) + if (count > isize - pos) count = isize - pos; if (!NInoNonResident(ni)) { @@ -4087,8 +4102,13 @@ s64 ntfs_inode_attr_pwrite(struct inode *vi, s64 pos, s64 count, u8 *buf, bool s mutex_unlock(&mrec_ni->mrec_lock); /* Attribute writes bypass iomap's delayed-allocation preparation. */ if (ntfs_inode_is_named_stream(ni)) { - /* A failed write must not expose any newly initialized data. */ - ret = ntfs_extend_initialized_size(vi, pos + count, pos + count); + /* + * A failed write must not expose any newly initialized + * data. The stream ioctl caller holds the mapping + * invalidate lock. + */ + ret = __ntfs_extend_initialized_size(vi, pos + count, + pos + count); modified |= ni->initialized_size != old_init_size; if (!ret) ret = ntfs_attr_fallocate(ni, pos, count, true); diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c index 62b01646c262..b46fe44b63b5 100644 --- a/fs/ntfs/namei.c +++ b/fs/ntfs/namei.c @@ -472,8 +472,10 @@ static struct ntfs_inode *__ntfs_create(const struct mnt_idmap *idmap, struct in #ifdef CONFIG_NTFS_FS_POSIX_ACL if (!S_ISLNK(mode) && (sb->s_flags & SB_POSIXACL)) { err = ntfs_init_acl(idmap, vi, dir); - if (err) - goto err_out; + if (err) { + iput(vi); + return ERR_PTR(err); + } } else #endif { |
