Skip to content

Commit a5d1079

Browse files
committed
Pull ntfs3 updates from Konstantin Komarov: "New: - reject inodes with zero non-DOS link count - return folios from ntfs_lock_new_page() - subset of W=1 warnings for stricter checks - work around -Wmaybe-uninitialized warnings - buffer boundary checks to run_unpack() - terminate the cached volume label after UTF-8 conversion Fixes: - check return value of indx_find to avoid infinite loop - prevent uninitialized lcn caused by zero len - increase CLIENT_REC name field size to prevent buffer overflow - missing run load for vcn0 in attr_data_get_block_locked() - memory leak in indx_create_allocate() - OOB write in attr_wof_frame_info() - mount failure on volumes with fragmented MFT bitmap - integer overflow in run_unpack() volume boundary check - validate rec->used in journal-replay file record check Updates: - resolve compare function in public index APIs - $LXDEV xattr lookup - potential double iput on d_make_root() failure - initialize err in ni_allocate_da_blocks_locked() - correct the pre_alloc condition in attr_allocate_clusters()" * tag 'ntfs3_for_7.1' of https://github.com/Paragon-Software-Group/linux-ntfs3: fs/ntfs3: fix Smatch warnings fs/ntfs3: validate rec->used in journal-replay file record check fs/ntfs3: terminate the cached volume label after UTF-8 conversion fs/ntfs3: fix potential double iput on d_make_root() failure ntfs3: fix integer overflow in run_unpack() volume boundary check ntfs3: add buffer boundary checks to run_unpack() ntfs3: fix mount failure on volumes with fragmented MFT bitmap fs/ntfs3: fix $LXDEV xattr lookup ntfs3: fix OOB write in attr_wof_frame_info() ntfs3: fix memory leak in indx_create_allocate() ntfs3: work around false-postive -Wmaybe-uninitialized warnings fs/ntfs3: fix missing run load for vcn0 in attr_data_get_block_locked() fs/ntfs3: increase CLIENT_REC name field size fs/ntfs3: prevent uninitialized lcn caused by zero len fs/ntfs3: add a subset of W=1 warnings for stricter checks fs/ntfs3: return folios from ntfs_lock_new_page() fs/ntfs3: resolve compare function in public index APIs ntfs3: reject inodes with zero non-DOS link count
2 parents a5e1c3b + 819bd27 commit a5d1079

11 files changed

Lines changed: 202 additions & 73 deletions

File tree

fs/ntfs3/Makefile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,26 @@
33
# Makefile for the ntfs3 filesystem support.
44
#
55

6+
# Subset of W=1 warnings
7+
subdir-ccflags-y += -Wextra -Wunused -Wno-unused-parameter
8+
subdir-ccflags-y += -Wmissing-declarations
9+
subdir-ccflags-y += -Wmissing-format-attribute
10+
subdir-ccflags-y += -Wmissing-prototypes
11+
subdir-ccflags-y += -Wold-style-definition
12+
subdir-ccflags-y += -Wmissing-include-dirs
13+
condflags := \
14+
$(call cc-option, -Wunused-but-set-variable) \
15+
$(call cc-option, -Wunused-const-variable) \
16+
$(call cc-option, -Wpacked-not-aligned) \
17+
$(call cc-option, -Wstringop-truncation) \
18+
$(call cc-option, -Wmaybe-uninitialized)
19+
subdir-ccflags-y += $(condflags)
20+
# The following turn off the warnings enabled by -Wextra
21+
subdir-ccflags-y += -Wno-missing-field-initializers
22+
subdir-ccflags-y += -Wno-sign-compare
23+
subdir-ccflags-y += -Wno-type-limits
24+
subdir-ccflags-y += -Wno-shift-negative-value
25+
626
# to check robot warnings
727
ccflags-y += -Wint-to-pointer-cast \
828
$(call cc-option,-Wunused-but-set-variable,-Wunused-const-variable) \

fs/ntfs3/attrib.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run,
173173

