Commit ff9726d7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull ntfs updates from Namjae Jeon:

 - Fix potential data leakage by zeroing the portion of the straddle
   block beyond initialized_size when reading non-resident attributes

 - Remove unnecessary zeroing in ntfs_punch_hole() for ranges beyond
   initialized_size, as they are already returned as zeros on read

 - Fix writable check in ntfs_file_mmap_prepare() to correctly handle
   shared mappings using VMA_SHARED_BIT | VMA_MAYWRITE_BIT

 - Use page allocation instead of kmemdup() for IOMAP_INLINE data to
   ensure page-aligned address and avoid BUG trap in
   iomap_inline_data_valid() caused by the page boundary check

 - Add a size check before memory allocation in ntfs_attr_readall() and
   reject overly large attributes

 - Remove unneeded noop_direct_IO from ntfs_aops as it is no longer
   required following the FMODE_CAN_ODIRECT flag

 - Fix seven static analysis warnings reported by Smatch

* tag 'ntfs-for-7.1-rc1-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/ntfs:
  ntfs: use page allocation for resident attribute inline data
  ntfs: fix mmap_prepare writable check for shared mappings
  ntfs: fix potential 32-bit truncation in ntfs_write_cb()
  ntfs: fix uninitialized variable in ntfs_map_runlist_nolock
  ntfs: delete dead code
  ntfs: add missing error code in ntfs_mft_record_alloc()
  ntfs: fix uninitialized variables in ntfs_ea_set_wsl_inode()
  ntfs: fix uninitialized pointer in ntfs_write_mft_block
  ntfs: fix uninitialized variable in ntfs_write_simple_iomap_begin_non_resident
  ntfs: remove noop_direct_IO from address_space_operations
  ntfs: limit memory allocation in ntfs_attr_readall
  ntfs: not zero out range beyond init in punch_hole
  ntfs: zero out stale data in straddle block beyond initialized_size
parents bdcb864c 36ee1313
Loading
Loading
Loading
Loading
+45 −3
Original line number Diff line number Diff line
@@ -15,6 +15,41 @@
#include "debug.h"
#include "iomap.h"

static void ntfs_iomap_read_end_io(struct bio *bio)
{
	int error = blk_status_to_errno(bio->bi_status);
	struct folio_iter iter;

	bio_for_each_folio_all(iter, bio) {
		struct folio *folio = iter.folio;
		struct ntfs_inode *ni = NTFS_I(folio->mapping->host);
		s64 init_size;
		loff_t pos = folio_pos(folio);

		init_size = ni->initialized_size;
		if (pos + iter.offset < init_size &&
		    pos + iter.offset + iter.length > init_size)
			folio_zero_segment(folio, offset_in_folio(folio, init_size),
					   iter.offset + iter.length);

		iomap_finish_folio_read(folio, iter.offset, iter.length, error);
	}
	bio_put(bio);
}

static void ntfs_iomap_bio_submit_read(const struct iomap_iter *iter,
	struct iomap_read_folio_ctx *ctx)
{
	struct bio *bio = ctx->read_ctx;
	bio->bi_end_io = ntfs_iomap_read_end_io;
	submit_bio(bio);
}

static const struct iomap_read_ops ntfs_iomap_bio_read_ops = {
	.read_folio_range	= iomap_bio_read_folio_range,
	.submit_read		= ntfs_iomap_bio_submit_read,
};

