Skip to content

Commit a2343df

Browse files
committed
Pull ntfs3 fixes from Konstantin Komarov: "Fixed: - size update for compressed file - some logic errors, overflows - memory leak - some code was refactored Added: - implement super_operations::shutdown Improved: - alternative boot processing - reduced stack usage" * tag 'ntfs3_for_6.8' of https://github.com/Paragon-Software-Group/linux-ntfs3: (28 commits) fs/ntfs3: Slightly simplify ntfs_inode_printk() fs/ntfs3: Add ioctl operation for directories (FITRIM) fs/ntfs3: Fix oob in ntfs_listxattr fs/ntfs3: Fix an NULL dereference bug fs/ntfs3: Update inode->i_size after success write into compressed file fs/ntfs3: Fixed overflow check in mi_enum_attr() fs/ntfs3: Correct function is_rst_area_valid fs/ntfs3: Use i_size_read and i_size_write fs/ntfs3: Prevent generic message "attempt to access beyond end of device" fs/ntfs3: use non-movable memory for ntfs3 MFT buffer cache fs/ntfs3: Use kvfree to free memory allocated by kvmalloc fs/ntfs3: Disable ATTR_LIST_ENTRY size check fs/ntfs3: Fix c/mtime typo fs/ntfs3: Add NULL ptr dereference checking at the end of attr_allocate_frame() fs/ntfs3: Add and fix comments fs/ntfs3: ntfs3_forced_shutdown use int instead of bool fs/ntfs3: Implement super_operations::shutdown fs/ntfs3: Drop suid and sgid bits as a part of fpunch fs/ntfs3: Add file_modified fs/ntfs3: Correct use bh_read ...
2 parents 4356e9f + 622cd3d commit a2343df

File tree

16 files changed

+381
-247
lines changed

16 files changed

+381
-247
lines changed

fs/ntfs3/attrib.c

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -886,7 +886,7 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
886886
struct runs_tree *run = &ni->file.run;
887887
struct ntfs_sb_info *sbi;
888888
u8 cluster_bits;
889-
struct ATTRIB *attr = NULL, *attr_b;
889+
struct ATTRIB *attr, *attr_b;
890890
struct ATTR_LIST_ENTRY *le, *le_b;
891891
struct mft_inode *mi, *mi_b;
892892
CLST hint, svcn, to_alloc, evcn1, next_svcn, asize, end, vcn0, alen;
@@ -904,12 +904,8 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
904904
*len = 0;
905905
up_read(&ni->file.run_lock);
906906

907-
if (*len) {
908-
if (*lcn != SPARSE_LCN || !new)
909-
return 0; /* Fast normal way without allocation. */
910-
else if (clen > *len)
911-
clen = *len;
912-
}
907+
if (*len && (*lcn != SPARSE_LCN || !new))
908+
return 0; /* Fast normal way without allocation. */
913909

914910
/* No cluster in cache or we need to allocate cluster in hole. */
915911
sbi = ni->mi.sbi;
@@ -918,6 +914,17 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
918914
ni_lock(ni);
919915
down_write(&ni->file.run_lock);
920916

917+
/* Repeat the code above (under write lock). */
918+
if (!run_lookup_entry(run, vcn, lcn, len, NULL))
919+
*len = 0;
920+
921+
if (*len) {
922+
if (*lcn != SPARSE_LCN || !new)
923+
goto out; /* normal way without allocation. */
924+
if (clen > *len)
925+
clen = *len;
926+
}
927+
921928
le_b = NULL;
922929
attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL, &mi_b);
923930
if (!attr_b) {
@@ -1736,8 +1743,10 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
17361743
le_b = NULL;
17371744
attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL,
17381745
0, NULL, &mi_b);
1739-
if (!attr_b)
1740-
return -ENOENT;
1746+
if (!attr_b) {
1747+
err = -ENOENT;
1748+
goto out;
1749+
}
17411750

