Skip to content

Commit f0e6f20

Browse files
committed
Pull ntfs3 updates from Konstantin Komarov: "Added: - depth limit to indx_find_buffer() to prevent stack overflow - validate split-point offset in indx_insert_into_buffer() - bounds check to run_get_highest_vcn() - fileattr_get() and fileattr_set() support - zero stale pagecache beyond valid data length - handle delayed allocation overlap in run lookup - validate lcns_follow in log_replay() conversion - cap RESTART_TABLE free-chain walker at rt->used - resize log->one_page_buf when adopting on-disk page size - reject direct userspace writes to reserved $LX* xattrs Fixed: - out-of-bounds read in decompress_lznt() - avoid -Wmaybe-uninitialized warnings - hold ni_lock across readdir metadata walk - preserve non-DOS attribute bits in system.dos_attrib - validate index entry key bounds - syncing wrong inode on DIRSYNC cross-directory rename - validate Dirty Page Table capacity in log_replay() copy_lcns - wrong LCN in run_remove_range() when splitting a run - allocate iomap inline_data using alloc_page - mount failure on 64K page-size kernels - out-of-bounds read in ntfs_dir_emit() and hdr_find_e() - bound attr_off in UpdateResidentValue against data_off - bound DeleteIndexEntryAllocation memmove length - bound copy_lcns dp->page_lcns[] index in analysis pass - bound NTFS_DE view.data_off in UpdateRecordData{Root,Allocation} - prevent potential lcn remains uninitialized Changed: - bound to_move in indx_insert_into_root() before hdr_insert_head() - call _ntfs_bad_inode() when failing to rename - fold resident writeback into writepages loop - force waiting for direct I/O completion - fold file size handling into ntfs_set_size() - reject SEEK_DATA and SEEK_HOLE past EOF early - format code, add descriptive comments and remove non-useful" * tag 'ntfs3_for_7.2' of https://github.com/Paragon-Software-Group/linux-ntfs3: (34 commits) ntfs3: reject direct userspace writes to reserved $LX* xattrs fs/ntfs3: resize log->one_page_buf when adopting on-disk page size fs/ntfs3: prevent potential lcn remains uninitialized ntfs3: cap RESTART_TABLE free-chain walker at rt->used fs/ntfs3: bound NTFS_DE view.data_off in UpdateRecordData{Root,Allocation} fs/ntfs3: validate lcns_follow in log_replay conversion fs/ntfs3: bound copy_lcns dp->page_lcns[] index in analysis pass fs/ntfs3: bound DeleteIndexEntryAllocation memmove length fs/ntfs3: bound attr_off in UpdateResidentValue against data_off ntfs3: fix out-of-bounds read in ntfs_dir_emit() and hdr_find_e() fs/ntfs3: fix mount failure on 64K page-size kernels ntfs3: avoid another -Wmaybe-uninitialized warning ntfs3: Allocate iomap inline_data using alloc_page fs/ntfs3: format code, deal with comments fs/ntfs3: reject SEEK_DATA and SEEK_HOLE past EOF early fs/ntfs3: fold file size handling into ntfs_set_size() fs/ntfs3: force waiting for direct I/O completion fs/ntfs3: fold resident writeback into writepages loop fs/ntfs3: handle delayed allocation overlap in run lookup fs/ntfs3: zero stale pagecache beyond valid data length ...
2 parents 840ef6c + 5b08dcc commit f0e6f20

13 files changed

Lines changed: 590 additions & 302 deletions

File tree

fs/ntfs3/attrib.c

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -962,11 +962,8 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
962962