/*
 * ntfs_read_folio - Read data for a folio from the device
 * @file:	open file to which the folio @folio belongs or NULL
@@ -35,6 +70,10 @@
static int ntfs_read_folio(struct file *file, struct folio *folio)
{
	struct ntfs_inode *ni = NTFS_I(folio->mapping->host);
	struct iomap_read_folio_ctx ctx = {
		.cur_folio = folio,
		.ops = &ntfs_iomap_bio_read_ops,
	};

	/*
	 * Only $DATA attributes can be encrypted and only unnamed $DATA
@@ -58,7 +97,7 @@ static int ntfs_read_folio(struct file *file, struct folio *folio)
			return ntfs_read_compressed_block(folio);
	}

	iomap_bio_read_folio(folio, &ntfs_read_iomap_ops);
	iomap_read_folio(&ntfs_read_iomap_ops, &ctx, NULL);
	return 0;
}

@@ -188,6 +227,10 @@ static void ntfs_readahead(struct readahead_control *rac)
	struct address_space *mapping = rac->mapping;
	struct inode *inode = mapping->host;
	struct ntfs_inode *ni = NTFS_I(inode);
	struct iomap_read_folio_ctx ctx = {
		.ops = &ntfs_iomap_bio_read_ops,
		.rac = rac,
	};

	/*
	 * Resident files are not cached in the page cache,
@@ -195,7 +238,7 @@ static void ntfs_readahead(struct readahead_control *rac)
	 */
	if (!NInoNonResident(ni) || NInoCompressed(ni))
		return;
	iomap_bio_readahead(rac, &ntfs_read_iomap_ops);
	iomap_readahead(&ntfs_read_iomap_ops, &ctx, NULL);
}