174174
if (err == -ENOSPC && pre) {
175175
pre = 0;
176-
if (*pre_alloc)
176+
if (pre_alloc)
177177
*pre_alloc = 0;
178178
continue;
179179
}
@@ -1152,6 +1152,21 @@ int attr_data_get_block_locked(struct ntfs_inode *ni, CLST vcn, CLST clen,
11521152
if (err)
11531153
goto out;
11541154
}
1155+
1156+
if (vcn0 < svcn || evcn1 <= vcn0) {
1157+
struct ATTRIB *attr2;
1158+
1159+
attr2 = ni_find_attr(ni, attr_b, &le_b, ATTR_DATA, NULL,
1160+
0, &vcn0, &mi);
1161+
if (!attr2) {
1162+
err = -EINVAL;
1163+
goto out;
1164+
}
1165+
err = attr_load_runs(attr2, ni, run, NULL);
1166+
if (err)
1167+
goto out;
1168+
}
1169+
11551170
da = false; /* no delalloc for compressed file. */
11561171
}
11571172

@@ -1576,6 +1591,12 @@ int attr_wof_frame_info(struct ntfs_inode *ni, struct ATTRIB *attr,
15761591
u64 from = vbo[i] & ~(u64)(PAGE_SIZE - 1);
15771592
u64 to = min(from + PAGE_SIZE, wof_size);
15781593

1594+
if (from >= wof_size) {
1595+
_ntfs_bad_inode(&ni->vfs_inode);
1596+
err = -EINVAL;
1597+
goto out1;
1598+
}
1599+
15791600
err = attr_load_runs_range(ni, ATTR_DATA, WOF_NAME,
15801601
ARRAY_SIZE(WOF_NAME), run,
15811602
from, to);

fs/ntfs3/frecord.c

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1852,27 +1852,31 @@ enum REPARSE_SIGN ni_parse_reparse(struct ntfs_inode *ni, struct ATTRIB *attr,
18521852
return REPARSE_LINK;
18531853
}
18541854

1855-
static struct page *ntfs_lock_new_page(struct address_space *mapping,
1856-
pgoff_t index, gfp_t gfp)
1855+
static struct folio *ntfs_lock_new_page(struct address_space *mapping,
1856+
pgoff_t index, gfp_t gfp)
18571857
{
1858-
struct folio *folio = __filemap_get_folio(
1859-
mapping, index, FGP_LOCK | FGP_ACCESSED | FGP_CREAT, gfp);
1860-
struct page *page;
1858+
struct folio *folio = __filemap_get_folio(mapping, index,
1859+
FGP_LOCK | FGP_ACCESSED | FGP_CREAT, gfp);
18611860

18621861
if (IS_ERR(folio))
1863-
return ERR_CAST(folio);
1862+
return folio;
18641863

1865-
if (!folio_test_uptodate(folio))
1866-
return folio_file_page(folio, index);
1864+
if (!folio_test_uptodate(folio)) {
1865+
struct page *page = folio_file_page(folio, index);
1866+
1867+
if (IS_ERR(page))
1868+
return ERR_CAST(page);
1869+
return page_folio(page);
1870+
}
18671871

18681872
/* Use a temporary page to avoid data corruption */
18691873
folio_unlock(folio);
18701874
folio_put(folio);
1871-
page = alloc_page(gfp);
1872-
if (!page)
1875+
folio = folio_alloc(gfp, 0);
1876+
if (!folio)
18731877
return ERR_PTR(-ENOMEM);
1874-
__SetPageLocked(page);
1875-
return page;
1878+
__folio_set_locked(folio);
1879+
return folio;
18761880
}
18771881

18781882
/*
@@ -1894,6 +1898,7 @@ int ni_read_folio_cmpr(struct ntfs_inode *ni, struct folio *folio)
18941898
u32 i, idx, frame_size, pages_per_frame;
18951899
gfp_t gfp_mask;
18961900
struct page *pg;
1901+
struct folio *f;
18971902

18981903
if (vbo >= i_size_read(&ni->vfs_inode)) {
18991904
folio_zero_range(folio, 0, folio_size(folio));
@@ -1929,12 +1934,12 @@ int ni_read_folio_cmpr(struct ntfs_inode *ni, struct folio *folio)
19291934
if (i == idx)
19301935
continue;
19311936

1932-
pg = ntfs_lock_new_page(mapping, index, gfp_mask);
1933-
if (IS_ERR(pg)) {
1934-
err = PTR_ERR(pg);
1937+
f = ntfs_lock_new_page(mapping, index, gfp_mask);
1938+
if (IS_ERR(f)) {
1939+
err = PTR_ERR(f);
19351940
goto out1;
19361941
}
1937-
pages[i] = pg;
1942+
pages[i] = &f->page;
19381943
}
19391944

19401945
ni_lock(ni);
@@ -2023,18 +2028,18 @@ int ni_decompress_file(struct ntfs_inode *ni)
20232028
}
20242029

20252030
for (i = 0; i < pages_per_frame; i++, index++) {
2026-
struct page *pg;
2031+
struct folio *f;
20272032

2028-
pg = ntfs_lock_new_page(mapping, index, gfp_mask);
2029-
if (IS_ERR(pg)) {
2033+
f = ntfs_lock_new_page(mapping, index, gfp_mask);
2034+
if (IS_ERR(f)) {
20302035
while (i--) {
20312036
unlock_page(pages[i]);
20322037
put_page(pages[i]);
20332038
}
2034-
err = PTR_ERR(pg);
2039+
err = PTR_ERR(f);
20352040
goto out;
20362041
}
2037-
pages[i] = pg;
2042+
pages[i] = &f->page;
20382043
}
20392044

20402045
err = ni_read_frame(ni, vbo, pages, pages_per_frame, 1);
@@ -3262,7 +3267,7 @@ int ni_allocate_da_blocks(struct ntfs_inode *ni)
32623267
*/
32633268
int ni_allocate_da_blocks_locked(struct ntfs_inode *ni)
32643269
{
3265-
int err;
3270+
int err = 0;
32663271

32673272
if (!ni->file.run_da.count)
32683273
return 0;

fs/ntfs3/fslog.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ struct CLIENT_REC {
4545
__le16 seq_num; // 0x14:
4646
u8 align[6]; // 0x16:
4747
__le32 name_bytes; // 0x1C: In bytes.
48-
__le16 name[32]; // 0x20: Name of client.
48+
__le16 name[64]; // 0x20: Name of client.
4949
};
5050

51-
static_assert(sizeof(struct CLIENT_REC) == 0x60);
51+
static_assert(sizeof(struct CLIENT_REC) == 0xa0);
5252

5353
/* Two copies of these will exist at the beginning of the log file */
5454
struct RESTART_AREA {
@@ -2791,13 +2791,14 @@ static inline bool check_file_record(const struct MFT_REC *rec,
27912791
u16 fn = le16_to_cpu(rec->rhdr.fix_num);
27922792
u16 ao = le16_to_cpu(rec->attr_off);
27932793
u32 rs = sbi->record_size;
2794+
u32 used = le32_to_cpu(rec->used);
27942795

27952796
/* Check the file record header for consistency. */
27962797
if (rec->rhdr.sign != NTFS_FILE_SIGNATURE ||
27972798
fo > (SECTOR_SIZE - ((rs >> SECTOR_SHIFT) + 1) * sizeof(short)) ||
27982799
(fn - 1) * SECTOR_SIZE != rs || ao < MFTRECORD_FIXUP_OFFSET_1 ||
27992800
ao > sbi->record_size - SIZEOF_RESIDENT || !is_rec_inuse(rec) ||
2800-
le32_to_cpu(rec->total) != rs) {
2801+
le32_to_cpu(rec->total) != rs || used > rs || used < ao) {
28012802
return false;
28022803
}
28032804

@@ -2809,6 +2810,15 @@ static inline bool check_file_record(const struct MFT_REC *rec,
28092810
return false;
28102811
}
28112812

2813+
/*
2814+
* The do_action() handlers compute memmove lengths as
2815+
* "rec->used - <offset of validated attr>", which underflows when
2816+
* rec->used is smaller than the attribute walk reached. At this
2817+
* point attr is the ATTR_END marker; rec->used must cover it.
2818+
*/
2819+
if (used < PtrOffset(rec, attr) + sizeof(attr->type))
2820+
return false;
2821+
28122822
return true;
28132823
}
28142824

fs/ntfs3/fsntfs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,8 +1440,8 @@ int ntfs_write_bh(struct ntfs_sb_info *sbi, struct NTFS_RECORD_HEADER *rhdr,
14401440
u16 fo = le16_to_cpu(rhdr->fix_off);
14411441
u16 fn = le16_to_cpu(rhdr->fix_num);
14421442
u32 idx;
1443-
__le16 *fixup;
1444-
__le16 sample;
1443+
__le16 *fixup = NULL;
1444+
__le16 sample = cpu_to_le16(-1u);
14451445

14461446
if ((fo & 1) || fo + fn * sizeof(short) > SECTOR_SIZE || !fn-- ||
14471447
fn * SECTOR_SIZE > bytes) {

0 commit comments

Comments
 (0)