From 0203471df1d5242ab63692ddd9e95f37f0cddadc Mon Sep 17 00:00:00 2001 From: Daniel Pinto Date: Tue, 15 Nov 2022 08:17:32 +0000 Subject: fs/ntfs3: Fix wrong cast in xattr.c cpu_to_be32 and be32_to_cpu respectively return and receive __be32, change the cast to the correct types. Fixes the following sparse warnings: fs/ntfs3/xattr.c:811:48: sparse: sparse: incorrect type in assignment (different base types) fs/ntfs3/xattr.c:901:34: sparse: sparse: cast to restricted __be32 Reported-by: kernel test robot Signed-off-by: Daniel Pinto Signed-off-by: Konstantin Komarov --- fs/ntfs3/xattr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index ff64302e87e5..f8043838eb92 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -780,7 +780,7 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de, err = sizeof(u32); *(u32 *)buffer = le32_to_cpu(ni->std_fa); if (!strcmp(name, SYSTEM_NTFS_ATTRIB_BE)) - *(u32 *)buffer = cpu_to_be32(*(u32 *)buffer); + *(__be32 *)buffer = cpu_to_be32(*(u32 *)buffer); } goto out; } @@ -857,7 +857,7 @@ static noinline int ntfs_setxattr(const struct xattr_handler *handler, if (size != sizeof(u32)) goto out; if (!strcmp(name, SYSTEM_NTFS_ATTRIB_BE)) - new_fa = cpu_to_le32(be32_to_cpu(*(u32 *)value)); + new_fa = cpu_to_le32(be32_to_cpu(*(__be32 *)value)); else new_fa = cpu_to_le32(*(u32 *)value); -- cgit v1.2.3 From bfa434c60157c9793e9b12c9b68ade02aff9f803 Mon Sep 17 00:00:00 2001 From: Chen Zhongjin Date: Tue, 22 Nov 2022 17:24:14 +0800 Subject: fs/ntfs3: Fix memory leak if ntfs_read_mft failed Label ATTR_ROOT in ntfs_read_mft() sets is_root = true and ni->ni_flags |= NI_FLAG_DIR, then next attr will goto label ATTR_ALLOC and alloc ni->dir.alloc_run. However two states are not always consistent and can make memory leak. 1) attr_name in ATTR_ROOT does not fit the condition it will set is_root = true but NI_FLAG_DIR is not set. 2) next attr_name in ATTR_ALLOC fits the condition and alloc ni->dir.alloc_run 3) in cleanup function ni_clear(), when NI_FLAG_DIR is set, it frees ni->dir.alloc_run, otherwise it frees ni->file.run 4) because NI_FLAG_DIR is not set in this case, ni->dir.alloc_run is leaked as kmemleak reported: unreferenced object 0xffff888003bc5480 (size 64): backtrace: [<000000003d42e6b0>] __kmalloc_node+0x4e/0x1c0 [<00000000d8e19b8a>] kvmalloc_node+0x39/0x1f0 [<00000000fc3eb5b8>] run_add_entry+0x18a/0xa40 [ntfs3] [<0000000011c9f978>] run_unpack+0x75d/0x8e0 [ntfs3] [<00000000e7cf1819>] run_unpack_ex+0xbc/0x500 [ntfs3] [<00000000bbf0a43d>] ntfs_iget5+0xb25/0x2dd0 [ntfs3] [<00000000a6e50693>] ntfs_fill_super+0x218d/0x3580 [ntfs3] [<00000000b9170608>] get_tree_bdev+0x3fb/0x710 [<000000004833798a>] vfs_get_tree+0x8e/0x280 [<000000006e20b8e6>] path_mount+0xf3c/0x1930 [<000000007bf15a5f>] do_mount+0xf3/0x110 ... Fix this by always setting is_root and NI_FLAG_DIR together. Fixes: 82cae269cfa9 ("fs/ntfs3: Add initialization of super block") Signed-off-by: Chen Zhongjin Signed-off-by: Konstantin Komarov --- fs/ntfs3/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index 309d9b46b5d5..ce6bb3bd86b6 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -259,7 +259,6 @@ next_attr: goto out; root = Add2Ptr(attr, roff); - is_root = true; if (attr->name_len != ARRAY_SIZE(I30_NAME) || memcmp(attr_name(attr), I30_NAME, sizeof(I30_NAME))) @@ -272,6 +271,7 @@ next_attr: if (!is_dir) goto next_attr; + is_root = true; ni->ni_flags |= NI_FLAG_DIR; err = indx_init(&ni->dir, sbi, attr, INDEX_MUTEX_I30); -- cgit v1.2.3 From e6c3cef24cb0d045f99d5cb039b344874e3cfd74 Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Wed, 23 Nov 2022 16:48:46 +0800 Subject: fs/ntfs3: Add check for kmemdup Since the kmemdup may return NULL pointer, it should be better to add check for the return value in order to avoid NULL pointer dereference. Fixes: b46acd6a6a62 ("fs/ntfs3: Add NTFS journal") Signed-off-by: Jiasheng Jiang Signed-off-by: Konstantin Komarov --- fs/ntfs3/fslog.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c index c6eb371a3695..dc723f03d6bb 100644 --- a/fs/ntfs3/fslog.c +++ b/fs/ntfs3/fslog.c @@ -4256,6 +4256,10 @@ check_attribute_names: rec_len -= t32; attr_names = kmemdup(Add2Ptr(lrh, t32), rec_len, GFP_NOFS); + if (!attr_names) { + err = -ENOMEM; + goto out; + } lcb_put(lcb); lcb = NULL; -- cgit v1.2.3 From 254e69f284d7270e0abdc023ee53b71401c3ba0c Mon Sep 17 00:00:00 2001 From: ZhangPeng Date: Fri, 25 Nov 2022 10:21:59 +0000 Subject: fs/ntfs3: Fix null-ptr-deref on inode->i_op in ntfs_lookup() Syzbot reported a null-ptr-deref bug: ntfs3: loop0: Different NTFS' sector size (1024) and media sector size (512) ntfs3: loop0: Mark volume as dirty due to NTFS errors general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] PREEMPT SMP KASAN KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] RIP: 0010:d_flags_for_inode fs/dcache.c:1980 [inline] RIP: 0010:__d_add+0x5ce/0x800 fs/dcache.c:2796 Call Trace: d_splice_alias+0x122/0x3b0 fs/dcache.c:3191 lookup_open fs/namei.c:3391 [inline] open_last_lookups fs/namei.c:3481 [inline] path_openat+0x10e6/0x2df0 fs/namei.c:3688 do_filp_open+0x264/0x4f0 fs/namei.c:3718 do_sys_openat2+0x124/0x4e0 fs/open.c:1310 do_sys_open fs/open.c:1326 [inline] __do_sys_open fs/open.c:1334 [inline] __se_sys_open fs/open.c:1330 [inline] __x64_sys_open+0x221/0x270 fs/open.c:1330 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x3d/0xb0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd If the MFT record of ntfs inode is not a base record, inode->i_op can be NULL. And a null-ptr-deref may happen: ntfs_lookup() dir_search_u() # inode->i_op is set to NULL d_splice_alias() __d_add() d_flags_for_inode() # inode->i_op->get_link null-ptr-deref Fix this by adding a Check on inode->i_op before calling the d_splice_alias() function. Fixes: 4342306f0f0d ("fs/ntfs3: Add file operations and implementation") Reported-by: syzbot+a8f26a403c169b7593fe@syzkaller.appspotmail.com Signed-off-by: ZhangPeng Signed-off-by: Konstantin Komarov --- fs/ntfs3/namei.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c index 407fe92394e2..8d206770d8c6 100644 --- a/fs/ntfs3/namei.c +++ b/fs/ntfs3/namei.c @@ -88,6 +88,16 @@ static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *dentry, __putname(uni); } + /* + * Check for a null pointer + * If the MFT record of ntfs inode is not a base record, inode->i_op can be NULL. + * This causes null pointer dereference in d_splice_alias(). + */ + if (!IS_ERR(inode) && inode->i_op == NULL) { + iput(inode); + inode = ERR_PTR(-EINVAL); + } + return d_splice_alias(inode, dentry); } -- cgit v1.2.3 From db2a3cc6a3481076da6344cc62a80a4e2525f36f Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Thu, 17 Nov 2022 17:19:12 +0800 Subject: fs/ntfs3: Fix NULL pointer dereference in 'ni_write_inode' Syzbot found the following issue: Unable to handle kernel NULL pointer dereference at virtual address 0000000000000016 Mem abort info: ESR = 0x0000000096000006 EC = 0x25: DABT (current EL), IL = 32 bits SET = 0, FnV = 0 EA = 0, S1PTW = 0 FSC = 0x06: level 2 translation fault Data abort info: ISV = 0, ISS = 0x00000006 CM = 0, WnR = 0 user pgtable: 4k pages, 48-bit VAs, pgdp=000000010af56000 [0000000000000016] pgd=08000001090da003, p4d=08000001090da003, pud=08000001090ce003, pmd=0000000000000000 Internal error: Oops: 0000000096000006 [#1] PREEMPT SMP Modules linked in: CPU: 1 PID: 3036 Comm: syz-executor206 Not tainted 6.0.0-rc6-syzkaller-17739-g16c9f284e746 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 08/26/2022 pstate: 80400005 (Nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : is_rec_inuse fs/ntfs3/ntfs.h:313 [inline] pc : ni_write_inode+0xac/0x798 fs/ntfs3/frecord.c:3232 lr : ni_write_inode+0xa0/0x798 fs/ntfs3/frecord.c:3226 sp : ffff8000126c3800 x29: ffff8000126c3860 x28: 0000000000000000 x27: ffff0000c8b02000 x26: ffff0000c7502320 x25: ffff0000c7502288 x24: 0000000000000000 x23: ffff80000cbec91c x22: ffff0000c8b03000 x21: ffff0000c8b02000 x20: 0000000000000001 x19: ffff0000c75024d8 x18: 00000000000000c0 x17: ffff80000dd1b198 x16: ffff80000db59158 x15: ffff0000c4b6b500 x14: 00000000000000b8 x13: 0000000000000000 x12: ffff0000c4b6b500 x11: ff80800008be1b60 x10: 0000000000000000 x9 : ffff0000c4b6b500 x8 : 0000000000000000 x7 : ffff800008be1b50 x6 : 0000000000000000 x5 : 0000000000000000 x4 : 0000000000000001 x3 : 0000000000000000 x2 : 0000000000000008 x1 : 0000000000000001 x0 : 0000000000000000 Call trace: is_rec_inuse fs/ntfs3/ntfs.h:313 [inline] ni_write_inode+0xac/0x798 fs/ntfs3/frecord.c:3232 ntfs_evict_inode+0x54/0x84 fs/ntfs3/inode.c:1744 evict+0xec/0x334 fs/inode.c:665 iput_final fs/inode.c:1748 [inline] iput+0x2c4/0x324 fs/inode.c:1774 ntfs_new_inode+0x7c/0xe0 fs/ntfs3/fsntfs.c:1660 ntfs_create_inode+0x20c/0xe78 fs/ntfs3/inode.c:1278 ntfs_create+0x54/0x74 fs/ntfs3/namei.c:100 lookup_open fs/namei.c:3413 [inline] open_last_lookups fs/namei.c:3481 [inline] path_openat+0x804/0x11c4 fs/namei.c:3688 do_filp_open+0xdc/0x1b8 fs/namei.c:3718 do_sys_openat2+0xb8/0x22c fs/open.c:1311 do_sys_open fs/open.c:1327 [inline] __do_sys_openat fs/open.c:1343 [inline] __se_sys_openat fs/open.c:1338 [inline] __arm64_sys_openat+0xb0/0xe0 fs/open.c:1338 __invoke_syscall arch/arm64/kernel/syscall.c:38 [inline] invoke_syscall arch/arm64/kernel/syscall.c:52 [inline] el0_svc_common+0x138/0x220 arch/arm64/kernel/syscall.c:142 do_el0_svc+0x48/0x164 arch/arm64/kernel/syscall.c:206 el0_svc+0x58/0x150 arch/arm64/kernel/entry-common.c:636 el0t_64_sync_handler+0x84/0xf0 arch/arm64/kernel/entry-common.c:654 el0t_64_sync+0x18c/0x190 Code: 97dafee4 340001b4 f9401328 2a1f03e0 (79402d14) ---[ end trace 0000000000000000 ]--- Above issue may happens as follows: ntfs_new_inode mi_init mi->mrec = kmalloc(sbi->record_size, GFP_NOFS); -->failed to allocate memory if (!mi->mrec) return -ENOMEM; iput iput_final evict ntfs_evict_inode ni_write_inode is_rec_inuse(ni->mi.mrec)-> As 'ni->mi.mrec' is NULL trigger NULL-ptr-deref To solve above issue if new inode failed make inode bad before call 'iput()' in 'ntfs_new_inode()'. Reported-by: syzbot+f45957555ed4a808cc7a@syzkaller.appspotmail.com Signed-off-by: Ye Bin Signed-off-by: Konstantin Komarov --- fs/ntfs3/fsntfs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c index 567563771bf8..8de861ddec60 100644 --- a/fs/ntfs3/fsntfs.c +++ b/fs/ntfs3/fsntfs.c @@ -1683,6 +1683,7 @@ struct ntfs_inode *ntfs_new_inode(struct ntfs_sb_info *sbi, CLST rno, bool dir) out: if (err) { + make_bad_inode(inode); iput(inode); ni = ERR_PTR(err); } -- cgit v1.2.3 From b8c44949044e5f7f864525fdffe8e95135ce9ce5 Mon Sep 17 00:00:00 2001 From: ZhangPeng Date: Wed, 7 Dec 2022 09:46:10 +0000 Subject: fs/ntfs3: Fix OOB read in indx_insert_into_buffer Syzbot reported a OOB read bug: BUG: KASAN: slab-out-of-bounds in indx_insert_into_buffer+0xaa3/0x13b0 fs/ntfs3/index.c:1755 Read of size 17168 at addr ffff8880255e06c0 by task syz-executor308/3630 Call Trace: memmove+0x25/0x60 mm/kasan/shadow.c:54 indx_insert_into_buffer+0xaa3/0x13b0 fs/ntfs3/index.c:1755 indx_insert_entry+0x446/0x6b0 fs/ntfs3/index.c:1863 ntfs_create_inode+0x1d3f/0x35c0 fs/ntfs3/inode.c:1548 ntfs_create+0x3e/0x60 fs/ntfs3/namei.c:100 lookup_open fs/namei.c:3413 [inline] If the member struct INDEX_BUFFER *index of struct indx_node is incorrect, that is, the value of __le32 used is greater than the value of __le32 total in struct INDEX_HDR. Therefore, OOB read occurs when memmove is called in indx_insert_into_buffer(). Fix this by adding a check in hdr_find_e(). Fixes: 82cae269cfa9 ("fs/ntfs3: Add initialization of super block") Reported-by: syzbot+d882d57193079e379309@syzkaller.appspotmail.com Signed-off-by: ZhangPeng Signed-off-by: Konstantin Komarov --- fs/ntfs3/index.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c index 51ab75954640..ae9616becec1 100644 --- a/fs/ntfs3/index.c +++ b/fs/ntfs3/index.c @@ -725,9 +725,13 @@ static struct NTFS_DE *hdr_find_e(const struct ntfs_index *indx, u32 e_size, e_key_len; u32 end = le32_to_cpu(hdr->used); u32 off = le32_to_cpu(hdr->de_off); + u32 total = le32_to_cpu(hdr->total); u16 offs[128]; fill_table: + if (end > total) + return NULL; + if (off + sizeof(struct NTFS_DE) > end) return NULL; -- cgit v1.2.3 From 4f082a7531223a438c757bb20e304f4c941c67a8 Mon Sep 17 00:00:00 2001 From: Edward Lo Date: Thu, 27 Oct 2022 23:33:37 +0800 Subject: fs/ntfs3: Enhance the attribute size check This combines the overflow and boundary check so that all attribute size will be properly examined while enumerating them. [ 169.181521] BUG: KASAN: slab-out-of-bounds in run_unpack+0x2e3/0x570 [ 169.183161] Read of size 1 at addr ffff8880094b6240 by task mount/247 [ 169.184046] [ 169.184925] CPU: 0 PID: 247 Comm: mount Not tainted 6.0.0-rc7+ #3 [ 169.185908] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014 [ 169.187066] Call Trace: [ 169.187492] [ 169.188049] dump_stack_lvl+0x49/0x63 [ 169.188495] print_report.cold+0xf5/0x689 [ 169.188964] ? run_unpack+0x2e3/0x570 [ 169.189331] kasan_report+0xa7/0x130 [ 169.189714] ? run_unpack+0x2e3/0x570 [ 169.190079] __asan_load1+0x51/0x60 [ 169.190634] run_unpack+0x2e3/0x570 [ 169.191290] ? run_pack+0x840/0x840 [ 169.191569] ? run_lookup_entry+0xb3/0x1f0 [ 169.192443] ? mi_enum_attr+0x20a/0x230 [ 169.192886] run_unpack_ex+0xad/0x3e0 [ 169.193276] ? run_unpack+0x570/0x570 [ 169.193557] ? ni_load_mi+0x80/0x80 [ 169.193889] ? debug_smp_processor_id+0x17/0x20 [ 169.194236] ? mi_init+0x4a/0x70 [ 169.194496] attr_load_runs_vcn+0x166/0x1c0 [ 169.194851] ? attr_data_write_resident+0x250/0x250 [ 169.195188] mi_read+0x133/0x2c0 [ 169.195481] ntfs_iget5+0x277/0x1780 [ 169.196017] ? call_rcu+0x1c7/0x330 [ 169.196392] ? ntfs_get_block_bmap+0x70/0x70 [ 169.196708] ? evict+0x223/0x280 [ 169.197014] ? __kmalloc+0x33/0x540 [ 169.197305] ? wnd_init+0x15b/0x1b0 [ 169.197599] ntfs_fill_super+0x1026/0x1ba0 [ 169.197994] ? put_ntfs+0x1d0/0x1d0 [ 169.198299] ? vsprintf+0x20/0x20 [ 169.198583] ? mutex_unlock+0x81/0xd0 [ 169.198930] ? set_blocksize+0x95/0x150 [ 169.199269] get_tree_bdev+0x232/0x370 [ 169.199750] ? put_ntfs+0x1d0/0x1d0 [ 169.200094] ntfs_fs_get_tree+0x15/0x20 [ 169.200431] vfs_get_tree+0x4c/0x130 [ 169.200714] path_mount+0x654/0xfe0 [ 169.201067] ? putname+0x80/0xa0 [ 169.201358] ? finish_automount+0x2e0/0x2e0 [ 169.201965] ? putname+0x80/0xa0 [ 169.202445] ? kmem_cache_free+0x1c4/0x440 [ 169.203075] ? putname+0x80/0xa0 [ 169.203414] do_mount+0xd6/0xf0 [ 169.203719] ? path_mount+0xfe0/0xfe0 [ 169.203977] ? __kasan_check_write+0x14/0x20 [ 169.204382] __x64_sys_mount+0xca/0x110 [ 169.204711] do_syscall_64+0x3b/0x90 [ 169.205059] entry_SYSCALL_64_after_hwframe+0x63/0xcd [ 169.205571] RIP: 0033:0x7f67a80e948a [ 169.206327] Code: 48 8b 0d 11 fa 2a 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 49 89 ca b8 a5 00 00 008 [ 169.208296] RSP: 002b:00007ffddf020f58 EFLAGS: 00000202 ORIG_RAX: 00000000000000a5 [ 169.209253] RAX: ffffffffffffffda RBX: 000055e2547a6060 RCX: 00007f67a80e948a [ 169.209777] RDX: 000055e2547a6260 RSI: 000055e2547a62e0 RDI: 000055e2547aeaf0 [ 169.210342] RBP: 0000000000000000 R08: 000055e2547a6280 R09: 0000000000000020 [ 169.210843] R10: 00000000c0ed0000 R11: 0000000000000202 R12: 000055e2547aeaf0 [ 169.211307] R13: 000055e2547a6260 R14: 0000000000000000 R15: 00000000ffffffff [ 169.211913] [ 169.212304] [ 169.212680] Allocated by task 0: [ 169.212963] (stack is not available) [ 169.213200] [ 169.213472] The buggy address belongs to the object at ffff8880094b5e00 [ 169.213472] which belongs to the cache UDP of size 1152 [ 169.214095] The buggy address is located 1088 bytes inside of [ 169.214095] 1152-byte region [ffff8880094b5e00, ffff8880094b6280) [ 169.214639] [ 169.215004] The buggy address belongs to the physical page: [ 169.215766] page:000000002e324c8c refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x94b4 [ 169.218412] head:000000002e324c8c order:2 compound_mapcount:0 compound_pincount:0 [ 169.219078] flags: 0xfffffc0010200(slab|head|node=0|zone=1|lastcpupid=0x1fffff) [ 169.220272] raw: 000fffffc0010200 0000000000000000 dead000000000122 ffff888002409b40 [ 169.221006] raw: 0000000000000000 00000000800c000c 00000001ffffffff 0000000000000000 [ 169.222320] page dumped because: kasan: bad access detected [ 169.222922] [ 169.223119] Memory state around the buggy address: [ 169.224056] ffff8880094b6100: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 169.224908] ffff8880094b6180: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 169.225677] >ffff8880094b6200: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 169.226445] ^ [ 169.227055] ffff8880094b6280: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 169.227638] ffff8880094b6300: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb Signed-off-by: Edward Lo Signed-off-by: Konstantin Komarov --- fs/ntfs3/record.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/record.c b/fs/ntfs3/record.c index defce6a5c8e1..abfe004774c0 100644 --- a/fs/ntfs3/record.c +++ b/fs/ntfs3/record.c @@ -220,11 +220,6 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr) return NULL; } - if (off + asize < off) { - /* overflow check */ - return NULL; - } - attr = Add2Ptr(attr, asize); off += asize; } @@ -247,8 +242,8 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr) if ((t32 & 0xf) || (t32 > 0x100)) return NULL; - /* Check boundary. */ - if (off + asize > used) + /* Check overflow and boundary. */ + if (off + asize < off || off + asize > used) return NULL; /* Check size of attribute. */ -- cgit v1.2.3 From 8dae4f6341e335a09575be60b4fdf697c732a470 Mon Sep 17 00:00:00 2001 From: Abdun Nihaal Date: Sun, 30 Oct 2022 12:32:51 +0530 Subject: fs/ntfs3: Fix NULL dereference in ni_write_inode Syzbot reports a NULL dereference in ni_write_inode. When creating a new inode, if allocation fails in mi_init function (called in mi_format_new function), mi->mrec is set to NULL. In the error path of this inode creation, mi->mrec is later dereferenced in ni_write_inode. Add a NULL check to prevent NULL dereference. Link: https://syzkaller.appspot.com/bug?extid=f45957555ed4a808cc7a Reported-and-tested-by: syzbot+f45957555ed4a808cc7a@syzkaller.appspotmail.com Signed-off-by: Abdun Nihaal Signed-off-by: Konstantin Komarov --- fs/ntfs3/frecord.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index f1df52dfab74..912eeb3d3471 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -3258,6 +3258,9 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint) return 0; } + if (!ni->mi.mrec) + goto out; + if (is_rec_inuse(ni->mi.mrec) && !(sbi->flags & NTFS_FLAGS_LOG_REPLAYING) && inode->i_nlink) { bool modified = false; -- cgit v1.2.3 From 98bea253aa28ad8be2ce565a9ca21beb4a9419e5 Mon Sep 17 00:00:00 2001 From: Edward Lo Date: Sat, 5 Nov 2022 23:39:44 +0800 Subject: fs/ntfs3: Validate MFT flags before replaying logs Log load and replay is part of the metadata handle flow during mount operation. The $MFT record will be loaded and used while replaying logs. However, a malformed $MFT record, say, has RECORD_FLAG_DIR flag set and contains an ATTR_ROOT attribute will misguide kernel to treat it as a directory, and try to free the allocated resources when the corresponding inode is freed, which will cause an invalid kfree because the memory hasn't actually been allocated. [ 101.368647] BUG: KASAN: invalid-free in kvfree+0x2c/0x40 [ 101.369457] [ 101.369986] CPU: 0 PID: 198 Comm: mount Not tainted 6.0.0-rc7+ #5 [ 101.370529] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014 [ 101.371362] Call Trace: [ 101.371795] [ 101.372157] dump_stack_lvl+0x49/0x63 [ 101.372658] print_report.cold+0xf5/0x689 [ 101.373022] ? ni_write_inode+0x754/0xd90 [ 101.373378] ? kvfree+0x2c/0x40 [ 101.373698] kasan_report_invalid_free+0x77/0xf0 [ 101.374058] ? kvfree+0x2c/0x40 [ 101.374352] ? kvfree+0x2c/0x40 [ 101.374668] __kasan_slab_free+0x189/0x1b0 [ 101.374992] ? kvfree+0x2c/0x40 [ 101.375271] kfree+0x168/0x3b0 [ 101.375717] kvfree+0x2c/0x40 [ 101.376002] indx_clear+0x26/0x60 [ 101.376316] ni_clear+0xc5/0x290 [ 101.376661] ntfs_evict_inode+0x45/0x70 [ 101.377001] evict+0x199/0x280 [ 101.377432] iput.part.0+0x286/0x320 [ 101.377819] iput+0x32/0x50 [ 101.378166] ntfs_loadlog_and_replay+0x143/0x320 [ 101.378656] ? ntfs_bio_fill_1+0x510/0x510 [ 101.378968] ? iput.part.0+0x286/0x320 [ 101.379367] ntfs_fill_super+0xecb/0x1ba0 [ 101.379729] ? put_ntfs+0x1d0/0x1d0 [ 101.380046] ? vsprintf+0x20/0x20 [ 101.380542] ? mutex_unlock+0x81/0xd0 [ 101.380914] ? set_blocksize+0x95/0x150 [ 101.381597] get_tree_bdev+0x232/0x370 [ 101.382254] ? put_ntfs+0x1d0/0x1d0 [ 101.382699] ntfs_fs_get_tree+0x15/0x20 [ 101.383094] vfs_get_tree+0x4c/0x130 [ 101.383675] path_mount+0x654/0xfe0 [ 101.384203] ? putname+0x80/0xa0 [ 101.384540] ? finish_automount+0x2e0/0x2e0 [ 101.384943] ? putname+0x80/0xa0 [ 101.385362] ? kmem_cache_free+0x1c4/0x440 [ 101.385968] ? putname+0x80/0xa0 [ 101.386666] do_mount+0xd6/0xf0 [ 101.387228] ? path_mount+0xfe0/0xfe0 [ 101.387585] ? __kasan_check_write+0x14/0x20 [ 101.387979] __x64_sys_mount+0xca/0x110 [ 101.388436] do_syscall_64+0x3b/0x90 [ 101.388757] entry_SYSCALL_64_after_hwframe+0x63/0xcd [ 101.389289] RIP: 0033:0x7fa0f70e948a [ 101.390048] Code: 48 8b 0d 11 fa 2a 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 49 89 ca b8 a5 00 00 008 [ 101.391297] RSP: 002b:00007ffc24fdecc8 EFLAGS: 00000202 ORIG_RAX: 00000000000000a5 [ 101.391988] RAX: ffffffffffffffda RBX: 000055932c183060 RCX: 00007fa0f70e948a [ 101.392494] RDX: 000055932c183260 RSI: 000055932c1832e0 RDI: 000055932c18bce0 [ 101.393053] RBP: 0000000000000000 R08: 000055932c183280 R09: 0000000000000020 [ 101.393577] R10: 00000000c0ed0000 R11: 0000000000000202 R12: 000055932c18bce0 [ 101.394044] R13: 000055932c183260 R14: 0000000000000000 R15: 00000000ffffffff [ 101.394747] [ 101.395402] [ 101.396047] Allocated by task 198: [ 101.396724] kasan_save_stack+0x26/0x50 [ 101.397400] __kasan_slab_alloc+0x6d/0x90 [ 101.397974] kmem_cache_alloc_lru+0x192/0x5a0 [ 101.398524] ntfs_alloc_inode+0x23/0x70 [ 101.399137] alloc_inode+0x3b/0xf0 [ 101.399534] iget5_locked+0x54/0xa0 [ 101.400026] ntfs_iget5+0xaf/0x1780 [ 101.400414] ntfs_loadlog_and_replay+0xe5/0x320 [ 101.400883] ntfs_fill_super+0xecb/0x1ba0 [ 101.401313] get_tree_bdev+0x232/0x370 [ 101.401774] ntfs_fs_get_tree+0x15/0x20 [ 101.402224] vfs_get_tree+0x4c/0x130 [ 101.402673] path_mount+0x654/0xfe0 [ 101.403160] do_mount+0xd6/0xf0 [ 101.403537] __x64_sys_mount+0xca/0x110 [ 101.404058] do_syscall_64+0x3b/0x90 [ 101.404333] entry_SYSCALL_64_after_hwframe+0x63/0xcd [ 101.404816] [ 101.405067] The buggy address belongs to the object at ffff888008cc9ea0 [ 101.405067] which belongs to the cache ntfs_inode_cache of size 992 [ 101.406171] The buggy address is located 232 bytes inside of [ 101.406171] 992-byte region [ffff888008cc9ea0, ffff888008cca280) [ 101.406995] [ 101.408559] The buggy address belongs to the physical page: [ 101.409320] page:00000000dccf19dd refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x8cc8 [ 101.410654] head:00000000dccf19dd order:2 compound_mapcount:0 compound_pincount:0 [ 101.411533] flags: 0xfffffc0010200(slab|head|node=0|zone=1|lastcpupid=0x1fffff) [ 101.412665] raw: 000fffffc0010200 0000000000000000 dead000000000122 ffff888003695140 [ 101.413209] raw: 0000000000000000 00000000800e000e 00000001ffffffff 0000000000000000 [ 101.413799] page dumped because: kasan: bad access detected [ 101.414213] [ 101.414427] Memory state around the buggy address: [ 101.414991] ffff888008cc9e80: fc fc fc fc 00 00 00 00 00 00 00 00 00 00 00 00 [ 101.415785] ffff888008cc9f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 101.416933] >ffff888008cc9f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 101.417857] ^ [ 101.418566] ffff888008cca000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 101.419704] ffff888008cca080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Signed-off-by: Edward Lo Signed-off-by: Konstantin Komarov --- fs/ntfs3/inode.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index ce6bb3bd86b6..059f28878458 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -100,6 +100,12 @@ static struct inode *ntfs_read_mft(struct inode *inode, /* Record should contain $I30 root. */ is_dir = rec->flags & RECORD_FLAG_DIR; + /* MFT_REC_MFT is not a dir */ + if (is_dir && ino == MFT_REC_MFT) { + err = -EINVAL; + goto out; + } + inode->i_generation = le16_to_cpu(rec->seq); /* Enumerate all struct Attributes MFT. */ -- cgit v1.2.3 From ab84eee4c7ab929996602eda7832854c35a6dda2 Mon Sep 17 00:00:00 2001 From: Zeng Heng Date: Mon, 12 Dec 2022 09:31:34 +0800 Subject: fs/ntfs3: Fix slab-out-of-bounds read in hdr_delete_de() Here is a BUG report from syzbot: BUG: KASAN: slab-out-of-bounds in hdr_delete_de+0xe0/0x150 fs/ntfs3/index.c:806 Read of size 16842960 at addr ffff888079cc0600 by task syz-executor934/3631 Call Trace: memmove+0x25/0x60 mm/kasan/shadow.c:54 hdr_delete_de+0xe0/0x150 fs/ntfs3/index.c:806 indx_delete_entry+0x74f/0x3670 fs/ntfs3/index.c:2193 ni_remove_name+0x27a/0x980 fs/ntfs3/frecord.c:2910 ntfs_unlink_inode+0x3d4/0x720 fs/ntfs3/inode.c:1712 ntfs_rename+0x41a/0xcb0 fs/ntfs3/namei.c:276 Before using the meta-data in struct INDEX_HDR, we need to check index header valid or not. Otherwise, the corruptedi (or malicious) fs image can cause out-of-bounds access which could make kernel panic. Fixes: 82cae269cfa9 ("fs/ntfs3: Add initialization of super block") Reported-by: syzbot+9c2811fd56591639ff5f@syzkaller.appspotmail.com Signed-off-by: Zeng Heng Signed-off-by: Konstantin Komarov --- fs/ntfs3/fslog.c | 2 +- fs/ntfs3/index.c | 4 ++++ fs/ntfs3/ntfs_fs.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c index dc723f03d6bb..bf7396447284 100644 --- a/fs/ntfs3/fslog.c +++ b/fs/ntfs3/fslog.c @@ -2575,7 +2575,7 @@ static int read_next_log_rec(struct ntfs_log *log, struct lcb *lcb, u64 *lsn) return find_log_rec(log, *lsn, lcb); } -static inline bool check_index_header(const struct INDEX_HDR *hdr, size_t bytes) +bool check_index_header(const struct INDEX_HDR *hdr, size_t bytes) { __le16 mask; u32 min_de, de_off, used, total; diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c index ae9616becec1..7a1e01a2ed9a 100644 --- a/fs/ntfs3/index.c +++ b/fs/ntfs3/index.c @@ -848,6 +848,10 @@ static inline struct NTFS_DE *hdr_delete_de(struct INDEX_HDR *hdr, u32 off = PtrOffset(hdr, re); int bytes = used - (off + esize); + /* check INDEX_HDR valid before using INDEX_HDR */ + if (!check_index_header(hdr, le32_to_cpu(hdr->total))) + return NULL; + if (off >= used || esize < sizeof(struct NTFS_DE) || bytes < sizeof(struct NTFS_DE)) return NULL; diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 80072e5f96f7..15296f5690b5 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -581,6 +581,7 @@ int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni, bool ni_is_dirty(struct inode *inode); /* Globals from fslog.c */ +bool check_index_header(const struct INDEX_HDR *hdr, size_t bytes); int log_replay(struct ntfs_inode *ni, bool *initialized); /* Globals from fsntfs.c */ -- cgit v1.2.3 From 08e8cf5f2d9ec383a2e339a2711b62a54ff3fba0 Mon Sep 17 00:00:00 2001 From: Edward Lo Date: Tue, 4 Oct 2022 23:15:06 +0800 Subject: fs/ntfs3: Add length check in indx_get_root This adds a length check to guarantee the retrieved index root is legit. [ 162.459513] BUG: KASAN: use-after-free in hdr_find_e.isra.0+0x10c/0x320 [ 162.460176] Read of size 2 at addr ffff8880037bca99 by task mount/243 [ 162.460851] [ 162.461252] CPU: 0 PID: 243 Comm: mount Not tainted 6.0.0-rc7 #42 [ 162.461744] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014 [ 162.462609] Call Trace: [ 162.462954] [ 162.463276] dump_stack_lvl+0x49/0x63 [ 162.463822] print_report.cold+0xf5/0x689 [ 162.464608] ? unwind_get_return_address+0x3a/0x60 [ 162.465766] ? hdr_find_e.isra.0+0x10c/0x320 [ 162.466975] kasan_report+0xa7/0x130 [ 162.467506] ? _raw_spin_lock_irq+0xc0/0xf0 [ 162.467998] ? hdr_find_e.isra.0+0x10c/0x320 [ 162.468536] __asan_load2+0x68/0x90 [ 162.468923] hdr_find_e.isra.0+0x10c/0x320 [ 162.469282] ? cmp_uints+0xe0/0xe0 [ 162.469557] ? cmp_sdh+0x90/0x90 [ 162.469864] ? ni_find_attr+0x214/0x300 [ 162.470217] ? ni_load_mi+0x80/0x80 [ 162.470479] ? entry_SYSCALL_64_after_hwframe+0x63/0xcd [ 162.470931] ? ntfs_bread_run+0x190/0x190 [ 162.471307] ? indx_get_root+0xe4/0x190 [ 162.471556] ? indx_get_root+0x140/0x190 [ 162.471833] ? indx_init+0x1e0/0x1e0 [ 162.472069] ? fnd_clear+0x115/0x140 [ 162.472363] ? _raw_spin_lock_irqsave+0x100/0x100 [ 162.472731] indx_find+0x184/0x470 [ 162.473461] ? sysvec_apic_timer_interrupt+0x57/0xc0 [ 162.474429] ? indx_find_buffer+0x2d0/0x2d0 [ 162.474704] ? do_syscall_64+0x3b/0x90 [ 162.474962] dir_search_u+0x196/0x2f0 [ 162.475381] ? ntfs_nls_to_utf16+0x450/0x450 [ 162.475661] ? ntfs_security_init+0x3d6/0x440 [ 162.475906] ? is_sd_valid+0x180/0x180 [ 162.476191] ntfs_extend_init+0x13f/0x2c0 [ 162.476496] ? ntfs_fix_post_read+0x130/0x130 [ 162.476861] ? iput.part.0+0x286/0x320 [ 162.477325] ntfs_fill_super+0x11e0/0x1b50 [ 162.477709] ? put_ntfs+0x1d0/0x1d0 [ 162.477970] ? vsprintf+0x20/0x20 [ 162.478258] ? set_blocksize+0x95/0x150 [ 162.478538] get_tree_bdev+0x232/0x370 [ 162.478789] ? put_ntfs+0x1d0/0x1d0 [ 162.479038] ntfs_fs_get_tree+0x15/0x20 [ 162.479374] vfs_get_tree+0x4c/0x130 [ 162.479729] path_mount+0x654/0xfe0 [ 162.480124] ? putname+0x80/0xa0 [ 162.480484] ? finish_automount+0x2e0/0x2e0 [ 162.480894] ? putname+0x80/0xa0 [ 162.481467] ? kmem_cache_free+0x1c4/0x440 [ 162.482280] ? putname+0x80/0xa0 [ 162.482714] do_mount+0xd6/0xf0 [ 162.483264] ? path_mount+0xfe0/0xfe0 [ 162.484782] ? __kasan_check_write+0x14/0x20 [ 162.485593] __x64_sys_mount+0xca/0x110 [ 162.486024] do_syscall_64+0x3b/0x90 [ 162.486543] entry_SYSCALL_64_after_hwframe+0x63/0xcd [ 162.487141] RIP: 0033:0x7f9d374e948a [ 162.488324] Code: 48 8b 0d 11 fa 2a 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 49 89 ca b8 a5 00 00 008 [ 162.489728] RSP: 002b:00007ffe30e73d18 EFLAGS: 00000206 ORIG_RAX: 00000000000000a5 [ 162.490971] RAX: ffffffffffffffda RBX: 0000561cdb43a060 RCX: 00007f9d374e948a [ 162.491669] RDX: 0000561cdb43a260 RSI: 0000561cdb43a2e0 RDI: 0000561cdb442af0 [ 162.492050] RBP: 0000000000000000 R08: 0000561cdb43a280 R09: 0000000000000020 [ 162.492459] R10: 00000000c0ed0000 R11: 0000000000000206 R12: 0000561cdb442af0 [ 162.493183] R13: 0000561cdb43a260 R14: 0000000000000000 R15: 00000000ffffffff [ 162.493644] [ 162.493908] [ 162.494214] The buggy address belongs to the physical page: [ 162.494761] page:000000003e38a3d5 refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x37bc [ 162.496064] flags: 0xfffffc0000000(node=0|zone=1|lastcpupid=0x1fffff) [ 162.497278] raw: 000fffffc0000000 ffffea00000df1c8 ffffea00000df008 0000000000000000 [ 162.498928] raw: 0000000000000000 0000000000240000 00000000ffffffff 0000000000000000 [ 162.500542] page dumped because: kasan: bad access detected [ 162.501057] [ 162.501242] Memory state around the buggy address: [ 162.502230] ffff8880037bc980: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff [ 162.502977] ffff8880037bca00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff [ 162.503522] >ffff8880037bca80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff [ 162.503963] ^ [ 162.504370] ffff8880037bcb00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff [ 162.504766] ffff8880037bcb80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff Signed-off-by: Edward Lo Signed-off-by: Konstantin Komarov --- fs/ntfs3/index.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c index 7a1e01a2ed9a..f716487ec8a0 100644 --- a/fs/ntfs3/index.c +++ b/fs/ntfs3/index.c @@ -994,6 +994,7 @@ struct INDEX_ROOT *indx_get_root(struct ntfs_index *indx, struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le = NULL; struct ATTRIB *a; const struct INDEX_NAMES *in = &s_index_names[indx->type]; + struct INDEX_ROOT *root = NULL; a = ni_find_attr(ni, NULL, &le, ATTR_ROOT, in->name, in->name_len, NULL, mi); @@ -1003,7 +1004,15 @@ struct INDEX_ROOT *indx_get_root(struct ntfs_index *indx, struct ntfs_inode *ni, if (attr) *attr = a; - return resident_data_ex(a, sizeof(struct INDEX_ROOT)); + root = resident_data_ex(a, sizeof(struct INDEX_ROOT)); + + /* length check */ + if (root && offsetof(struct INDEX_ROOT, ihdr) + le32_to_cpu(root->ihdr.used) > + le32_to_cpu(a->res.data_size)) { + return NULL; + } + + return root; } static int indx_write(struct ntfs_index *indx, struct ntfs_inode *ni, -- cgit v1.2.3 From e479f0a62a2a4358f25d0d0b60c333e6d881d7c6 Mon Sep 17 00:00:00 2001 From: Yu Zhe Date: Thu, 10 Nov 2022 15:46:40 +0800 Subject: fs/ntfs3: fix spelling mistake "attibute" -> "attribute" There is a spelling mistake in comment. Fix it. Signed-off-by: Yu Zhe Signed-off-by: Konstantin Komarov --- fs/ntfs3/xattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index f8043838eb92..4746959af964 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -410,7 +410,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name, /* * 1. Check ea_info.size_pack for overflow. - * 2. New attibute size must fit value from $AttrDef + * 2. New attribute size must fit value from $AttrDef */ if (new_pack > 0xffff || size > sbi->ea_max_size) { ntfs_inode_warn( -- cgit v1.2.3 From fc4992458e0aa2d2e82a25c922e6ac36c2d91083 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Thu, 29 Dec 2022 15:44:43 +0400 Subject: fs/ntfs3: Add null pointer checks Added null pointer checks in function ntfs_security_init. Also added le32_to_cpu in functions ntfs_security_init and indx_read. Signed-off-by: Konstantin Komarov --- fs/ntfs3/fsntfs.c | 16 ++++++++++------ fs/ntfs3/index.c | 3 ++- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c index 8de861ddec60..1f36e89dcff7 100644 --- a/fs/ntfs3/fsntfs.c +++ b/fs/ntfs3/fsntfs.c @@ -1876,10 +1876,12 @@ int ntfs_security_init(struct ntfs_sb_info *sbi) goto out; } - root_sdh = resident_data_ex(attr, sizeof(struct INDEX_ROOT)); - if (root_sdh->type != ATTR_ZERO || + if(!(root_sdh = resident_data_ex(attr, sizeof(struct INDEX_ROOT))) || + root_sdh->type != ATTR_ZERO || root_sdh->rule != NTFS_COLLATION_TYPE_SECURITY_HASH || - offsetof(struct INDEX_ROOT, ihdr) + root_sdh->ihdr.used > attr->res.data_size) { + offsetof(struct INDEX_ROOT, ihdr) + + le32_to_cpu(root_sdh->ihdr.used) > + le32_to_cpu(attr->res.data_size)) { err = -EINVAL; goto out; } @@ -1895,10 +1897,12 @@ int ntfs_security_init(struct ntfs_sb_info *sbi) goto out; } - root_sii = resident_data_ex(attr, sizeof(struct INDEX_ROOT)); - if (root_sii->type != ATTR_ZERO || + if(!(root_sii = resident_data_ex(attr, sizeof(struct INDEX_ROOT))) || + root_sii->type != ATTR_ZERO || root_sii->rule != NTFS_COLLATION_TYPE_UINT || - offsetof(struct INDEX_ROOT, ihdr) + root_sii->ihdr.used > attr->res.data_size) { + offsetof(struct INDEX_ROOT, ihdr) + + le32_to_cpu(root_sii->ihdr.used) > + le32_to_cpu(attr->res.data_size)) { err = -EINVAL; goto out; } diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c index f716487ec8a0..8718df791a55 100644 --- a/fs/ntfs3/index.c +++ b/fs/ntfs3/index.c @@ -1102,7 +1102,8 @@ ok: } /* check for index header length */ - if (offsetof(struct INDEX_BUFFER, ihdr) + ib->ihdr.used > bytes) { + if (offsetof(struct INDEX_BUFFER, ihdr) + le32_to_cpu(ib->ihdr.used) > + bytes) { err = -EINVAL; goto out; } -- cgit v1.2.3 From 0addfb1c2281b5ca2ac02e7dbf6f5a7dbfbc71b9 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Thu, 29 Dec 2022 15:50:41 +0400 Subject: fs/ntfs3: Improved checking of attribute's name length Added comment, added null pointer checking. Signed-off-by: Konstantin Komarov --- fs/ntfs3/inode.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index 059f28878458..3d2e4c1270e4 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -137,7 +137,13 @@ next_attr: rsize = attr->non_res ? 0 : le32_to_cpu(attr->res.data_size); asize = le32_to_cpu(attr->size); - if (le16_to_cpu(attr->name_off) + attr->name_len > asize) + /* + * Really this check was done in 'ni_enum_attr_ex' -> ... 'mi_enum_attr'. + * There not critical to check this case again + */ + if (attr->name_len && + sizeof(short) * attr->name_len + le16_to_cpu(attr->name_off) > + asize) goto out; if (attr->non_res) { -- cgit v1.2.3 From 318d016e423054c143e5e58644ac93ef553013b9 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Thu, 29 Dec 2022 15:58:56 +0400 Subject: fs/ntfs3: Check for extremely large size of $AttrDef Added additional checking for size of $AttrDef. Added comment. Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index ef4ea3f21905..0967035146ce 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -1185,10 +1185,18 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) goto out; } - if (inode->i_size < sizeof(struct ATTR_DEF_ENTRY)) { + /* + * Typical $AttrDef contains up to 20 entries. + * Check for extremely large size. + */ + if (inode->i_size < sizeof(struct ATTR_DEF_ENTRY) || + inode->i_size > 100 * sizeof(struct ATTR_DEF_ENTRY)) { + ntfs_err(sb, "Looks like $AttrDef is corrupted (size=%llu).", + inode->i_size); err = -EINVAL; goto put_inode_out; } + bytes = inode->i_size; sbi->def_table = t = kmalloc(bytes, GFP_NOFS | __GFP_NOWARN); if (!t) { -- cgit v1.2.3 From 30200ef8d1368f0dee424d5926bd7af0cdc87b54 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Fri, 30 Dec 2022 14:09:44 +0400 Subject: fs/ntfs3: Restore overflow checking for attr size in mi_enum_attr Fixed comment. Removed explicit initialization for INDEX_ROOT. Signed-off-by: Konstantin Komarov --- fs/ntfs3/index.c | 7 ++++--- fs/ntfs3/record.c | 5 +++++ fs/ntfs3/super.c | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c index 8718df791a55..9fefeac5fe7e 100644 --- a/fs/ntfs3/index.c +++ b/fs/ntfs3/index.c @@ -994,7 +994,7 @@ struct INDEX_ROOT *indx_get_root(struct ntfs_index *indx, struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le = NULL; struct ATTRIB *a; const struct INDEX_NAMES *in = &s_index_names[indx->type]; - struct INDEX_ROOT *root = NULL; + struct INDEX_ROOT *root; a = ni_find_attr(ni, NULL, &le, ATTR_ROOT, in->name, in->name_len, NULL, mi); @@ -1007,8 +1007,9 @@ struct INDEX_ROOT *indx_get_root(struct ntfs_index *indx, struct ntfs_inode *ni, root = resident_data_ex(a, sizeof(struct INDEX_ROOT)); /* length check */ - if (root && offsetof(struct INDEX_ROOT, ihdr) + le32_to_cpu(root->ihdr.used) > - le32_to_cpu(a->res.data_size)) { + if (root && + offsetof(struct INDEX_ROOT, ihdr) + le32_to_cpu(root->ihdr.used) > + le32_to_cpu(a->res.data_size)) { return NULL; } diff --git a/fs/ntfs3/record.c b/fs/ntfs3/record.c index abfe004774c0..0603169ee8a0 100644 --- a/fs/ntfs3/record.c +++ b/fs/ntfs3/record.c @@ -220,6 +220,11 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr) return NULL; } + if (off + asize < off) { + /* Overflow check. */ + return NULL; + } + attr = Add2Ptr(attr, asize); off += asize; } diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 0967035146ce..19d0889b131f 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -1187,7 +1187,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) /* * Typical $AttrDef contains up to 20 entries. - * Check for extremely large size. + * Check for extremely large/small size. */ if (inode->i_size < sizeof(struct ATTR_DEF_ENTRY) || inode->i_size > 100 * sizeof(struct ATTR_DEF_ENTRY)) { -- cgit v1.2.3 From 6827d50b2c430c329af442b64c9176d174f56521 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Fri, 30 Dec 2022 14:58:25 +0400 Subject: fs/ntfs3: Refactoring of various minor issues Removed unused macro. Changed null pointer checking. Fixed inconsistent indenting. Signed-off-by: Konstantin Komarov --- fs/ntfs3/bitmap.c | 3 ++- fs/ntfs3/frecord.c | 2 +- fs/ntfs3/fsntfs.c | 6 ++++-- fs/ntfs3/namei.c | 2 +- fs/ntfs3/ntfs.h | 3 --- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/bitmap.c b/fs/ntfs3/bitmap.c index 723fb64e6531..393c726ef17a 100644 --- a/fs/ntfs3/bitmap.c +++ b/fs/ntfs3/bitmap.c @@ -658,7 +658,8 @@ int wnd_init(struct wnd_bitmap *wnd, struct super_block *sb, size_t nbits) if (!wnd->bits_last) wnd->bits_last = wbits; - wnd->free_bits = kcalloc(wnd->nwnd, sizeof(u16), GFP_NOFS | __GFP_NOWARN); + wnd->free_bits = + kcalloc(wnd->nwnd, sizeof(u16), GFP_NOFS | __GFP_NOWARN); if (!wnd->free_bits) return -ENOMEM; diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index 912eeb3d3471..1103d4d9a497 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -1645,7 +1645,7 @@ struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni, { struct ATTRIB *attr = NULL; struct ATTR_FILE_NAME *fname; - struct le_str *fns; + struct le_str *fns; if (le) *le = NULL; diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c index 1f36e89dcff7..342938704cfd 100644 --- a/fs/ntfs3/fsntfs.c +++ b/fs/ntfs3/fsntfs.c @@ -2599,8 +2599,10 @@ static inline bool is_reserved_name(struct ntfs_sb_info *sbi, if (len == 4 || (len > 4 && le16_to_cpu(name[4]) == '.')) { port_digit = le16_to_cpu(name[3]); if (port_digit >= '1' && port_digit <= '9') - if (!ntfs_cmp_names(name, 3, COM_NAME, 3, upcase, false) || - !ntfs_cmp_names(name, 3, LPT_NAME, 3, upcase, false)) + if (!ntfs_cmp_names(name, 3, COM_NAME, 3, upcase, + false) || + !ntfs_cmp_names(name, 3, LPT_NAME, 3, upcase, + false)) return true; } diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c index 8d206770d8c6..92bbc8ee83ca 100644 --- a/fs/ntfs3/namei.c +++ b/fs/ntfs3/namei.c @@ -93,7 +93,7 @@ static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *dentry, * If the MFT record of ntfs inode is not a base record, inode->i_op can be NULL. * This causes null pointer dereference in d_splice_alias(). */ - if (!IS_ERR(inode) && inode->i_op == NULL) { + if (!IS_ERR_OR_NULL(inode) && !inode->i_op) { iput(inode); inode = ERR_PTR(-EINVAL); } diff --git a/fs/ntfs3/ntfs.h b/fs/ntfs3/ntfs.h index 86ea1826d099..90151e56c122 100644 --- a/fs/ntfs3/ntfs.h +++ b/fs/ntfs3/ntfs.h @@ -435,9 +435,6 @@ static inline u64 attr_svcn(const struct ATTRIB *attr) return attr->non_res ? le64_to_cpu(attr->nres.svcn) : 0; } -/* The size of resident attribute by its resident size. */ -#define BYTES_PER_RESIDENT(b) (0x18 + (b)) - static_assert(sizeof(struct ATTRIB) == 0x48); static_assert(sizeof(((struct ATTRIB *)NULL)->res) == 0x08); static_assert(sizeof(((struct ATTRIB *)NULL)->nres) == 0x38); -- cgit v1.2.3 From ec275bf9693d19cc0fdce8436f4c425ced86f6e7 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Wed, 11 Jan 2023 16:59:43 +0800 Subject: fs/ntfs3: Fix a possible null-pointer dereference in ni_clear() In a previous commit c1006bd13146, ni->mi.mrec in ni_write_inode() could be NULL, and thus a NULL check is added for this variable. However, in the same call stack, ni->mi.mrec can be also dereferenced in ni_clear(): ntfs_evict_inode(inode) ni_write_inode(inode, ...) ni = ntfs_i(inode); is_rec_inuse(ni->mi.mrec) -> Add a NULL check by previous commit ni_clear(ntfs_i(inode)) is_rec_inuse(ni->mi.mrec) -> No check Thus, a possible null-pointer dereference may exist in ni_clear(). To fix it, a NULL check is added in this function. Signed-off-by: Jia-Ju Bai Reported-by: TOTE Robot Signed-off-by: Konstantin Komarov --- fs/ntfs3/frecord.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index 1103d4d9a497..9e7dfee303e8 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -102,7 +102,7 @@ void ni_clear(struct ntfs_inode *ni) { struct rb_node *node; - if (!ni->vfs_inode.i_nlink && is_rec_inuse(ni->mi.mrec)) + if (!ni->vfs_inode.i_nlink && ni->mi.mrec && is_rec_inuse(ni->mi.mrec)) ni_delete_all(ni); al_destroy(ni); -- cgit v1.2.3 From c20bc9c6d8eb13ab1c3f8e5f8ad91466ae717d7f Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Mon, 16 Jan 2023 11:41:41 +0400 Subject: fs/ntfs3: Use bh_read to simplify code The duplicating code is replaced by a generic function bh_read() Signed-off-by: Konstantin Komarov --- fs/ntfs3/file.c | 10 ++-------- fs/ntfs3/inode.c | 1 + 2 files changed, 3 insertions(+), 8 deletions(-) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index e9bdc1ff08c9..b3b72673fa5e 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -223,16 +223,10 @@ static int ntfs_zero_range(struct inode *inode, u64 vbo, u64 vbo_to) set_buffer_uptodate(bh); if (!buffer_uptodate(bh)) { - lock_buffer(bh); - bh->b_end_io = end_buffer_read_sync; - get_bh(bh); - submit_bh(REQ_OP_READ, bh); - - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) { + err = bh_read(bh, 0); + if (err < 0) { unlock_page(page); put_page(page); - err = -EIO; goto out; } } diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index 3d2e4c1270e4..bb004e476563 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -648,6 +648,7 @@ static noinline int ntfs_get_block_vbo(struct inode *inode, u64 vbo, bh->b_size = block_size; off = vbo & (PAGE_SIZE - 1); set_bh_page(bh, page, off); + err = bh_read(bh, 0); if (err < 0) goto out; -- cgit v1.2.3 From 267a36ba30a7425ad59d20e7e7e33bbdcc9cfb0a Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Mon, 16 Jan 2023 12:52:10 +0400 Subject: fs/ntfs3: Remove noacsrules Currently, this option does not work properly. Its use leads to unstable results. If we figure out how to implement it without errors, we will add it later. Signed-off-by: Konstantin Komarov --- fs/ntfs3/file.c | 11 ----------- fs/ntfs3/inode.c | 1 - fs/ntfs3/namei.c | 1 - fs/ntfs3/ntfs_fs.h | 3 --- fs/ntfs3/super.c | 9 +-------- fs/ntfs3/xattr.c | 14 -------------- 6 files changed, 1 insertion(+), 38 deletions(-) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index b3b72673fa5e..e4b54d6bcda5 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -654,22 +654,12 @@ out: int ntfs3_setattr(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *attr) { - struct super_block *sb = dentry->d_sb; - struct ntfs_sb_info *sbi = sb->s_fs_info; struct inode *inode = d_inode(dentry); struct ntfs_inode *ni = ntfs_i(inode); u32 ia_valid = attr->ia_valid; umode_t mode = inode->i_mode; int err; - if (sbi->options->noacsrules) { - /* "No access rules" - Force any changes of time etc. */ - attr->ia_valid |= ATTR_FORCE; - /* and disable for editing some attributes. */ - attr->ia_valid &= ~(ATTR_UID | ATTR_GID | ATTR_MODE); - ia_valid = attr->ia_valid; - } - err = setattr_prepare(idmap, dentry, attr); if (err) goto out; @@ -1153,7 +1143,6 @@ const struct inode_operations ntfs_file_inode_operations = { .getattr = ntfs_getattr, .setattr = ntfs3_setattr, .listxattr = ntfs_listxattr, - .permission = ntfs_permission, .get_inode_acl = ntfs_get_acl, .set_acl = ntfs_set_acl, .fiemap = ntfs_fiemap, diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index bb004e476563..31f7e97fa43e 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -2070,7 +2070,6 @@ const struct inode_operations ntfs_link_inode_operations = { .get_link = ntfs_get_link, .setattr = ntfs3_setattr, .listxattr = ntfs_listxattr, - .permission = ntfs_permission, }; const struct address_space_operations ntfs_aops = { diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c index 92bbc8ee83ca..fdd11f2a1883 100644 --- a/fs/ntfs3/namei.c +++ b/fs/ntfs3/namei.c @@ -607,7 +607,6 @@ const struct inode_operations ntfs_dir_inode_operations = { .rmdir = ntfs_rmdir, .mknod = ntfs_mknod, .rename = ntfs_rename, - .permission = ntfs_permission, .get_inode_acl = ntfs_get_acl, .set_acl = ntfs_set_acl, .setattr = ntfs3_setattr, diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 15296f5690b5..85efb34d211c 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -100,7 +100,6 @@ struct ntfs_mount_options { unsigned hide_dot_files : 1; /* Set hidden flag on dot files. */ unsigned windows_names : 1; /* Disallow names forbidden by Windows. */ unsigned force : 1; /* RW mount dirty volume. */ - unsigned noacsrules : 1; /* Exclude acs rules. */ unsigned prealloc : 1; /* Preallocate space when file is growing. */ unsigned nocase : 1; /* case insensitive. */ }; @@ -870,8 +869,6 @@ int ntfs_init_acl(struct mnt_idmap *idmap, struct inode *inode, #endif int ntfs_acl_chmod(struct mnt_idmap *idmap, struct dentry *dentry); -int ntfs_permission(struct mnt_idmap *idmap, struct inode *inode, - int mask); ssize_t ntfs_listxattr(struct dentry *dentry, char *buffer, size_t size); extern const struct xattr_handler *ntfs_xattr_handlers[]; diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 19d0889b131f..10c019ef7da3 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -253,7 +253,6 @@ enum Opt { Opt_acl, Opt_iocharset, Opt_prealloc, - Opt_noacsrules, Opt_nocase, Opt_err, }; @@ -274,7 +273,6 @@ static const struct fs_parameter_spec ntfs_fs_parameters[] = { fsparam_flag_no("acl", Opt_acl), fsparam_flag_no("showmeta", Opt_showmeta), fsparam_flag_no("prealloc", Opt_prealloc), - fsparam_flag_no("acsrules", Opt_noacsrules), fsparam_flag_no("nocase", Opt_nocase), fsparam_string("iocharset", Opt_iocharset), {} @@ -387,9 +385,6 @@ static int ntfs_fs_parse_param(struct fs_context *fc, case Opt_prealloc: opts->prealloc = result.negated ? 0 : 1; break; - case Opt_noacsrules: - opts->noacsrules = result.negated ? 1 : 0; - break; case Opt_nocase: opts->nocase = result.negated ? 1 : 0; break; @@ -572,8 +567,6 @@ static int ntfs_show_options(struct seq_file *m, struct dentry *root) seq_puts(m, ",hide_dot_files"); if (opts->force) seq_puts(m, ",force"); - if (opts->noacsrules) - seq_puts(m, ",noacsrules"); if (opts->prealloc) seq_puts(m, ",prealloc"); if (sb->s_flags & SB_POSIXACL) @@ -791,7 +784,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, if (boot_sector_size != sector_size) { ntfs_warn( sb, - "Different NTFS' sector size (%u) and media sector size (%u)", + "Different NTFS sector size (%u) and media sector size (%u)", boot_sector_size, sector_size); dev_size += sector_size - 1; } diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index 4746959af964..4cab20d70c79 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -711,20 +711,6 @@ int ntfs_acl_chmod(struct mnt_idmap *idmap, struct dentry *dentry) return posix_acl_chmod(idmap, dentry, inode->i_mode); } -/* - * ntfs_permission - inode_operations::permission - */ -int ntfs_permission(struct mnt_idmap *idmap, struct inode *inode, - int mask) -{ - if (ntfs_sb(inode->i_sb)->options->noacsrules) { - /* "No access rules" mode - Allow all changes. */ - return 0; - } - - return generic_permission(idmap, inode, mask); -} - /* * ntfs_listxattr - inode_operations::listxattr */ -- cgit v1.2.3 From 1842fbc8d25e629e54080fe3c5928d4ce8ccf55a Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Mon, 16 Jan 2023 13:03:24 +0400 Subject: fs/ntfs3: Fix ntfs_create_inode() Previous variant creates an inode that requires update the parent directory (ea_packed_size). Operations in ntfs_create_inode have been rearranged so we insert new directory entry with correct ea_packed_size and new created inode does not require update it's parent directory. Signed-off-by: Konstantin Komarov --- fs/ntfs3/file.c | 2 +- fs/ntfs3/inode.c | 83 +++++++++++++++++++++++++++++------------------------- fs/ntfs3/ntfs_fs.h | 2 +- fs/ntfs3/xattr.c | 20 +++++++------ 4 files changed, 58 insertions(+), 49 deletions(-) (limited to 'fs/ntfs3') diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index e4b54d6bcda5..1e8d6a3c9fec 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -703,7 +703,7 @@ int ntfs3_setattr(struct mnt_idmap *idmap, struct dentry *dentry, } if (ia_valid & (ATTR_UID | ATTR_GID | ATTR_MODE)) - ntfs_save_wsl_perm(inode); + ntfs_save_wsl_perm(inode, NULL); mark_inode_dirty(inode); out: return err; diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index 31f7e97fa43e..a7ca8183b91d 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -1320,8 +1320,7 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, inode_init_owner(idmap, inode, dir, mode); mode = inode->i_mode; - inode->i_atime = inode->i_mtime = inode->i_ctime = ni->i_crtime = - current_time(inode); + ni->i_crtime = current_time(inode); rec = ni->mi.mrec; rec->hard_links = cpu_to_le16(1); @@ -1362,10 +1361,9 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, attr->res.data_size = cpu_to_le32(dsize); std5->cr_time = std5->m_time = std5->c_time = std5->a_time = - kernel2nt(&inode->i_atime); + kernel2nt(&ni->i_crtime); - ni->std_fa = fa; - std5->fa = fa; + std5->fa = ni->std_fa = fa; attr = Add2Ptr(attr, asize); @@ -1564,11 +1562,15 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, } asize = SIZEOF_NONRESIDENT + ALIGN(err, 8); + /* Write non resident data. */ + err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rp, + nsize, 0); + if (err) + goto out5; } else { attr->res.data_off = SIZEOF_RESIDENT_LE; attr->res.data_size = cpu_to_le32(nsize); memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), rp, nsize); - nsize = 0; } /* Size of symlink equals the length of input string. */ inode->i_size = size; @@ -1589,19 +1591,8 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, rec->used = cpu_to_le32(PtrOffset(rec, attr) + 8); rec->next_attr_id = cpu_to_le16(aid); - /* Step 2: Add new name in index. */ - err = indx_insert_entry(&dir_ni->dir, dir_ni, new_de, sbi, fnd, 0); - if (err) - goto out6; - - /* Unlock parent directory before ntfs_init_acl. */ - if (!fnd) - ni_unlock(dir_ni); - inode->i_generation = le16_to_cpu(rec->seq); - dir->i_mtime = dir->i_ctime = inode->i_atime; - if (S_ISDIR(mode)) { inode->i_op = &ntfs_dir_inode_operations; inode->i_fop = &ntfs_dir_operations; @@ -1626,41 +1617,58 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, if (!S_ISLNK(mode) && (sb->s_flags & SB_POSIXACL)) { err = ntfs_init_acl(idmap, inode, dir); if (err) - goto out7; + goto out5; } else #endif { inode->i_flags |= S_NOSEC; } - /* Write non resident data. */ - if (nsize) { - err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rp, nsize, 0); - if (err) - goto out7; + /* + * ntfs_init_acl and ntfs_save_wsl_perm update extended attribute. + * The packed size of extended attribute is stored in direntry too. + * 'fname' here points to inside new_de. + */ + ntfs_save_wsl_perm(inode, &fname->dup.ea_size); + + /* + * update ea_size in file_name attribute too. + * Use ni_find_attr cause layout of MFT record may be changed + * in ntfs_init_acl and ntfs_save_wsl_perm. + */ + attr = ni_find_attr(ni, NULL, NULL, ATTR_NAME, NULL, 0, NULL, NULL); + if (attr) { + struct ATTR_FILE_NAME *fn; + + fn = resident_data_ex(attr, SIZEOF_ATTRIBUTE_FILENAME); + if (fn) + fn->dup.ea_size = fname->dup.ea_size; } + /* We do not need to update parent directory later */ + ni->ni_flags &= ~NI_FLAG_UPDATE_PARENT; + + /* Step 2: Add new name in index. */ + err = indx_insert_entry(&dir_ni->dir, dir_ni, new_de, sbi, fnd, 0); + if (err) + goto out6; + /* * Call 'd_instantiate' after inode->i_op is set * but before finish_open. */ d_instantiate(dentry, inode); - ntfs_save_wsl_perm(inode); + /* Set original time. inode times (i_ctime) may be changed in ntfs_init_acl. */ + inode->i_atime = inode->i_mtime = inode->i_ctime = dir->i_mtime = + dir->i_ctime = ni->i_crtime; + mark_inode_dirty(dir); mark_inode_dirty(inode); /* Normal exit. */ goto out2; -out7: - - /* Undo 'indx_insert_entry'. */ - if (!fnd) - ni_lock_dir(dir_ni); - indx_delete_entry(&dir_ni->dir, dir_ni, new_de + 1, - le16_to_cpu(new_de->key_size), sbi); - /* ni_unlock(dir_ni); will be called later. */ out6: if (rp_inserted) ntfs_remove_reparse(sbi, IO_REPARSE_TAG_SYMLINK, &new_de->ref); @@ -1682,11 +1690,11 @@ out2: kfree(rp); out1: - if (err) { - if (!fnd) - ni_unlock(dir_ni); + if (!fnd) + ni_unlock(dir_ni); + + if (err) return ERR_PTR(err); - } unlock_new_inode(inode); @@ -1783,9 +1791,6 @@ void ntfs_evict_inode(struct inode *inode) { truncate_inode_pages_final(&inode->i_data); - if (inode->i_nlink) - _ni_write_inode(inode, inode_needs_sync(inode)); - invalidate_inode_buffers(inode); clear_inode(inode); diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 85efb34d211c..50b7fb71ca26 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -872,7 +872,7 @@ int ntfs_acl_chmod(struct mnt_idmap *idmap, struct dentry *dentry); ssize_t ntfs_listxattr(struct dentry *dentry, char *buffer, size_t size); extern const struct xattr_handler *ntfs_xattr_handlers[]; -int ntfs_save_wsl_perm(struct inode *inode); +int ntfs_save_wsl_perm(struct inode *inode, __le16 *ea_size); void ntfs_get_wsl_perm(struct inode *inode); /* globals from lznt.c */ diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index 4cab20d70c79..9fbeaa7bbc00 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -296,7 +296,8 @@ out: static noinline int ntfs_set_ea(struct inode *inode, const char *name, size_t name_len, const void *value, - size_t val_size, int flags, bool locked) + size_t val_size, int flags, bool locked, + __le16 *ea_size) { struct ntfs_inode *ni = ntfs_i(inode); struct ntfs_sb_info *sbi = ni->mi.sbi; @@ -504,6 +505,8 @@ update_ea: if (ea_info.size_pack != size_pack) ni->ni_flags |= NI_FLAG_UPDATE_PARENT; + if (ea_size) + *ea_size = ea_info.size_pack; mark_inode_dirty(&ni->vfs_inode); out: @@ -633,7 +636,7 @@ static noinline int ntfs_set_acl_ex(struct mnt_idmap *idmap, flags = 0; } - err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0); + err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0, NULL); if (err == -ENODATA && !size) err = 0; /* Removing non existed xattr. */ if (!err) { @@ -923,7 +926,8 @@ set_new_fa: } /* Deal with NTFS extended attribute. */ - err = ntfs_set_ea(inode, name, strlen(name), value, size, flags, 0); + err = ntfs_set_ea(inode, name, strlen(name), value, size, flags, 0, + NULL); out: inode->i_ctime = current_time(inode); @@ -937,7 +941,7 @@ out: * * save uid/gid/mode in xattr */ -int ntfs_save_wsl_perm(struct inode *inode) +int ntfs_save_wsl_perm(struct inode *inode, __le16 *ea_size) { int err; __le32 value; @@ -946,26 +950,26 @@ int ntfs_save_wsl_perm(struct inode *inode) ni_lock(ni); value = cpu_to_le32(i_uid_read(inode)); err = ntfs_set_ea(inode, "$LXUID", sizeof("$LXUID") - 1, &value, - sizeof(value), 0, true); /* true == already locked. */ + sizeof(value), 0, true, ea_size); if (err) goto out; value = cpu_to_le32(i_gid_read(inode)); err = ntfs_set_ea(inode, "$LXGID", sizeof("$LXGID") - 1, &value, - sizeof(value), 0, true); + sizeof(value), 0, true, ea_size); if (err) goto out; value = cpu_to_le32(inode->i_mode); err = ntfs_set_ea(inode, "$LXMOD", sizeof("$LXMOD") - 1, &value, - sizeof(value), 0, true); + sizeof(value), 0, true, ea_size); if (err) goto out; if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { value = cpu_to_le32(inode->i_rdev); err = ntfs_set_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, &value, - sizeof(value), 0, true); + sizeof(value), 0, true, ea_size); if (err) goto out; } -- cgit v1.2.3 From 625602487a03203a732dc0d4b63da895f45def86 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Mon, 16 Jan 2023 14:23:38 +0400 Subject: fs/ntfs3: Optimization in ntfs_set_state() The current volume flags are updated only if VOLUME_FLAG_DIRTY has been changed. Signed-off-by: Konstantin Komarov --- fs/ntfs3/fsntfs.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)