static int ntfs_writepages(struct address_space *mapping,
@@ -238,7 +281,6 @@ const struct address_space_operations ntfs_aops = {
	.read_folio		= ntfs_read_folio,
	.readahead		= ntfs_readahead,
	.writepages		= ntfs_writepages,
	.direct_IO		= noop_direct_IO,
	.dirty_folio		= iomap_dirty_folio,
	.bmap			= ntfs_bmap,
	.migrate_folio		= filemap_migrate_folio,
+15 −1
Original line number Diff line number Diff line
@@ -29,6 +29,13 @@

__le16 AT_UNNAMED[] = { cpu_to_le16('\0') };

/*
 * Maximum size allowed for reading attributes by ntfs_attr_readall().
 * Extended attribute, reparse point are not expected to be larger than this size.
 */

#define NTFS_ATTR_READALL_MAX_SIZE	(64 * 1024)

/*
 * ntfs_map_runlist_nolock - map (a part of) a runlist of an ntfs inode
 * @ni:		ntfs inode for which to map (part of) a runlist
@@ -85,7 +92,7 @@ int ntfs_map_runlist_nolock(struct ntfs_inode *ni, s64 vcn, struct ntfs_attr_sea
	struct runlist_element *rl;
	struct folio *put_this_folio = NULL;
	int err = 0;
	bool ctx_is_temporary = false, ctx_needs_reset;
	bool ctx_is_temporary = false, ctx_needs_reset = false;
	struct ntfs_attr_search_ctx old_ctx = { NULL, };
	size_t new_rl_count;

@@ -5117,6 +5124,13 @@ void *ntfs_attr_readall(struct ntfs_inode *ni, const __le32 type,
	}
	bmp_ni = NTFS_I(bmp_vi);

	if (bmp_ni->data_size > NTFS_ATTR_READALL_MAX_SIZE &&
		(bmp_ni->type != AT_BITMAP ||
		bmp_ni->data_size > ((ni->vol->nr_clusters + 7) >> 3))) {
		ntfs_error(sb, "Invalid attribute data size");
		goto out;
	}

	data = kvmalloc(bmp_ni->data_size, GFP_NOFS);
	if (!data)
		goto out;
+2 −1
Original line number Diff line number Diff line
@@ -1374,7 +1374,8 @@ static int ntfs_write_cb(struct ntfs_inode *ni, loff_t pos, struct page **pages,
		bio_size = insz;
	}

	new_vcn = ntfs_bytes_to_cluster(vol, pos & ~(ni->itype.compressed.block_size - 1));
	new_vcn = ntfs_bytes_to_cluster(vol,
			pos & ~((loff_t)ni->itype.compressed.block_size - 1));
	new_length = ntfs_bytes_to_cluster(vol, round_up(bio_size, vol->cluster_size));

	err = ntfs_non_resident_attr_punch_hole(ni, new_vcn, ni->itype.compressed.block_clusters);
+4 −1
Original line number Diff line number Diff line
@@ -406,7 +406,10 @@ int ntfs_ea_set_wsl_inode(struct inode *inode, dev_t rdev, __le16 *ea_size,
		unsigned int flags)
{
	__le32 v;
	int err;
	int err = 0;

	if (ea_size)
		*ea_size = 0;

	if (flags & NTFS_EA_UID) {
		/* Store uid to lxuid EA */
+25 −26
Original line number Diff line number Diff line
@@ -267,15 +267,6 @@ static int ntfs_setattr_size(struct inode *vi, struct iattr *attr)
		return err;

	inode_dio_wait(vi);
	/* Serialize against page faults */
	if (NInoNonResident(NTFS_I(vi)) && attr->ia_size < old_size) {
		err = iomap_truncate_page(vi, attr->ia_size, NULL,
				&ntfs_read_iomap_ops,
				&ntfs_iomap_folio_ops, NULL);
		if (err)
			return err;
	}

	truncate_setsize(vi, attr->ia_size);
	err = ntfs_truncate_vfs(vi, attr->ia_size, old_size);
	if (err) {
@@ -534,7 +525,6 @@ static ssize_t ntfs_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
			ret = -EIO;
			goto out;
		}
		if (!ret2)
		invalidate_mapping_pages(iocb->ki_filp->f_mapping,
					 offset >> PAGE_SHIFT,
					 end >> PAGE_SHIFT);
@@ -654,7 +644,7 @@ static int ntfs_file_mmap_prepare(struct vm_area_desc *desc)
	if (NInoCompressed(NTFS_I(inode)))
		return -EOPNOTSUPP;

	if (vma_desc_test(desc, VMA_WRITE_BIT)) {
	if (vma_desc_test_all(desc, VMA_SHARED_BIT, VMA_MAYWRITE_BIT)) {
		struct inode *inode = file_inode(file);
		loff_t from, to;
		int err;
@@ -885,14 +875,19 @@ static int ntfs_punch_hole(struct ntfs_inode *ni, int mode, loff_t offset,
	end_vcn = ntfs_bytes_to_cluster(vol, end_offset - 1) + 1;

	if (offset & vol->cluster_size_mask) {
		if (offset < ni->initialized_size) {
			loff_t to;

		to = min_t(loff_t, ntfs_cluster_to_bytes(vol, start_vcn + 1),
			to = min_t(loff_t,
				   ntfs_cluster_to_bytes(vol, start_vcn + 1),
				   end_offset);
		err = iomap_zero_range(vi, offset, to - offset, NULL,
				&ntfs_seek_iomap_ops,
			err = iomap_zero_range(vi, offset, to - offset,
					       NULL, &ntfs_seek_iomap_ops,
					       &ntfs_iomap_folio_ops, NULL);
		if (err < 0 || (end_vcn - start_vcn) == 1)
			if (err < 0)
				goto out;
		}
		if (end_vcn - start_vcn == 1)
			goto out;
		start_vcn++;
	}
@@ -901,10 +896,14 @@ static int ntfs_punch_hole(struct ntfs_inode *ni, int mode, loff_t offset,
		loff_t from;

		from = ntfs_cluster_to_bytes(vol, end_vcn - 1);
		err = iomap_zero_range(vi, from, end_offset - from, NULL,
				&ntfs_seek_iomap_ops,
		if (from < ni->initialized_size) {
			err = iomap_zero_range(vi, from, end_offset - from,
					       NULL, &ntfs_seek_iomap_ops,
					       &ntfs_iomap_folio_ops, NULL);
		if (err < 0 || (end_vcn - start_vcn) == 1)
			if (err < 0)
				goto out;
		}
		if (end_vcn - start_vcn == 1)
			goto out;
		end_vcn--;
	}
Loading