mirror of
https://github.com/torvalds/linux.git
synced 2026-06-02 11:33:28 +02:00
Description for this pull request:
- 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.
-----BEGIN PGP SIGNATURE-----
iQJKBAABCgA0FiEE6NzKS6Uv/XAAGHgyZwv7A1FEIQgFAmnrdBoWHGxpbmtpbmpl
b25Aa2VybmVsLm9yZwAKCRBnC/sDUUQhCMNDD/9K6oUrK67F9vOhTSD/dDlLVZXu
mKP7idXDxsGQRo4xbQCKdR5F0f7fHyRYUW40+vwhcyf8eGg8pcIN8ATSh9eXoLXo
uGggm0Wf1mnVhcAnlrLCYESVF1OUrYqZWL0mdY+T5UfdimmlOZvgBT0tPMKbVt3A
6wVGpo216/ttjgEbw6txDOS9qXtoUWD+AfMnHkSmHwdxABD3Hnv082qaWeAlCMvZ
T0QJdBFW4zfynqL3x2l5jgMau0fUJOEGsghxklRjFTHLFGcwgJ8b51wO0vkIYIb8
d+Ty78LpaMDShxS9P3aGSDewMgMztRHSf4F1Lhey9ZyU+0TYRTQ+lvjpjv/tND8o
I/zYl/hUWyasIKzGXoa1oMQ9IQews+hguX/tWnal4vWB95coqH+DPSoa5/pA54hd
t5ib7asDnEFeoRiebeB/zo6bY4LspfTQwLh8/O22mHdcc2/MLLriAVFx5I0Rx9d8
eumexuAbaLSD+1fIB4F/dNZW8GsIXu8xRJEPh6NqLJqqy9fQSOoDhbUP9nNpUUvx
ZmFhQKcn/1eGk6qYJgahZ683PJskvXKtu/w6qOyGmWf44RAaOo8DgAyg2a7kt1Eh
CIa5xdvXS3RDVSwY3yOtyA9PsW1v1H80iFVbYRO/kx+92HnAkH4fCCFWd07fX7z/
X94ISuRPFzGdkIInBg==
=JZSI
-----END PGP SIGNATURE-----
Merge tag 'ntfs-for-7.1-rc1-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/ntfs
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
This commit is contained in:
commit
ff9726d7a0
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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,10 +525,9 @@ 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);
|
||||
invalidate_mapping_pages(iocb->ki_filp->f_mapping,
|
||||
offset >> PAGE_SHIFT,
|
||||
end >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
@ -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) {
|
||||
loff_t to;
|
||||
if (offset < ni->initialized_size) {
|
||||
loff_t to;
|
||||
|
||||
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,
|
||||
&ntfs_iomap_folio_ops, NULL);
|
||||
if (err < 0 || (end_vcn - 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,
|
||||
&ntfs_iomap_folio_ops, NULL);
|
||||
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,
|
||||
&ntfs_iomap_folio_ops, NULL);
|
||||
if (err < 0 || (end_vcn - start_vcn) == 1)
|
||||
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)
|
||||
goto out;
|
||||
}
|
||||
if (end_vcn - start_vcn == 1)
|
||||
goto out;
|
||||
end_vcn--;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ static int ntfs_read_iomap_begin_resident(struct inode *inode, loff_t offset, lo
|
|||
u32 attr_len;
|
||||
int err = 0;
|
||||
char *kattr;
|
||||
struct page *ipage;
|
||||
|
||||
if (NInoAttr(ni))
|
||||
base_ni = ni->ext.base_ntfs_ino;
|
||||
|
|
@ -129,15 +130,18 @@ static int ntfs_read_iomap_begin_resident(struct inode *inode, loff_t offset, lo
|
|||
|
||||
kattr = (u8 *)ctx->attr + le16_to_cpu(ctx->attr->data.resident.value_offset);
|
||||
|
||||
iomap->inline_data = kmemdup(kattr, attr_len, GFP_KERNEL);
|
||||
if (!iomap->inline_data) {
|
||||
ipage = alloc_page(GFP_NOFS | __GFP_ZERO);
|
||||
if (!ipage) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(page_address(ipage), kattr, attr_len);
|
||||
iomap->type = IOMAP_INLINE;
|
||||
iomap->inline_data = page_address(ipage);
|
||||
iomap->offset = 0;
|
||||
iomap->length = attr_len;
|
||||
iomap->private = ipage;
|
||||
|
||||
out:
|
||||
if (ctx)
|
||||
|
|
@ -285,8 +289,11 @@ static int ntfs_read_iomap_begin(struct inode *inode, loff_t offset, loff_t leng
|
|||
static int ntfs_read_iomap_end(struct inode *inode, loff_t pos, loff_t length,
|
||||
ssize_t written, unsigned int flags, struct iomap *iomap)
|
||||
{
|
||||
if (iomap->type == IOMAP_INLINE)
|
||||
kfree(iomap->inline_data);
|
||||
if (iomap->type == IOMAP_INLINE) {
|
||||
struct page *ipage = iomap->private;
|
||||
|
||||
put_page(ipage);
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
|
|
@ -384,7 +391,7 @@ static int ntfs_write_simple_iomap_begin_non_resident(struct inode *inode, loff_
|
|||
loff_t vcn_ofs, rl_length;
|
||||
struct runlist_element *rl, *rlc;
|
||||
bool is_retry = false;
|
||||
int err;
|
||||
int err = 0;
|
||||
s64 vcn, lcn;
|
||||
s64 max_clu_count =
|
||||
ntfs_bytes_to_cluster(vol, round_up(length, vol->cluster_size));
|
||||
|
|
@ -652,6 +659,7 @@ static int ntfs_write_iomap_begin_resident(struct inode *inode, loff_t offset,
|
|||
u32 attr_len;
|
||||
int err = 0;
|
||||
char *kattr;
|
||||
struct page *ipage;
|
||||
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!ctx) {
|
||||
|
|
@ -672,16 +680,19 @@ static int ntfs_write_iomap_begin_resident(struct inode *inode, loff_t offset,
|
|||
attr_len = le32_to_cpu(a->data.resident.value_length);
|
||||
kattr = (u8 *)a + le16_to_cpu(a->data.resident.value_offset);
|
||||
|
||||
iomap->inline_data = kmemdup(kattr, attr_len, GFP_KERNEL);
|
||||
if (!iomap->inline_data) {
|
||||
ipage = alloc_page(GFP_NOFS | __GFP_ZERO);
|
||||
if (!ipage) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(page_address(ipage), kattr, attr_len);
|
||||
iomap->type = IOMAP_INLINE;
|
||||
iomap->inline_data = page_address(ipage);
|
||||
iomap->offset = 0;
|
||||
/* iomap requires there is only one INLINE_DATA extent */
|
||||
iomap->length = attr_len;
|
||||
iomap->private = ipage;
|
||||
|
||||
out:
|
||||
if (ctx)
|
||||
|
|
@ -771,6 +782,7 @@ static int ntfs_write_iomap_end_resident(struct inode *inode, loff_t pos,
|
|||
u32 attr_len;
|
||||
int err;
|
||||
char *kattr;
|
||||
struct page *ipage = iomap->private;
|
||||
|
||||
mutex_lock(&ni->mrec_lock);
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
|
|
@ -799,7 +811,7 @@ static int ntfs_write_iomap_end_resident(struct inode *inode, loff_t pos,
|
|||
mark_mft_record_dirty(ctx->ntfs_ino);
|
||||
err_out:
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
kfree(iomap->inline_data);
|
||||
put_page(ipage);
|
||||
mutex_unlock(&ni->mrec_lock);
|
||||
return written;
|
||||
|
||||
|
|
|
|||
|
|
@ -2503,6 +2503,7 @@ int ntfs_mft_record_alloc(struct ntfs_volume *vol, const int mode,
|
|||
folio_unlock(folio);
|
||||
kunmap_local(m);
|
||||
folio_put(folio);
|
||||
err = -ENOMEM;
|
||||
goto undo_mftbmp_alloc;
|
||||
}
|
||||
|
||||
|
|
@ -2714,7 +2715,7 @@ static int ntfs_write_mft_block(struct folio *folio, struct writeback_control *w
|
|||
s64 vcn = ntfs_pidx_to_cluster(vol, folio->index);
|
||||
s64 end_vcn = ntfs_bytes_to_cluster(vol, ni->allocated_size);
|
||||
unsigned int folio_sz;
|
||||
struct runlist_element *rl;
|
||||
struct runlist_element *rl = NULL;
|
||||
loff_t i_size = i_size_read(vi);
|
||||
|
||||
ntfs_debug("Entering for inode 0x%llx, attribute type 0x%x, folio index 0x%lx.",
|
||||
|
|
@ -2820,7 +2821,7 @@ static int ntfs_write_mft_block(struct folio *folio, struct writeback_control *w
|
|||
|
||||
if (vol->cluster_size == NTFS_BLOCK_SIZE &&
|
||||
(mft_record_off ||
|
||||
rl->length - (vcn_off - rl->vcn) == 1 ||
|
||||
(rl && rl->length - (vcn_off - rl->vcn) == 1) ||
|
||||
mft_ofs + NTFS_BLOCK_SIZE >= PAGE_SIZE))
|
||||
folio_sz = NTFS_BLOCK_SIZE;
|
||||
else
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user