17421751
attr = attr_b;
17431752
le = le_b;
@@ -1818,13 +1827,15 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
18181827
ok:
18191828
run_truncate_around(run, vcn);
18201829
out:
1821-
if (new_valid > data_size)
1822-
new_valid = data_size;
1830+
if (attr_b) {
1831+
if (new_valid > data_size)
1832+
new_valid = data_size;
18231833

1824-
valid_size = le64_to_cpu(attr_b->nres.valid_size);
1825-
if (new_valid != valid_size) {
1826-
attr_b->nres.valid_size = cpu_to_le64(valid_size);
1827-
mi_b->dirty = true;
1834+
valid_size = le64_to_cpu(attr_b->nres.valid_size);
1835+
if (new_valid != valid_size) {
1836+
attr_b->nres.valid_size = cpu_to_le64(valid_size);
1837+
mi_b->dirty = true;
1838+
}
18281839
}
18291840

18301841
return err;
@@ -2073,7 +2084,7 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
20732084

20742085
/* Update inode size. */
20752086
ni->i_valid = valid_size;
2076-
ni->vfs_inode.i_size = data_size;
2087+
i_size_write(&ni->vfs_inode, data_size);
20772088
inode_set_bytes(&ni->vfs_inode, total_size);
20782089
ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
20792090
mark_inode_dirty(&ni->vfs_inode);
@@ -2488,7 +2499,7 @@ int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
24882499
mi_b->dirty = true;
24892500

24902501
done:
2491-
ni->vfs_inode.i_size += bytes;
2502+
i_size_write(&ni->vfs_inode, ni->vfs_inode.i_size + bytes);
24922503
ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
24932504
mark_inode_dirty(&ni->vfs_inode);
24942505

fs/ntfs3/attrlist.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ static inline bool al_is_valid_le(const struct ntfs_inode *ni,
2929
void al_destroy(struct ntfs_inode *ni)
3030
{
3131
run_close(&ni->attr_list.run);
32-
kfree(ni->attr_list.le);
32+
kvfree(ni->attr_list.le);
3333
ni->attr_list.le = NULL;
3434
ni->attr_list.size = 0;
3535
ni->attr_list.dirty = false;
@@ -127,12 +127,13 @@ struct ATTR_LIST_ENTRY *al_enumerate(struct ntfs_inode *ni,
127127
{
128128
size_t off;
129129
u16 sz;
130+
const unsigned le_min_size = le_size(0);
130131

131132
if (!le) {
132133
le = ni->attr_list.le;
133134
} else {
134135
sz = le16_to_cpu(le->size);
135-
if (sz < sizeof(struct ATTR_LIST_ENTRY)) {
136+
if (sz < le_min_size) {
136137
/* Impossible 'cause we should not return such le. */
137138
return NULL;
138139
}
@@ -141,16 +142,15 @@ struct ATTR_LIST_ENTRY *al_enumerate(struct ntfs_inode *ni,
141142

142143
/* Check boundary. */
143144
off = PtrOffset(ni->attr_list.le, le);
144-
if (off + sizeof(struct ATTR_LIST_ENTRY) > ni->attr_list.size) {
145+
if (off + le_min_size > ni->attr_list.size) {
145146
/* The regular end of list. */
146147
return NULL;
147148
}
148149

149150
sz = le16_to_cpu(le->size);
150151

151152
/* Check le for errors. */
152-
if (sz < sizeof(struct ATTR_LIST_ENTRY) ||
153-
off + sz > ni->attr_list.size ||
153+
if (sz < le_min_size || off + sz > ni->attr_list.size ||
154154
sz < le->name_off + le->name_len * sizeof(short)) {
155155
return NULL;
156156
}
@@ -318,7 +318,7 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
318318
memcpy(ptr, al->le, off);
319319
memcpy(Add2Ptr(ptr, off + sz), le, old_size - off);
320320
le = Add2Ptr(ptr, off);
321-
kfree(al->le);
321+
kvfree(al->le);
322322
al->le = ptr;
323323
} else {
324324
memmove(Add2Ptr(le, sz), le, old_size - off);

fs/ntfs3/bitmap.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ void wnd_close(struct wnd_bitmap *wnd)
124124
{
125125
struct rb_node *node, *next;
126126

127-
kfree(wnd->free_bits);
127+
kvfree(wnd->free_bits);
128128
wnd->free_bits = NULL;
129129
run_close(&wnd->run);
130130

@@ -1360,7 +1360,7 @@ int wnd_extend(struct wnd_bitmap *wnd, size_t new_bits)
13601360
memcpy(new_free, wnd->free_bits, wnd->nwnd * sizeof(short));
13611361
memset(new_free + wnd->nwnd, 0,
13621362
(new_wnd - wnd->nwnd) * sizeof(short));
1363-
kfree(wnd->free_bits);
1363+
kvfree(wnd->free_bits);
13641364
wnd->free_bits = new_free;
13651365
}
13661366

fs/ntfs3/dir.c

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

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;
312+
/*
313+
* NTFS: symlinks are "dir + reparse" or "file + reparse"
314+
* Unfortunately reparse attribute is used for many purposes (several dozens).
315+
* It is not possible here to know is this name symlink or not.
316+
* To get exactly the type of name we should to open inode (read mft).
317+
* getattr for opened file (fstat) correctly returns symlink.
318+
*/
319+
dt_type = (fname->dup.fa & FILE_ATTRIBUTE_DIRECTORY) ? DT_DIR : DT_REG;
320+
321+
/*
322+
* It is not reliable to detect the type of name using duplicated information
323+
* stored in parent directory.
324+
* The only correct way to get the type of name - read MFT record and find ATTR_STD.
325+
* The code below is not good idea.
326+
* It does additional locks/reads just to get the type of name.
327+
* Should we use additional mount option to enable branch below?
328+
*/
329+
if ((fname->dup.fa & FILE_ATTRIBUTE_REPARSE_POINT) &&
330+
ino != ni->mi.rno) {
331+
struct inode *inode = ntfs_iget5(sbi->sb, &e->ref, NULL);
332+
if (!IS_ERR_OR_NULL(inode)) {
333+
dt_type = fs_umode_to_dtype(inode->i_mode);
334+
iput(inode);
335+
}
336+
}
317337

318338
return !dir_emit(ctx, (s8 *)name, name_len, ino, dt_type);
319339
}
@@ -495,11 +515,9 @@ static int ntfs_dir_count(struct inode *dir, bool *is_empty, size_t *dirs,
495515
struct INDEX_HDR *hdr;
496516
const struct ATTR_FILE_NAME *fname;
497517
u32 e_size, off, end;
498-
u64 vbo = 0;
499518
size_t drs = 0, fles = 0, bit = 0;
500-
loff_t i_size = ni->vfs_inode.i_size;
501519
struct indx_node *node = NULL;
502-
u8 index_bits = ni->dir.index_bits;
520+
size_t max_indx = i_size_read(&ni->vfs_inode) >> ni->dir.index_bits;
503521

504522
if (is_empty)
505523
*is_empty = true;
@@ -518,8 +536,10 @@ static int ntfs_dir_count(struct inode *dir, bool *is_empty, size_t *dirs,
518536
e = Add2Ptr(hdr, off);
519537
e_size = le16_to_cpu(e->size);
520538
if (e_size < sizeof(struct NTFS_DE) ||
521-
off + e_size > end)
539+
off + e_size > end) {
540+
/* Looks like corruption. */
522541
break;
542+
}
523543

524544
if (de_is_last(e))
525545
break;
@@ -543,7 +563,7 @@ static int ntfs_dir_count(struct inode *dir, bool *is_empty, size_t *dirs,
543563
fles += 1;
544564
}
545565

546-
if (vbo >= i_size)
566+
if (bit >= max_indx)
547567
goto out;
548568

549569
err = indx_used_bit(&ni->dir, ni, &bit);
@@ -553,8 +573,7 @@ static int ntfs_dir_count(struct inode *dir, bool *is_empty, size_t *dirs,
553573
if (bit == MINUS_ONE_T)
554574
goto out;
555575

556-
vbo = (u64)bit << index_bits;
557-
if (vbo >= i_size)
576+
if (bit >= max_indx)
558577
goto out;
559578

560579
err = indx_read(&ni->dir, ni, bit << ni->dir.idx2vbn_bits,
@@ -564,7 +583,6 @@ static int ntfs_dir_count(struct inode *dir, bool *is_empty, size_t *dirs,
564583

565584
hdr = &node->index->ihdr;
566585
bit += 1;
567-
vbo = (u64)bit << ni->dir.idx2vbn_bits;
568586
}
569587

570588
out:
@@ -593,5 +611,9 @@ const struct file_operations ntfs_dir_operations = {
593611
.iterate_shared = ntfs_readdir,
594612
.fsync = generic_file_fsync,
595613
.open = ntfs_file_open,
614+
.unlocked_ioctl = ntfs_ioctl,
615+
#ifdef CONFIG_COMPAT
616+
.compat_ioctl = ntfs_compat_ioctl,
617+
#endif
596618
};
597619
// clang-format on

0 commit comments

Comments
 (0)