Skip to content

Commit f69d00d

Browse files
committed
Pull ntfs3 fixes from Konstantin Komarov: - memory leak - some logic errors, NULL dereferences - some code was refactored - more sanity checks * tag 'ntfs3_for_6.6' of https://github.com/Paragon-Software-Group/linux-ntfs3: fs/ntfs3: Avoid possible memory leak fs/ntfs3: Fix directory element type detection fs/ntfs3: Fix possible null-pointer dereference in hdr_find_e() fs/ntfs3: Fix OOB read in ntfs_init_from_boot fs/ntfs3: fix panic about slab-out-of-bounds caused by ntfs_list_ea() fs/ntfs3: Fix NULL pointer dereference on error in attr_allocate_frame() fs/ntfs3: Fix possible NULL-ptr-deref in ni_readpage_cmpr() fs/ntfs3: Do not allow to change label if volume is read-only fs/ntfs3: Add more info into /proc/fs/ntfs3/<dev>/volinfo fs/ntfs3: Refactoring and comments fs/ntfs3: Fix alternative boot searching fs/ntfs3: Allow repeated call to ntfs3_put_sbi fs/ntfs3: Use inode_set_ctime_to_ts instead of inode_set_ctime fs/ntfs3: Fix shift-out-of-bounds in ntfs_fill_super fs/ntfs3: fix deadlock in mark_as_free_ex fs/ntfs3: Add more attributes checks in mi_enum_attr() fs/ntfs3: Use kvmalloc instead of kmalloc(... __GFP_NOWARN) fs/ntfs3: Write immediately updated ntfs state fs/ntfs3: Add ckeck in ni_update_parent()
2 parents 7cf4bea + e449477 commit f69d00d

File tree

16 files changed

+197
-82
lines changed

16 files changed

+197
-82
lines changed

fs/ntfs3/attrib.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,10 +1106,10 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
11061106
}
11071107
}
11081108

1109-
/*
1109+
/*
11101110
* The code below may require additional cluster (to extend attribute list)
1111-
* and / or one MFT record
1112-
* It is too complex to undo operations if -ENOSPC occurs deep inside
1111+
* and / or one MFT record
1112+
* It is too complex to undo operations if -ENOSPC occurs deep inside
11131113
* in 'ni_insert_nonresident'.
11141114
* Return in advance -ENOSPC here if there are no free cluster and no free MFT.
11151115
*/
@@ -1736,10 +1736,8 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
17361736
le_b = NULL;
17371737
attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL,
17381738
0, NULL, &mi_b);
1739-
if (!attr_b) {
1740-
err = -ENOENT;
1741-
goto out;
1742-
}
1739+
if (!attr_b)
1740+
return -ENOENT;
17431741

17441742
attr = attr_b;
17451743
le = le_b;

fs/ntfs3/attrlist.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr)
5252

5353
if (!attr->non_res) {
5454
lsize = le32_to_cpu(attr->res.data_size);
55-
le = kmalloc(al_aligned(lsize), GFP_NOFS | __GFP_NOWARN);
55+
/* attr is resident: lsize < record_size (1K or 4K) */
56+
le = kvmalloc(al_aligned(lsize), GFP_KERNEL);
5657
if (!le) {
5758
err = -ENOMEM;
5859
goto out;
@@ -80,7 +81,17 @@ int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr)
8081
if (err < 0)
8182
goto out;
8283

83-
le = kmalloc(al_aligned(lsize), GFP_NOFS | __GFP_NOWARN);
84+
/* attr is nonresident.
85+
* The worst case:
86+
* 1T (2^40) extremely fragmented file.
87+
* cluster = 4K (2^12) => 2^28 fragments
88+
* 2^9 fragments per one record => 2^19 records
89+
* 2^5 bytes of ATTR_LIST_ENTRY per one record => 2^24 bytes.
90+
*
91+
* the result is 16M bytes per attribute list.
92+
* Use kvmalloc to allocate in range [several Kbytes - dozen Mbytes]
93+
*/
94+
le = kvmalloc(al_aligned(lsize), GFP_KERNEL);
8495
if (!le) {
8596
err = -ENOMEM;
8697
goto out;

fs/ntfs3/bitmap.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ void wnd_close(struct wnd_bitmap *wnd)
125125
struct rb_node *node, *next;
126126

127127
kfree(wnd->free_bits);
128+
wnd->free_bits = NULL;
128129
run_close(&wnd->run);
129130

130131
node = rb_first(&wnd->start_tree);
@@ -659,7 +660,8 @@ int wnd_init(struct wnd_bitmap *wnd, struct super_block *sb, size_t nbits)
659660
wnd->bits_last = wbits;
660661

661662
wnd->free_bits =
662-
kcalloc(wnd->nwnd, sizeof(u16), GFP_NOFS | __GFP_NOWARN);
663+
kvmalloc_array(wnd->nwnd, sizeof(u16), GFP_KERNEL | __GFP_ZERO);
664+
663665
if (!wnd->free_bits)
664666
return -ENOMEM;
665667

fs/ntfs3/dir.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,11 @@ static inline int ntfs_filldir(struct ntfs_sb_info *sbi, struct ntfs_inode *ni,
309309
return 0;
310310
}
311311

312-
dt_type = (fname->dup.fa & FILE_ATTRIBUTE_DIRECTORY) ? DT_DIR : DT_REG;
312+
/* NTFS: symlinks are "dir + reparse" or "file + reparse" */
313+
if (fname->dup.fa & FILE_ATTRIBUTE_REPARSE_POINT)
314+
dt_type = DT_LNK;
315+
else
316+
dt_type = (fname->dup.fa & FILE_ATTRIBUTE_DIRECTORY) ? DT_DIR : DT_REG;
313317

314318
return !dir_emit(ctx, (s8 *)name, name_len, ino, dt_type);
315319
}

fs/ntfs3/file.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -745,8 +745,8 @@ static ssize_t ntfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
745745
}
746746