963963
/* Try to find in cache. */
964964
down_read(&ni->file.run_lock);
965-
if (!no_da && run_lookup_entry(&ni->file.run_da, vcn, lcn, len, NULL)) {
966-
/* The requested vcn is delay allocated. */
967-
*lcn = DELALLOC_LCN;
968-
} else if (run_lookup_entry(&ni->file.run, vcn, lcn, len, NULL)) {
969-
/* The requested vcn is known in current run. */
965+
if (run_lookup_entry_da(&ni->file.run, !no_da ? &ni->file.run_da : NULL,
966+
vcn, lcn, len)) {
970967
} else {
971968
*len = 0;
972969
}
@@ -1004,18 +1001,16 @@ int attr_data_get_block_locked(struct ntfs_inode *ni, CLST vcn, CLST clen,
10041001
struct ATTRIB *attr, *attr_b;
10051002
struct ATTR_LIST_ENTRY *le, *le_b;
10061003
struct mft_inode *mi, *mi_b;
1004+
struct page *page;
10071005
CLST hint, svcn, to_alloc, evcn1, next_svcn, asize, end, vcn0;
10081006
CLST alloc, evcn;
10091007
unsigned fr;
10101008
u64 total_size, total_size0;
10111009
int step;
10121010

10131011
again:
1014-
if (da && run_lookup_entry(run_da, vcn, lcn, len, NULL)) {
1015-
/* The requested vcn is delay allocated. */
1016-
*lcn = DELALLOC_LCN;
1017-
} else if (run_lookup_entry(run, vcn, lcn, len, NULL)) {
1018-
/* The requested vcn is known in current run. */
1012+
if (run_lookup_entry_da(run, da ? &ni->file.run_da : NULL, vcn, lcn,
1013+
len)) {
10191014
} else {
10201015
*len = 0;
10211016
}
@@ -1042,10 +1037,13 @@ int attr_data_get_block_locked(struct ntfs_inode *ni, CLST vcn, CLST clen,
10421037
*lcn = RESIDENT_LCN;
10431038
*len = data_size;
10441039
if (res && data_size) {
1045-
*res = kmemdup(resident_data(attr_b), data_size,
1046-
GFP_KERNEL);
1047-
if (!*res)
1040+
page = alloc_page(GFP_KERNEL);
1041+
if (!page) {
10481042
err = -ENOMEM;
1043+
} else {
1044+
*res = page_address(page);
1045+
memcpy(*res, resident_data(attr_b), data_size);
1046+
}
10491047
}
10501048
goto out;
10511049
}
@@ -1100,7 +1098,8 @@ int attr_data_get_block_locked(struct ntfs_inode *ni, CLST vcn, CLST clen,
11001098
}
11011099

11021100
if (!*len) {
1103-
if (run_lookup_entry(run, vcn, lcn, len, NULL)) {
1101+
if (run_lookup_entry_da(run, da ? run_da : NULL, vcn, lcn,
1102+
len)) {
11041103
if (*lcn != SPARSE_LCN || !new)
11051104
goto ok; /* Slow normal way without allocation. */
11061105

@@ -1157,7 +1156,7 @@ int attr_data_get_block_locked(struct ntfs_inode *ni, CLST vcn, CLST clen,
11571156
struct ATTRIB *attr2;
11581157

11591158
attr2 = ni_find_attr(ni, attr_b, &le_b, ATTR_DATA, NULL,
1160-
0, &vcn0, &mi);
1159+
0, &vcn0, &mi);
11611160
if (!attr2) {
11621161
err = -EINVAL;
11631162
goto out;

fs/ntfs3/dir.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,9 @@ static inline bool ntfs_dir_emit(struct ntfs_sb_info *sbi,
305305
if (sbi->options->nohidden && (fname->dup.fa & FILE_ATTRIBUTE_HIDDEN))
306306
return true;
307307

308-
if (fname->name_len + sizeof(struct NTFS_DE) > le16_to_cpu(e->size))
308+
if (sizeof(struct NTFS_DE) +
309+
offsetof(struct ATTR_FILE_NAME, name) +
310+
fname->name_len * sizeof(short) > le16_to_cpu(e->size))
309311
return true;
310312

311313
name_len = ntfs_utf16_to_nls(sbi, fname->name, fname->name_len, name,
@@ -489,10 +491,17 @@ static int ntfs_readdir(struct file *file, struct dir_context *ctx)
489491
goto out;
490492
}
491493

494+
/*
495+
* Keep directory metadata stable for the whole walk. Loading subrecords
496+
* once is not enough if concurrent writeback can still compact ATTR_LIST
497+
* entries and free the record that ntfs_read_hdr() is currently walking.
498+
*/
499+
ni_lock(ni);
500+
492501
root = indx_get_root(&ni->dir, ni, NULL, NULL);
493502
if (!root) {
494503
err = -EINVAL;
495-
goto out;
504+
goto out_unlock;
496505
}
497506

498507
if (pos >= sbi->record_size) {
@@ -503,7 +512,7 @@ static int ntfs_readdir(struct file *file, struct dir_context *ctx)
503512
*/
504513
err = ntfs_read_hdr(sbi, ni, &root->ihdr, 0, pos, name, ctx);
505514
if (err)
506-
goto out;
515+
goto out_unlock;
507516
bit = 0;
508517
}
509518

@@ -514,7 +523,7 @@ static int ntfs_readdir(struct file *file, struct dir_context *ctx)
514523
/* Get the next used index. */
515524
err = indx_used_bit(&ni->dir, ni, &bit);
516525
if (err)
517-
goto out;
526+
goto out_unlock;
518527

519528
if (bit == MINUS_ONE_T) {
520529
/* no more used indexes. end of dir. */
@@ -524,13 +533,13 @@ static int ntfs_readdir(struct file *file, struct dir_context *ctx)
524533
if (bit >= max_bit) {
525534
/* Corrupted directory. */
526535
err = -EINVAL;
527-
goto out;
536+
goto out_unlock;
528537
}
529538

530539
err = indx_read_ra(&ni->dir, ni, bit << ni->dir.idx2vbn_bits,
531540
&node, &file->f_ra);
532541
if (err)
533-
goto out;
542+
goto out_unlock;
534543

535544
/*
536545
* Add each name from index in 'ctx'.
@@ -539,9 +548,12 @@ static int ntfs_readdir(struct file *file, struct dir_context *ctx)
539548
((u64)bit << index_bits) + sbi->record_size,
540549
pos, name, ctx);
541550
if (err)
542-
goto out;
551+
goto out_unlock;
543552
}
544553

554+
out_unlock:
555+
ni_unlock(ni);
556+
545557
out:
546558
kfree(name);
547559
put_indx_node(node);

0 commit comments

Comments
 (0)