747747
static ssize_t ntfs_file_splice_read(struct file *in, loff_t *ppos,
748-
struct pipe_inode_info *pipe,
749-
size_t len, unsigned int flags)
748+
struct pipe_inode_info *pipe, size_t len,
749+
unsigned int flags)
750750
{
751751
struct inode *inode = in->f_mapping->host;
752752
struct ntfs_inode *ni = ntfs_i(inode);

fs/ntfs3/frecord.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2148,7 +2148,7 @@ int ni_readpage_cmpr(struct ntfs_inode *ni, struct page *page)
21482148

21492149
for (i = 0; i < pages_per_frame; i++) {
21502150
pg = pages[i];
2151-
if (i == idx)
2151+
if (i == idx || !pg)
21522152
continue;
21532153
unlock_page(pg);
21542154
put_page(pg);
@@ -3208,6 +3208,12 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup,
32083208
if (!fname || !memcmp(&fname->dup, dup, sizeof(fname->dup)))
32093209
continue;
32103210

3211+
/* Check simple case when parent inode equals current inode. */
3212+
if (ino_get(&fname->home) == ni->vfs_inode.i_ino) {
3213+
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
3214+
continue;
3215+
}
3216+
32113217
/* ntfs_iget5 may sleep. */
32123218
dir = ntfs_iget5(sb, &fname->home, NULL);
32133219
if (IS_ERR(dir)) {

fs/ntfs3/fslog.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2168,8 +2168,10 @@ static int last_log_lsn(struct ntfs_log *log)
21682168

21692169
if (!page) {
21702170
page = kmalloc(log->page_size, GFP_NOFS);
2171-
if (!page)
2172-
return -ENOMEM;
2171+
if (!page) {
2172+
err = -ENOMEM;
2173+
goto out;
2174+
}
21732175
}
21742176

21752177
/*

fs/ntfs3/fsntfs.c

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -983,18 +983,11 @@ int ntfs_set_state(struct ntfs_sb_info *sbi, enum NTFS_DIRTY_FLAGS dirty)
983983
if (err)
984984
return err;
985985

986-
mark_inode_dirty(&ni->vfs_inode);
986+
mark_inode_dirty_sync(&ni->vfs_inode);
987987
/* verify(!ntfs_update_mftmirr()); */
988988

989-
/*
990-
* If we used wait=1, sync_inode_metadata waits for the io for the
991-
* inode to finish. It hangs when media is removed.
992-
* So wait=0 is sent down to sync_inode_metadata
993-
* and filemap_fdatawrite is used for the data blocks.
994-
*/
995-
err = sync_inode_metadata(&ni->vfs_inode, 0);
996-
if (!err)
997-
err = filemap_fdatawrite(ni->vfs_inode.i_mapping);
989+
/* write mft record on disk. */
990+
err = _ni_write_inode(&ni->vfs_inode, 1);
998991

999992
return err;
1000993
}
@@ -2461,10 +2454,12 @@ void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim)
24612454
{
24622455
CLST end, i, zone_len, zlen;
24632456
struct wnd_bitmap *wnd = &sbi->used.bitmap;
2457+
bool dirty = false;
24642458

24652459
down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
24662460
if (!wnd_is_used(wnd, lcn, len)) {
2467-
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
2461+
/* mark volume as dirty out of wnd->rw_lock */
2462+
dirty = true;
24682463

24692464
end = lcn + len;
24702465
len = 0;
@@ -2518,6 +2513,8 @@ void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim)
25182513

25192514
out:
25202515
up_write(&wnd->rw_lock);
2516+
if (dirty)
2517+
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
25212518
}
25222519

25232520
/*

fs/ntfs3/index.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,9 @@ static struct NTFS_DE *hdr_find_e(const struct ntfs_index *indx,
729729
u32 total = le32_to_cpu(hdr->total);
730730
u16 offs[128];
731731

732+
if (unlikely(!cmp))
733+
return NULL;
734+
732735
fill_table:
733736
if (end > total)
734737
return NULL;

fs/ntfs3/inode.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ static struct inode *ntfs_read_mft(struct inode *inode,
170170
nt2kernel(std5->cr_time, &ni->i_crtime);
171171
#endif
172172
nt2kernel(std5->a_time, &inode->i_atime);
173-
ctime = inode_get_ctime(inode);
174173
nt2kernel(std5->c_time, &ctime);
174+
inode_set_ctime_to_ts(inode, ctime);
175175
nt2kernel(std5->m_time, &inode->i_mtime);
176176

177177
ni->std_fa = std5->fa;
@@ -1660,7 +1660,8 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
16601660
d_instantiate(dentry, inode);
16611661

16621662
/* Set original time. inode times (i_ctime) may be changed in ntfs_init_acl. */
1663-
inode->i_atime = inode->i_mtime = inode_set_ctime_to_ts(inode, ni->i_crtime);
1663+
inode->i_atime = inode->i_mtime =
1664+
inode_set_ctime_to_ts(inode, ni->i_crtime);
16641665
dir->i_mtime = inode_set_ctime_to_ts(dir, ni->i_crtime);
16651666

16661667
mark_inode_dirty(dir);

0 commit comments

Comments
 (0)