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(-) 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 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(-) 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 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(+) 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 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(+) 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 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(+) 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 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(+) 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 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(-) 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 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(+) 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 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(+) 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 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(-) 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 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(-) 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 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(-) 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 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(-) 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 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(-) 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 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(-) 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 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(-) 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 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(-) 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 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(-) 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 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(-) 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 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 --- Documentation/filesystems/ntfs3.rst | 11 ----------- 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 -------------- 7 files changed, 1 insertion(+), 49 deletions(-) diff --git a/Documentation/filesystems/ntfs3.rst b/Documentation/filesystems/ntfs3.rst index 5aa102bd72c2..f0cf05cad2ba 100644 --- a/Documentation/filesystems/ntfs3.rst +++ b/Documentation/filesystems/ntfs3.rst @@ -61,17 +61,6 @@ this table marked with no it means default is without **no**. directories, fmask applies only to files and dmask only to directories. * - fmask= - * - noacsrules - - "No access rules" mount option sets access rights for files/folders to - 777 and owner/group to root. This mount option absorbs all other - permissions. - - - Permissions change for files/folders will be reported as successful, - but they will remain 777. - - - Owner/group change will be reported as successful, butthey will stay - as root. - * - nohidden - Files with the Windows-specific HIDDEN (FILE_ATTRIBUTE_HIDDEN) attribute will not be shown under Linux. 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 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(-) 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 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(-) diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c index 342938704cfd..d888ba14237f 100644 --- a/fs/ntfs3/fsntfs.c +++ b/fs/ntfs3/fsntfs.c @@ -925,6 +925,7 @@ int ntfs_set_state(struct ntfs_sb_info *sbi, enum NTFS_DIRTY_FLAGS dirty) struct VOLUME_INFO *info; struct mft_inode *mi; struct ntfs_inode *ni; + __le16 info_flags; /* * Do not change state if fs was real_dirty. @@ -957,6 +958,8 @@ int ntfs_set_state(struct ntfs_sb_info *sbi, enum NTFS_DIRTY_FLAGS dirty) goto out; } + info_flags = info->flags; + switch (dirty) { case NTFS_DIRTY_ERROR: ntfs_notice(sbi->sb, "Mark volume as dirty due to NTFS errors"); @@ -970,8 +973,10 @@ int ntfs_set_state(struct ntfs_sb_info *sbi, enum NTFS_DIRTY_FLAGS dirty) break; } /* Cache current volume flags. */ - sbi->volume.flags = info->flags; - mi->dirty = true; + if (info_flags != info->flags) { + sbi->volume.flags = info->flags; + mi->dirty = true; + } err = 0; out: -- cgit From e483783c7bca4169a5ed284acc01a9577c875407 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 14 Feb 2023 13:44:22 +0400 Subject: fs/ntfs3: Undo endian changes sbi->mft.reserved_bitmap is in-memory (not on-disk!) bitmap. Assumed cpu endian is faster than fixed endian. Signed-off-by: Konstantin Komarov --- fs/ntfs3/fsntfs.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c index d888ba14237f..9ed9dd0d8edf 100644 --- a/fs/ntfs3/fsntfs.c +++ b/fs/ntfs3/fsntfs.c @@ -646,13 +646,13 @@ next: NULL, 0, NULL, NULL)) goto next; - __clear_bit_le(ir - MFT_REC_RESERVED, + __clear_bit(ir - MFT_REC_RESERVED, &sbi->mft.reserved_bitmap); } } /* Scan 5 bits for zero. Bit 0 == MFT_REC_RESERVED */ - zbit = find_next_zero_bit_le(&sbi->mft.reserved_bitmap, + zbit = find_next_zero_bit(&sbi->mft.reserved_bitmap, MFT_REC_FREE, MFT_REC_RESERVED); if (zbit >= MFT_REC_FREE) { sbi->mft.next_reserved = MFT_REC_FREE; @@ -720,7 +720,7 @@ found: if (*rno >= MFT_REC_FREE) wnd_set_used(wnd, *rno, 1); else if (*rno >= MFT_REC_RESERVED && sbi->mft.reserved_bitmap_inited) - __set_bit_le(*rno - MFT_REC_RESERVED, &sbi->mft.reserved_bitmap); + __set_bit(*rno - MFT_REC_RESERVED, &sbi->mft.reserved_bitmap); out: if (!mft) @@ -748,7 +748,7 @@ void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno, bool is_mft) else wnd_set_free(wnd, rno, 1); } else if (rno >= MFT_REC_RESERVED && sbi->mft.reserved_bitmap_inited) { - __clear_bit_le(rno - MFT_REC_RESERVED, &sbi->mft.reserved_bitmap); + __clear_bit(rno - MFT_REC_RESERVED, &sbi->mft.reserved_bitmap); } if (rno < wnd_zone_bit(wnd)) @@ -846,9 +846,8 @@ void ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait) { int err; struct super_block *sb = sbi->sb; - u32 blocksize; + u32 blocksize, bytes; sector_t block1, block2; - u32 bytes; if (!sb) return; -- cgit From 63e92a0c5a0d5816803907a3e30a91ef72c903a5 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 14 Feb 2023 13:57:09 +0400 Subject: fs/ntfs3: Undo critial modificatins to keep directory consistency Affect xfstest 320. Signed-off-by: Konstantin Komarov --- fs/ntfs3/index.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c index 9fefeac5fe7e..5d1ec0124137 100644 --- a/fs/ntfs3/index.c +++ b/fs/ntfs3/index.c @@ -1778,10 +1778,11 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni, struct indx_node *n1 = fnd->nodes[level]; struct INDEX_HDR *hdr1 = &n1->index->ihdr; struct INDEX_HDR *hdr2; - u32 to_copy, used; + u32 to_copy, used, used1; CLST new_vbn; __le64 t_vbn, *sub_vbn; u16 sp_size; + void *hdr1_saved = NULL; /* Try the most easy case. */ e = fnd->level - 1 == level ? fnd->de[level] : NULL; @@ -1814,6 +1815,13 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni, return -ENOMEM; memcpy(up_e, sp, sp_size); + used1 = le32_to_cpu(hdr1->used); + hdr1_saved = kmemdup(hdr1, used1, GFP_NOFS); + if (!hdr1_saved) { + err = -ENOMEM; + goto out; + } + if (!hdr1->flags) { up_e->flags |= NTFS_IE_HAS_SUBNODES; up_e->size = cpu_to_le16(sp_size + sizeof(u64)); @@ -1846,7 +1854,7 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni, hdr_insert_head(hdr2, de_t, to_copy); /* Remove all entries (sp including) from hdr1. */ - used = le32_to_cpu(hdr1->used) - to_copy - sp_size; + used = used1 - to_copy - sp_size; memmove(de_t, Add2Ptr(sp, sp_size), used - le32_to_cpu(hdr1->de_off)); hdr1->used = cpu_to_le32(used); @@ -1876,8 +1884,6 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni, if (!level) { /* Insert in root. */ err = indx_insert_into_root(indx, ni, up_e, NULL, ctx, fnd, 0); - if (err) - goto out; } else { /* * The target buffer's parent is another index buffer. @@ -1885,12 +1891,20 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni, */ err = indx_insert_into_buffer(indx, ni, root, up_e, ctx, level - 1, fnd); - if (err) - goto out; + } + + if (err) { + /* + * Undo critical operations. + */ + indx_mark_free(indx, ni, new_vbn >> indx->idx2vbn_bits); + memcpy(hdr1, hdr1_saved, used1); + indx_write(indx, ni, n1, 0); } out: kfree(up_e); + kfree(hdr1_saved); return err; } @@ -1949,16 +1963,12 @@ int indx_insert_entry(struct ntfs_index *indx, struct ntfs_inode *ni, */ err = indx_insert_into_root(indx, ni, new_de, fnd->root_de, ctx, fnd, undo); - if (err) - goto out; } else { /* * Found a leaf buffer, so we'll insert the new entry into it. */ err = indx_insert_into_buffer(indx, ni, root, new_de, ctx, fnd->level - 1, fnd); - if (err) - goto out; } out: -- cgit From 1a6be5fb156a1a7e1c81d30ca4ca48bca99b7ca1 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 14 Feb 2023 14:00:04 +0400 Subject: fs/ntfs3: Remove field sbi->used.bitmap.set_tail This field is not used in driver. Signed-off-by: Konstantin Komarov --- fs/ntfs3/ntfs_fs.h | 1 - fs/ntfs3/super.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 50b7fb71ca26..7845c627a761 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -163,7 +163,6 @@ struct wnd_bitmap { size_t zone_bit; size_t zone_end; - bool set_tail; // Not necessary in driver. bool inited; }; diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 10c019ef7da3..d7bec9b28a42 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -1117,8 +1117,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) goto put_inode_out; } - /* Not necessary. */ - sbi->used.bitmap.set_tail = true; err = wnd_init(&sbi->used.bitmap, sb, tt); if (err) goto put_inode_out; -- cgit From 75c5e0c9e5cad34deeec7c131c2b1368df5a8c75 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 14 Feb 2023 15:06:27 +0400 Subject: fs/ntfs3: Changed ntfs_get_acl() to use dentry ntfs_get_acl changed to match new interface in struct inode_operations. Signed-off-by: Konstantin Komarov --- fs/ntfs3/file.c | 2 +- fs/ntfs3/namei.c | 4 ++-- fs/ntfs3/ntfs_fs.h | 5 +++-- fs/ntfs3/xattr.c | 26 +++++++++----------------- 4 files changed, 15 insertions(+), 22 deletions(-) diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index 1e8d6a3c9fec..56185bd1a03e 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -1143,7 +1143,7 @@ const struct inode_operations ntfs_file_inode_operations = { .getattr = ntfs_getattr, .setattr = ntfs3_setattr, .listxattr = ntfs_listxattr, - .get_inode_acl = ntfs_get_acl, + .get_acl = ntfs_get_acl, .set_acl = ntfs_set_acl, .fiemap = ntfs_fiemap, }; diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c index fdd11f2a1883..447a241fe02c 100644 --- a/fs/ntfs3/namei.c +++ b/fs/ntfs3/namei.c @@ -607,7 +607,7 @@ const struct inode_operations ntfs_dir_inode_operations = { .rmdir = ntfs_rmdir, .mknod = ntfs_mknod, .rename = ntfs_rename, - .get_inode_acl = ntfs_get_acl, + .get_acl = ntfs_get_acl, .set_acl = ntfs_set_acl, .setattr = ntfs3_setattr, .getattr = ntfs_getattr, @@ -620,7 +620,7 @@ const struct inode_operations ntfs_special_inode_operations = { .setattr = ntfs3_setattr, .getattr = ntfs_getattr, .listxattr = ntfs_listxattr, - .get_inode_acl = ntfs_get_acl, + .get_acl = ntfs_get_acl, .set_acl = ntfs_set_acl, }; diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 7845c627a761..15df110f561f 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -857,11 +857,12 @@ unsigned long ntfs_names_hash(const u16 *name, size_t len, const u16 *upcase, /* globals from xattr.c */ #ifdef CONFIG_NTFS3_FS_POSIX_ACL -struct posix_acl *ntfs_get_acl(struct inode *inode, int type, bool rcu); +struct posix_acl *ntfs_get_acl(struct mnt_idmap *idmap, + struct dentry *dentry, int type); int ntfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, struct posix_acl *acl, int type); int ntfs_init_acl(struct mnt_idmap *idmap, struct inode *inode, - struct inode *dir); + struct inode *dir); #else #define ntfs_get_acl NULL #define ntfs_set_acl NULL diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index 9fbeaa7bbc00..d2746803f032 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -520,9 +520,14 @@ out: } #ifdef CONFIG_NTFS3_FS_POSIX_ACL -static struct posix_acl *ntfs_get_acl_ex(struct inode *inode, int type, - int locked) + +/* + * ntfs_get_acl - inode_operations::get_acl + */ +struct posix_acl *ntfs_get_acl(struct mnt_idmap *idmap, + struct dentry *dentry, int type) { + struct inode *inode = d_inode(dentry); struct ntfs_inode *ni = ntfs_i(inode); const char *name; size_t name_len; @@ -545,13 +550,11 @@ static struct posix_acl *ntfs_get_acl_ex(struct inode *inode, int type, name_len = sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1; } - if (!locked) - ni_lock(ni); + ni_lock(ni); err = ntfs_get_ea(inode, name, name_len, buf, PATH_MAX, &req); - if (!locked) - ni_unlock(ni); + ni_unlock(ni); /* Translate extended attribute to acl. */ if (err >= 0) { @@ -570,17 +573,6 @@ static struct posix_acl *ntfs_get_acl_ex(struct inode *inode, int type, return acl; } -/* - * ntfs_get_acl - inode_operations::get_acl - */ -struct posix_acl *ntfs_get_acl(struct inode *inode, int type, bool rcu) -{ - if (rcu) - return ERR_PTR(-ECHILD); - - return ntfs_get_acl_ex(inode, type, 0); -} - static noinline int ntfs_set_acl_ex(struct mnt_idmap *idmap, struct inode *inode, struct posix_acl *acl, int type, bool init_acl) -- cgit From 96de65a9413e0422233b285368e8a9a64e461187 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 17 Jan 2023 15:01:00 +0400 Subject: fs/ntfs3: Code formatting and refactoring Added minor refactoring. Added and fixed some comments. In some places, the code has been reformatted to fit into 80 columns. clang-format-12 was used to format code according kernel's .clang-format. Signed-off-by: Konstantin Komarov --- fs/ntfs3/attrib.c | 17 ++++++------ fs/ntfs3/bitmap.c | 22 ++++++++-------- fs/ntfs3/file.c | 25 ++++++++++-------- fs/ntfs3/frecord.c | 37 ++++++++++++-------------- fs/ntfs3/fslog.c | 77 +++++++++++++++++++++++++++--------------------------- fs/ntfs3/fsntfs.c | 13 +++++---- fs/ntfs3/index.c | 28 +++++++++++--------- fs/ntfs3/inode.c | 33 ++++++++++++----------- fs/ntfs3/lznt.c | 10 +++---- fs/ntfs3/namei.c | 4 +-- fs/ntfs3/ntfs_fs.h | 9 +++---- fs/ntfs3/record.c | 9 ++++--- fs/ntfs3/run.c | 6 ++--- fs/ntfs3/super.c | 70 +++++++++++++++++++++++++++---------------------- fs/ntfs3/xattr.c | 4 +-- 15 files changed, 186 insertions(+), 178 deletions(-) diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c index 5e6bafb10f42..0b8bc66377db 100644 --- a/fs/ntfs3/attrib.c +++ b/fs/ntfs3/attrib.c @@ -405,8 +405,8 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, int err = 0; struct ntfs_sb_info *sbi = ni->mi.sbi; u8 cluster_bits = sbi->cluster_bits; - bool is_mft = - ni->mi.rno == MFT_REC_MFT && type == ATTR_DATA && !name_len; + bool is_mft = ni->mi.rno == MFT_REC_MFT && type == ATTR_DATA && + !name_len; u64 old_valid, old_size, old_alloc, new_alloc, new_alloc_tmp; struct ATTRIB *attr = NULL, *attr_b; struct ATTR_LIST_ENTRY *le, *le_b; @@ -531,11 +531,10 @@ add_alloc_in_same_attr_seg: pre_alloc = 0; if (type == ATTR_DATA && !name_len && sbi->options->prealloc) { - pre_alloc = - bytes_to_cluster( - sbi, - get_pre_allocated(new_size)) - - new_alen; + pre_alloc = bytes_to_cluster( + sbi, get_pre_allocated( + new_size)) - + new_alen; } /* Get the last LCN to allocate from. */ @@ -573,8 +572,8 @@ add_alloc_in_same_attr_seg: err = attr_allocate_clusters( sbi, run, vcn, lcn, to_allocate, &pre_alloc, is_mft ? ALLOCATE_MFT : ALLOCATE_DEF, &alen, - is_mft ? 0 - : (sbi->record_size - + is_mft ? 0 : + (sbi->record_size - le32_to_cpu(rec->used) + 8) / 3 + 1, diff --git a/fs/ntfs3/bitmap.c b/fs/ntfs3/bitmap.c index 393c726ef17a..9a6c6a09d70c 100644 --- a/fs/ntfs3/bitmap.c +++ b/fs/ntfs3/bitmap.c @@ -40,9 +40,9 @@ static struct kmem_cache *ntfs_enode_cachep; int __init ntfs3_init_bitmap(void) { - ntfs_enode_cachep = - kmem_cache_create("ntfs3_enode_cache", sizeof(struct e_node), 0, - SLAB_RECLAIM_ACCOUNT, NULL); + ntfs_enode_cachep = kmem_cache_create("ntfs3_enode_cache", + sizeof(struct e_node), 0, + SLAB_RECLAIM_ACCOUNT, NULL); return ntfs_enode_cachep ? 0 : -ENOMEM; } @@ -286,9 +286,9 @@ static void wnd_add_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len, if (wnd->uptodated != 1) { /* Check bits before 'bit'. */ ib = wnd->zone_bit == wnd->zone_end || - bit < wnd->zone_end - ? 0 - : wnd->zone_end; + bit < wnd->zone_end ? + 0 : + wnd->zone_end; while (bit > ib && wnd_is_free_hlp(wnd, bit - 1, 1)) { bit -= 1; @@ -297,9 +297,9 @@ static void wnd_add_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len, /* Check bits after 'end_in'. */ ib = wnd->zone_bit == wnd->zone_end || - end_in > wnd->zone_bit - ? wnd->nbits - : wnd->zone_bit; + end_in > wnd->zone_bit ? + wnd->nbits : + wnd->zone_bit; while (end_in < ib && wnd_is_free_hlp(wnd, end_in, 1)) { end_in += 1; @@ -417,8 +417,8 @@ static void wnd_remove_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len) return; n3 = rb_first(&wnd->count_tree); wnd->extent_max = - n3 ? rb_entry(n3, struct e_node, count.node)->count.key - : 0; + n3 ? rb_entry(n3, struct e_node, count.node)->count.key : + 0; return; } diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index 56185bd1a03e..9a3d55c367d9 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -22,20 +22,21 @@ static int ntfs_ioctl_fitrim(struct ntfs_sb_info *sbi, unsigned long arg) { struct fstrim_range __user *user_range; struct fstrim_range range; + struct block_device *dev; int err; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (!bdev_max_discard_sectors(sbi->sb->s_bdev)) + dev = sbi->sb->s_bdev; + if (!bdev_max_discard_sectors(dev)) return -EOPNOTSUPP; user_range = (struct fstrim_range __user *)arg; if (copy_from_user(&range, user_range, sizeof(range))) return -EFAULT; - range.minlen = max_t(u32, range.minlen, - bdev_discard_granularity(sbi->sb->s_bdev)); + range.minlen = max_t(u32, range.minlen, bdev_discard_granularity(dev)); err = ntfs_trim_fs(sbi, &range); if (err < 0) @@ -190,8 +191,8 @@ static int ntfs_zero_range(struct inode *inode, u64 vbo, u64 vbo_to) for (; idx < idx_end; idx += 1, from = 0) { page_off = (loff_t)idx << PAGE_SHIFT; - to = (page_off + PAGE_SIZE) > vbo_to ? (vbo_to - page_off) - : PAGE_SIZE; + to = (page_off + PAGE_SIZE) > vbo_to ? (vbo_to - page_off) : + PAGE_SIZE; iblock = page_off >> inode->i_blkbits; page = find_or_create_page(mapping, idx, @@ -564,13 +565,14 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len) ni_unlock(ni); } else { /* Check new size. */ + u8 cluster_bits = sbi->cluster_bits; /* generic/213: expected -ENOSPC instead of -EFBIG. */ if (!is_supported_holes) { loff_t to_alloc = new_size - inode_get_bytes(inode); if (to_alloc > 0 && - (to_alloc >> sbi->cluster_bits) > + (to_alloc >> cluster_bits) > wnd_zeroes(&sbi->used.bitmap)) { err = -ENOSPC; goto out; @@ -591,7 +593,7 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len) } if (is_supported_holes) { - CLST vcn = vbo >> sbi->cluster_bits; + CLST vcn = vbo >> cluster_bits; CLST cend = bytes_to_cluster(sbi, end); CLST cend_v = bytes_to_cluster(sbi, ni->i_valid); CLST lcn, clen; @@ -1049,8 +1051,8 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (ret) goto out; - ret = is_compressed(ni) ? ntfs_compress_write(iocb, from) - : __generic_file_write_iter(iocb, from); + ret = is_compressed(ni) ? ntfs_compress_write(iocb, from) : + __generic_file_write_iter(iocb, from); out: inode_unlock(inode); @@ -1102,8 +1104,9 @@ static int ntfs_file_release(struct inode *inode, struct file *file) int err = 0; /* If we are last writer on the inode, drop the block reservation. */ - if (sbi->options->prealloc && ((file->f_mode & FMODE_WRITE) && - atomic_read(&inode->i_writecount) == 1)) { + if (sbi->options->prealloc && + ((file->f_mode & FMODE_WRITE) && + atomic_read(&inode->i_writecount) == 1)) { ni_lock(ni); down_write(&ni->file.run_lock); diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index 9e7dfee303e8..481219f2a7cf 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -76,8 +76,8 @@ struct ATTR_STD_INFO *ni_std(struct ntfs_inode *ni) const struct ATTRIB *attr; attr = mi_find_attr(&ni->mi, NULL, ATTR_STD, NULL, 0, NULL); - return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO)) - : NULL; + return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO)) : + NULL; } /* @@ -91,8 +91,8 @@ struct ATTR_STD_INFO5 *ni_std5(struct ntfs_inode *ni) attr = mi_find_attr(&ni->mi, NULL, ATTR_STD, NULL, 0, NULL); - return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO5)) - : NULL; + return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO5)) : + NULL; } /* @@ -1439,8 +1439,8 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type, int err; CLST plen; struct ATTRIB *attr; - bool is_ext = - (flags & (ATTR_FLAG_SPARSED | ATTR_FLAG_COMPRESSED)) && !svcn; + bool is_ext = (flags & (ATTR_FLAG_SPARSED | ATTR_FLAG_COMPRESSED)) && + !svcn; u32 name_size = ALIGN(name_len * sizeof(short), 8); u32 name_off = is_ext ? SIZEOF_NONRESIDENT_EX : SIZEOF_NONRESIDENT; u32 run_off = name_off + name_size; @@ -1756,9 +1756,9 @@ int ni_new_attr_flags(struct ntfs_inode *ni, enum FILE_ATTRIBUTE new_fa) } /* Resize nonresident empty attribute in-place only. */ - new_asize = (new_aflags & (ATTR_FLAG_COMPRESSED | ATTR_FLAG_SPARSED)) - ? (SIZEOF_NONRESIDENT_EX + 8) - : (SIZEOF_NONRESIDENT + 8); + new_asize = (new_aflags & (ATTR_FLAG_COMPRESSED | ATTR_FLAG_SPARSED)) ? + (SIZEOF_NONRESIDENT_EX + 8) : + (SIZEOF_NONRESIDENT + 8); if (!mi_resize_attr(mi, attr, new_asize - le32_to_cpu(attr->size))) return -EOPNOTSUPP; @@ -2965,14 +2965,14 @@ bool ni_remove_name_undo(struct ntfs_inode *dir_ni, struct ntfs_inode *ni, { struct ntfs_sb_info *sbi = ni->mi.sbi; struct ATTRIB *attr; - u16 de_key_size = de2 ? le16_to_cpu(de2->key_size) : 0; + u16 de_key_size; switch (undo_step) { case 4: + de_key_size = le16_to_cpu(de2->key_size); if (ni_insert_resident(ni, de_key_size, ATTR_NAME, NULL, 0, - &attr, NULL, NULL)) { + &attr, NULL, NULL)) return false; - } memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de2 + 1, de_key_size); mi_get_ref(&ni->mi, &de2->ref); @@ -2981,19 +2981,16 @@ bool ni_remove_name_undo(struct ntfs_inode *dir_ni, struct ntfs_inode *ni, de2->flags = 0; de2->res = 0; - if (indx_insert_entry(&dir_ni->dir, dir_ni, de2, sbi, NULL, - 1)) { + if (indx_insert_entry(&dir_ni->dir, dir_ni, de2, sbi, NULL, 1)) return false; - } fallthrough; case 2: de_key_size = le16_to_cpu(de->key_size); if (ni_insert_resident(ni, de_key_size, ATTR_NAME, NULL, 0, - &attr, NULL, NULL)) { + &attr, NULL, NULL)) return false; - } memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de + 1, de_key_size); mi_get_ref(&ni->mi, &de->ref); @@ -3162,9 +3159,9 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup, u64 data_size = le64_to_cpu(attr->nres.data_size); __le64 valid_le; - dup->alloc_size = is_attr_ext(attr) - ? attr->nres.total_size - : attr->nres.alloc_size; + dup->alloc_size = is_attr_ext(attr) ? + attr->nres.total_size : + attr->nres.alloc_size; dup->data_size = attr->nres.data_size; if (new_valid > data_size) diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c index bf7396447284..57762c5fe68b 100644 --- a/fs/ntfs3/fslog.c +++ b/fs/ntfs3/fslog.c @@ -827,10 +827,10 @@ static inline struct RESTART_TABLE *extend_rsttbl(struct RESTART_TABLE *tbl, memcpy(rt + 1, tbl + 1, esize * used); - rt->free_goal = free_goal == ~0u - ? cpu_to_le32(~0u) - : cpu_to_le32(sizeof(struct RESTART_TABLE) + - free_goal * esize); + rt->free_goal = free_goal == ~0u ? + cpu_to_le32(~0u) : + cpu_to_le32(sizeof(struct RESTART_TABLE) + + free_goal * esize); if (tbl->first_free) { rt->first_free = tbl->first_free; @@ -1089,9 +1089,9 @@ static inline u64 base_lsn(struct ntfs_log *log, (lsn < (lsn_to_vbo(log, h_lsn) & ~log->page_mask) ? 1 : 0)) << log->file_data_bits) + ((((is_log_record_end(hdr) && - h_lsn <= le64_to_cpu(hdr->record_hdr.last_end_lsn)) - ? le16_to_cpu(hdr->record_hdr.next_record_off) - : log->page_size) + + h_lsn <= le64_to_cpu(hdr->record_hdr.last_end_lsn)) ? + le16_to_cpu(hdr->record_hdr.next_record_off) : + log->page_size) + lsn) >> 3); @@ -1298,9 +1298,9 @@ static void log_init_pg_hdr(struct ntfs_log *log, u32 sys_page_size, if (!log->clst_per_page) log->clst_per_page = 1; - log->first_page = major_ver >= 2 - ? 0x22 * page_size - : ((sys_page_size << 1) + (page_size << 1)); + log->first_page = major_ver >= 2 ? + 0x22 * page_size : + ((sys_page_size << 1) + (page_size << 1)); log->major_ver = major_ver; log->minor_ver = minor_ver; } @@ -1512,20 +1512,19 @@ static u32 current_log_avail(struct ntfs_log *log) * have to compute the free range. * If there is no oldest lsn then start at the first page of the file. */ - oldest_off = (log->l_flags & NTFSLOG_NO_OLDEST_LSN) - ? log->first_page - : (log->oldest_lsn_off & ~log->sys_page_mask); + oldest_off = (log->l_flags & NTFSLOG_NO_OLDEST_LSN) ? + log->first_page : + (log->oldest_lsn_off & ~log->sys_page_mask); /* * We will use the next log page offset to compute the next free page. * If we are going to reuse this page go to the next page. * If we are at the first page then use the end of the file. */ - next_free_off = (log->l_flags & NTFSLOG_REUSE_TAIL) - ? log->next_page + log->page_size - : log->next_page == log->first_page - ? log->l_size - : log->next_page; + next_free_off = (log->l_flags & NTFSLOG_REUSE_TAIL) ? + log->next_page + log->page_size : + log->next_page == log->first_page ? log->l_size : + log->next_page; /* If the two offsets are the same then there is no available space. */ if (oldest_off == next_free_off) @@ -1535,9 +1534,9 @@ static u32 current_log_avail(struct ntfs_log *log) * this range from the total available pages. */ free_bytes = - oldest_off < next_free_off - ? log->total_avail_pages - (next_free_off - oldest_off) - : oldest_off - next_free_off; + oldest_off < next_free_off ? + log->total_avail_pages - (next_free_off - oldest_off) : + oldest_off - next_free_off; free_bytes >>= log->page_bits; return free_bytes * log->reserved; @@ -1671,8 +1670,8 @@ next_tail: } best_lsn1 = first_tail ? base_lsn(log, first_tail, first_file_off) : 0; - best_lsn2 = - second_tail ? base_lsn(log, second_tail, second_file_off) : 0; + best_lsn2 = second_tail ? base_lsn(log, second_tail, second_file_off) : + 0; if (first_tail && second_tail) { if (best_lsn1 > best_lsn2) { @@ -1767,8 +1766,8 @@ tail_read: page_cnt = page_pos = 1; - curpage_off = seq_base == log->seq_num ? min(log->next_page, page_off) - : log->next_page; + curpage_off = seq_base == log->seq_num ? min(log->next_page, page_off) : + log->next_page; wrapped_file = curpage_off == log->first_page && @@ -1826,9 +1825,9 @@ use_cur_page: le64_to_cpu(cur_page->record_hdr.last_end_lsn) && ((lsn_cur >> log->file_data_bits) + ((curpage_off < - (lsn_to_vbo(log, lsn_cur) & ~log->page_mask)) - ? 1 - : 0)) != expected_seq) { + (lsn_to_vbo(log, lsn_cur) & ~log->page_mask)) ? + 1 : + 0)) != expected_seq) { goto check_tail; } @@ -2642,9 +2641,10 @@ static inline bool check_index_root(const struct ATTRIB *attr, { bool ret; const struct INDEX_ROOT *root = resident_data(attr); - u8 index_bits = le32_to_cpu(root->index_block_size) >= sbi->cluster_size - ? sbi->cluster_bits - : SECTOR_SHIFT; + u8 index_bits = le32_to_cpu(root->index_block_size) >= + sbi->cluster_size ? + sbi->cluster_bits : + SECTOR_SHIFT; u8 block_clst = root->index_block_clst; if (le32_to_cpu(attr->res.data_size) < sizeof(struct INDEX_ROOT) || @@ -3683,7 +3683,8 @@ move_data: if (a_dirty) { attr = oa->attr; - err = ntfs_sb_write_run(sbi, oa->run1, vbo, buffer_le, bytes, 0); + err = ntfs_sb_write_run(sbi, oa->run1, vbo, buffer_le, bytes, + 0); if (err) goto out; } @@ -3768,11 +3769,10 @@ int log_replay(struct ntfs_inode *ni, bool *initialized) if (!log) return -ENOMEM; - memset(&rst_info, 0, sizeof(struct restart_info)); - log->ni = ni; log->l_size = l_size; log->one_page_buf = kmalloc(page_size, GFP_NOFS); + if (!log->one_page_buf) { err = -ENOMEM; goto out; @@ -3783,6 +3783,7 @@ int log_replay(struct ntfs_inode *ni, bool *initialized) log->page_bits = blksize_bits(page_size); /* Look for a restart area on the disk. */ + memset(&rst_info, 0, sizeof(struct restart_info)); err = log_read_rst(log, l_size, true, &rst_info); if (err) goto out; @@ -3859,10 +3860,10 @@ check_restart_area: log->init_ra = !!rst_info.vbo; /* If we have a valid page then grab a pointer to the restart area. */ - ra2 = rst_info.valid_page - ? Add2Ptr(rst_info.r_page, - le16_to_cpu(rst_info.r_page->ra_off)) - : NULL; + ra2 = rst_info.valid_page ? + Add2Ptr(rst_info.r_page, + le16_to_cpu(rst_info.r_page->ra_off)) : + NULL; if (rst_info.chkdsk_was_run || (ra2 && ra2->client_idx[1] == LFS_NO_CLIENT_LE)) { diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c index 9ed9dd0d8edf..0a82b1bf3ec2 100644 --- a/fs/ntfs3/fsntfs.c +++ b/fs/ntfs3/fsntfs.c @@ -172,8 +172,8 @@ int ntfs_fix_post_read(struct NTFS_RECORD_HEADER *rhdr, size_t bytes, u16 sample, fo, fn; fo = le16_to_cpu(rhdr->fix_off); - fn = simple ? ((bytes >> SECTOR_SHIFT) + 1) - : le16_to_cpu(rhdr->fix_num); + fn = simple ? ((bytes >> SECTOR_SHIFT) + 1) : + le16_to_cpu(rhdr->fix_num); /* Check errors. */ if ((fo & 1) || fo + fn * sizeof(short) > SECTOR_SIZE || !fn-- || @@ -849,14 +849,13 @@ void ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait) u32 blocksize, bytes; sector_t block1, block2; - if (!sb) + /* + * sb can be NULL here. In this case sbi->flags should be 0 too. + */ + if (!sb || !(sbi->flags & NTFS_FLAGS_MFTMIRR)) return; blocksize = sb->s_blocksize; - - if (!(sbi->flags & NTFS_FLAGS_MFTMIRR)) - return; - bytes = sbi->mft.recs_mirr << sbi->record_bits; block1 = sbi->mft.lbo >> sb->s_blocksize_bits; block2 = sbi->mft.lbo2 >> sb->s_blocksize_bits; diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c index 5d1ec0124137..0a48d2d67219 100644 --- a/fs/ntfs3/index.c +++ b/fs/ntfs3/index.c @@ -431,8 +431,9 @@ next_run: if (vbo + blocksize > data_size) nbits = 8 * (data_size - vbo); - ok = nbits > from ? (*fn)((ulong *)bh->b_data, from, nbits, ret) - : false; + ok = nbits > from ? + (*fn)((ulong *)bh->b_data, from, nbits, ret) : + false; put_bh(bh); if (ok) { @@ -764,8 +765,7 @@ binary_search: return NULL; max_idx = 0; - table_size = min(table_size * 2, - (int)ARRAY_SIZE(offs)); + table_size = min(table_size * 2, (int)ARRAY_SIZE(offs)); goto fill_table; } } else if (diff2 < 0) { @@ -1170,8 +1170,10 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni, /* Read next level. */ err = indx_read(indx, ni, de_get_vbn(e), &node); - if (err) + if (err) { + /* io error? */ return err; + } /* Lookup entry that is <= to the search value. */ e = hdr_find_e(indx, &node->index->ihdr, key, key_len, ctx, @@ -1673,9 +1675,9 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni, mi->dirty = true; /* Create alloc and bitmap attributes (if not). */ - err = run_is_empty(&indx->alloc_run) - ? indx_create_allocate(indx, ni, &new_vbn) - : indx_add_allocate(indx, ni, &new_vbn); + err = run_is_empty(&indx->alloc_run) ? + indx_create_allocate(indx, ni, &new_vbn) : + indx_add_allocate(indx, ni, &new_vbn); /* Layout of record may be changed, so rescan root. */ root = indx_get_root(indx, ni, &attr, &mi); @@ -1865,9 +1867,9 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni, hdr_insert_de(indx, (*indx->cmp)(new_de + 1, le16_to_cpu(new_de->key_size), up_e + 1, le16_to_cpu(up_e->key_size), - ctx) < 0 - ? hdr2 - : hdr1, + ctx) < 0 ? + hdr2 : + hdr1, new_de, NULL, ctx); indx_mark_used(indx, ni, new_vbn >> indx->idx2vbn_bits); @@ -2337,8 +2339,8 @@ int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni, err = level ? indx_insert_into_buffer(indx, ni, root, re, ctx, fnd->level - 1, - fnd) - : indx_insert_into_root(indx, ni, re, e, + fnd) : + indx_insert_into_root(indx, ni, re, e, ctx, fnd, 0); kfree(re); diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index a7ca8183b91d..6c560245eef4 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -262,8 +262,8 @@ next_attr: if (!attr->nres.alloc_size) goto next_attr; - run = ino == MFT_REC_BITMAP ? &sbi->used.bitmap.run - : &ni->file.run; + run = ino == MFT_REC_BITMAP ? &sbi->used.bitmap.run : + &ni->file.run; break; case ATTR_ROOT: @@ -290,9 +290,9 @@ next_attr: if (err) goto out; - mode = sb->s_root - ? (S_IFDIR | (0777 & sbi->options->fs_dmask_inv)) - : (S_IFDIR | 0777); + mode = sb->s_root ? + (S_IFDIR | (0777 & sbi->options->fs_dmask_inv)) : + (S_IFDIR | 0777); goto next_attr; case ATTR_ALLOC: @@ -449,8 +449,8 @@ end_enum: ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY; inode->i_op = &ntfs_file_inode_operations; inode->i_fop = &ntfs_file_operations; - inode->i_mapping->a_ops = - is_compressed(ni) ? &ntfs_aops_cmpr : &ntfs_aops; + inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr : + &ntfs_aops; if (ino != MFT_REC_MFT) init_rwsem(&ni->file.run_lock); } else if (S_ISCHR(mode) || S_ISBLK(mode) || S_ISFIFO(mode) || @@ -786,8 +786,8 @@ static ssize_t ntfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) } ret = blockdev_direct_IO(iocb, inode, iter, - wr ? ntfs_get_block_direct_IO_W - : ntfs_get_block_direct_IO_R); + wr ? ntfs_get_block_direct_IO_W : + ntfs_get_block_direct_IO_R); if (ret > 0) end = vbo + ret; @@ -846,7 +846,7 @@ out: } static int ntfs_resident_writepage(struct folio *folio, - struct writeback_control *wbc, void *data) + struct writeback_control *wbc, void *data) { struct address_space *mapping = data; struct ntfs_inode *ni = ntfs_i(mapping->host); @@ -887,8 +887,8 @@ int ntfs_write_begin(struct file *file, struct address_space *mapping, *pagep = NULL; if (is_resident(ni)) { - struct page *page = grab_cache_page_write_begin( - mapping, pos >> PAGE_SHIFT); + struct page *page = + grab_cache_page_write_begin(mapping, pos >> PAGE_SHIFT); if (!page) { err = -ENOMEM; @@ -920,9 +920,8 @@ out: /* * ntfs_write_end - Address_space_operations::write_end. */ -int ntfs_write_end(struct file *file, struct address_space *mapping, - loff_t pos, u32 len, u32 copied, struct page *page, - void *fsdata) +int ntfs_write_end(struct file *file, struct address_space *mapping, loff_t pos, + u32 len, u32 copied, struct page *page, void *fsdata) { struct inode *inode = mapping->host; struct ntfs_inode *ni = ntfs_i(inode); @@ -1605,8 +1604,8 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, } else if (S_ISREG(mode)) { inode->i_op = &ntfs_file_inode_operations; inode->i_fop = &ntfs_file_operations; - inode->i_mapping->a_ops = - is_compressed(ni) ? &ntfs_aops_cmpr : &ntfs_aops; + inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr : + &ntfs_aops; init_rwsem(&ni->file.run_lock); } else { inode->i_op = &ntfs_special_inode_operations; diff --git a/fs/ntfs3/lznt.c b/fs/ntfs3/lznt.c index 28f654561f27..61e161c7c567 100644 --- a/fs/ntfs3/lznt.c +++ b/fs/ntfs3/lznt.c @@ -296,8 +296,8 @@ next: */ struct lznt *get_lznt_ctx(int level) { - struct lznt *r = kzalloc(level ? offsetof(struct lznt, hash) - : sizeof(struct lznt), + struct lznt *r = kzalloc(level ? offsetof(struct lznt, hash) : + sizeof(struct lznt), GFP_NOFS); if (r) @@ -392,9 +392,9 @@ ssize_t decompress_lznt(const void *cmpr, size_t cmpr_size, void *unc, unc_use = err; } else { /* This chunk does not contain compressed data. */ - unc_use = unc_chunk + LZNT_CHUNK_SIZE > unc_end - ? unc_end - unc_chunk - : LZNT_CHUNK_SIZE; + unc_use = unc_chunk + LZNT_CHUNK_SIZE > unc_end ? + unc_end - unc_chunk : + LZNT_CHUNK_SIZE; if (cmpr_chunk + sizeof(chunk_hdr) + unc_use > cmpr_end) { diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c index 447a241fe02c..9736b1e4a0f6 100644 --- a/fs/ntfs3/namei.c +++ b/fs/ntfs3/namei.c @@ -433,8 +433,8 @@ static int ntfs_atomic_open(struct inode *dir, struct dentry *dentry, inode = ntfs_create_inode(&nop_mnt_idmap, dir, dentry, uni, mode, 0, NULL, 0, fnd); - err = IS_ERR(inode) ? PTR_ERR(inode) - : finish_open(file, dentry, ntfs_file_open); + err = IS_ERR(inode) ? PTR_ERR(inode) : + finish_open(file, dentry, ntfs_file_open); dput(d); out2: diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 15df110f561f..eb01f7e76479 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -338,7 +338,7 @@ enum ntfs_inode_mutex_lock_class { }; /* - * sturct ntfs_inode + * struct ntfs_inode * * Ntfs inode - extends linux inode. consists of one or more MFT inodes. */ @@ -699,9 +699,8 @@ int ntfs_get_block(struct inode *inode, sector_t vbn, struct buffer_head *bh_result, int create); int ntfs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, u32 len, struct page **pagep, void **fsdata); -int ntfs_write_end(struct file *file, struct address_space *mapping, - loff_t pos, u32 len, u32 copied, struct page *page, - void *fsdata); +int ntfs_write_end(struct file *file, struct address_space *mapping, loff_t pos, + u32 len, u32 copied, struct page *page, void *fsdata); int ntfs3_write_inode(struct inode *inode, struct writeback_control *wbc); int ntfs_sync_inode(struct inode *inode); int ntfs_flush_inodes(struct super_block *sb, struct inode *i1, @@ -858,7 +857,7 @@ unsigned long ntfs_names_hash(const u16 *name, size_t len, const u16 *upcase, /* globals from xattr.c */ #ifdef CONFIG_NTFS3_FS_POSIX_ACL struct posix_acl *ntfs_get_acl(struct mnt_idmap *idmap, - struct dentry *dentry, int type); + struct dentry *dentry, int type); int ntfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, struct posix_acl *acl, int type); int ntfs_init_acl(struct mnt_idmap *idmap, struct inode *inode, diff --git a/fs/ntfs3/record.c b/fs/ntfs3/record.c index 0603169ee8a0..2a281cead2bc 100644 --- a/fs/ntfs3/record.c +++ b/fs/ntfs3/record.c @@ -419,10 +419,9 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type, struct ntfs_sb_info *sbi = mi->sbi; u32 used = le32_to_cpu(rec->used); const u16 *upcase = sbi->upcase; - int diff; /* Can we insert mi attribute? */ - if (used + asize > mi->sbi->record_size) + if (used + asize > sbi->record_size) return NULL; /* @@ -431,7 +430,7 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type, */ attr = NULL; while ((attr = mi_enum_attr(mi, attr))) { - diff = compare_attr(attr, type, name, name_len, upcase); + int diff = compare_attr(attr, type, name, name_len, upcase); if (diff < 0) continue; @@ -442,9 +441,11 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type, } if (!attr) { - tail = 8; /* Not used, just to suppress warning. */ + /* Append. */ + tail = 8; attr = Add2Ptr(rec, used - 8); } else { + /* Insert before 'attr'. */ tail = used - PtrOffset(rec, attr); } diff --git a/fs/ntfs3/run.c b/fs/ntfs3/run.c index a5af71cd8d14..47612d16c027 100644 --- a/fs/ntfs3/run.c +++ b/fs/ntfs3/run.c @@ -433,9 +433,9 @@ requires_new_range: should_add_tail = Tovcn < r->len; if (should_add_tail) { - tail_lcn = r->lcn == SPARSE_LCN - ? SPARSE_LCN - : (r->lcn + Tovcn); + tail_lcn = r->lcn == SPARSE_LCN ? + SPARSE_LCN : + (r->lcn + Tovcn); tail_vcn = r->vcn + Tovcn; tail_len = r->len - Tovcn; } diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index d7bec9b28a42..6a412826b43d 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -39,10 +39,10 @@ * To mount large volumes as ntfs one should use large cluster size (up to 2M) * The maximum volume size in this case is 2^32 * 2^21 = 2^53 = 8P * - * ntfs limits, cluster size is 2M (2^31) + * ntfs limits, cluster size is 2M (2^21) * ----------------------------------------------------------------------------- - * | < 8P, 2^54 | < 2^32 | yes | yes | yes | yes | yes | - * | > 8P, 2^54 | > 2^32 | no | no | yes | yes | yes | + * | < 8P, 2^53 | < 2^32 | yes | yes | yes | yes | yes | + * | > 8P, 2^53 | > 2^32 | no | no | yes | yes | yes | * ----------------------------------------------------------|------------------ * */ @@ -115,9 +115,9 @@ void ntfs_inode_printk(struct inode *inode, const char *fmt, ...) return; /* Use static allocated buffer, if possible. */ - name = atomic_dec_and_test(&s_name_buf_cnt) - ? s_name_buf - : kmalloc(sizeof(s_name_buf), GFP_NOFS); + name = atomic_dec_and_test(&s_name_buf_cnt) ? + s_name_buf : + kmalloc(sizeof(s_name_buf), GFP_NOFS); if (name) { struct dentry *de = d_find_alias(inode); @@ -369,7 +369,8 @@ static int ntfs_fs_parse_param(struct fs_context *fc, #ifdef CONFIG_NTFS3_FS_POSIX_ACL fc->sb_flags |= SB_POSIXACL; #else - return invalf(fc, "ntfs3: Support for ACL not compiled in!"); + return invalf( + fc, "ntfs3: Support for ACL not compiled in!"); #endif else fc->sb_flags &= ~SB_POSIXACL; @@ -404,24 +405,29 @@ static int ntfs_fs_reconfigure(struct fs_context *fc) ro_rw = sb_rdonly(sb) && !(fc->sb_flags & SB_RDONLY); if (ro_rw && (sbi->flags & NTFS_FLAGS_NEED_REPLAY)) { - errorf(fc, "ntfs3: Couldn't remount rw because journal is not replayed. Please umount/remount instead\n"); + errorf(fc, + "ntfs3: Couldn't remount rw because journal is not replayed. Please umount/remount instead\n"); return -EINVAL; } new_opts->nls = ntfs_load_nls(new_opts->nls_name); if (IS_ERR(new_opts->nls)) { new_opts->nls = NULL; - errorf(fc, "ntfs3: Cannot load iocharset %s", new_opts->nls_name); + errorf(fc, "ntfs3: Cannot load iocharset %s", + new_opts->nls_name); return -EINVAL; } if (new_opts->nls != sbi->options->nls) - return invalf(fc, "ntfs3: Cannot use different iocharset when remounting!"); + return invalf( + fc, + "ntfs3: Cannot use different iocharset when remounting!"); sync_filesystem(sb); if (ro_rw && (sbi->volume.flags & VOLUME_FLAG_DIRTY) && !new_opts->force) { - errorf(fc, "ntfs3: Volume is dirty and \"force\" flag is not set!"); + errorf(fc, + "ntfs3: Volume is dirty and \"force\" flag is not set!"); return -EINVAL; } @@ -539,10 +545,8 @@ static int ntfs_show_options(struct seq_file *m, struct dentry *root) struct ntfs_mount_options *opts = sbi->options; struct user_namespace *user_ns = seq_user_ns(m); - seq_printf(m, ",uid=%u", - from_kuid_munged(user_ns, opts->fs_uid)); - seq_printf(m, ",gid=%u", - from_kgid_munged(user_ns, opts->fs_gid)); + seq_printf(m, ",uid=%u", from_kuid_munged(user_ns, opts->fs_uid)); + seq_printf(m, ",gid=%u", from_kgid_munged(user_ns, opts->fs_gid)); if (opts->fmask) seq_printf(m, ",fmask=%04o", opts->fs_fmask_inv ^ 0xffff); if (opts->dmask) @@ -699,7 +703,7 @@ static u32 true_sectors_per_clst(const struct NTFS_BOOT *boot) if (boot->sectors_per_clusters <= 0x80) return boot->sectors_per_clusters; if (boot->sectors_per_clusters >= 0xf4) /* limit shift to 2MB max */ - return 1U << -(s8)boot->sectors_per_clusters; + return 1U << (-(s8)boot->sectors_per_clusters); return -EINVAL; } @@ -717,6 +721,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, struct buffer_head *bh; struct MFT_REC *rec; u16 fn, ao; + u8 cluster_bits; sbi->volume.blocks = dev_size >> PAGE_SHIFT; @@ -784,7 +789,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; } @@ -792,8 +797,8 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, sbi->cluster_size = boot_sector_size * sct_per_clst; sbi->cluster_bits = blksize_bits(sbi->cluster_size); - sbi->mft.lbo = mlcn << sbi->cluster_bits; - sbi->mft.lbo2 = mlcn2 << sbi->cluster_bits; + sbi->mft.lbo = mlcn << cluster_bits; + sbi->mft.lbo2 = mlcn2 << cluster_bits; /* Compare boot's cluster and sector. */ if (sbi->cluster_size < boot_sector_size) @@ -804,7 +809,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, /* No way to use ntfs_get_block in this case. */ ntfs_err( sb, - "Failed to mount 'cause NTFS's cluster size (%u) is less than media sector size (%u)", + "Failed to mount 'cause NTFS's cluster size (%u) is less than media sector size (%u).", sbi->cluster_size, sector_size); goto out; } @@ -840,18 +845,18 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, gb0 = format_size_gb(dev_size, &mb0); ntfs_warn( sb, - "RAW NTFS volume: Filesystem size %u.%02u Gb > volume size %u.%02u Gb. Mount in read-only", + "RAW NTFS volume: Filesystem size %u.%02u Gb > volume size %u.%02u Gb. Mount in read-only.", gb, mb, gb0, mb0); sb->s_flags |= SB_RDONLY; } - clusters = sbi->volume.size >> sbi->cluster_bits; + clusters = sbi->volume.size >> cluster_bits; #ifndef CONFIG_NTFS3_64BIT_CLUSTER /* 32 bits per cluster. */ if (clusters >> 32) { ntfs_notice( sb, - "NTFS %u.%02u Gb is too big to use 32 bits per cluster", + "NTFS %u.%02u Gb is too big to use 32 bits per cluster.", gb, mb); goto out; } @@ -885,17 +890,17 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, sbi->volume.blocks = sbi->volume.size >> sb->s_blocksize_bits; /* Maximum size for normal files. */ - sbi->maxbytes = (clusters << sbi->cluster_bits) - 1; + sbi->maxbytes = (clusters << cluster_bits) - 1; #ifdef CONFIG_NTFS3_64BIT_CLUSTER - if (clusters >= (1ull << (64 - sbi->cluster_bits))) + if (clusters >= (1ull << (64 - cluster_bits))) sbi->maxbytes = -1; sbi->maxbytes_sparse = -1; sb->s_maxbytes = MAX_LFS_FILESIZE; #else /* Maximum size for sparse file. */ - sbi->maxbytes_sparse = (1ull << (sbi->cluster_bits + 32)) - 1; - sb->s_maxbytes = 0xFFFFFFFFull << sbi->cluster_bits; + sbi->maxbytes_sparse = (1ull << (cluster_bits + 32)) - 1; + sb->s_maxbytes = 0xFFFFFFFFull << cluster_bits; #endif /* @@ -903,7 +908,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, * It would be nice if we are able to allocate 1/8 of * total clusters for MFT but not more then 512 MB. */ - sbi->zone_max = min_t(CLST, 0x20000000 >> sbi->cluster_bits, clusters >> 3); + sbi->zone_max = min_t(CLST, 0x20000000 >> cluster_bits, clusters >> 3); err = 0; @@ -1433,7 +1438,7 @@ static const struct fs_context_operations ntfs_context_ops = { }; /* - * ntfs_init_fs_context - Initialize spi and opts + * ntfs_init_fs_context - Initialize sbi and opts * * This will called when mount/remount. We will first initialize * options so that if remount we can use just that. @@ -1506,7 +1511,8 @@ static int __init init_ntfs_fs(void) if (IS_ENABLED(CONFIG_NTFS3_FS_POSIX_ACL)) pr_info("ntfs3: Enabled Linux POSIX ACLs support\n"); if (IS_ENABLED(CONFIG_NTFS3_64BIT_CLUSTER)) - pr_notice("ntfs3: Warning: Activated 64 bits per cluster. Windows does not support this\n"); + pr_notice( + "ntfs3: Warning: Activated 64 bits per cluster. Windows does not support this\n"); if (IS_ENABLED(CONFIG_NTFS3_LZX_XPRESS)) pr_info("ntfs3: Read-only LZX/Xpress compression included\n"); @@ -1549,7 +1555,9 @@ MODULE_DESCRIPTION("ntfs3 read/write filesystem"); MODULE_INFO(behaviour, "Enabled Linux POSIX ACLs support"); #endif #ifdef CONFIG_NTFS3_64BIT_CLUSTER -MODULE_INFO(cluster, "Warning: Activated 64 bits per cluster. Windows does not support this"); +MODULE_INFO( + cluster, + "Warning: Activated 64 bits per cluster. Windows does not support this"); #endif #ifdef CONFIG_NTFS3_LZX_XPRESS MODULE_INFO(compression, "Read-only lzx/xpress compression included"); diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index d2746803f032..4ad78ceb0088 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -23,8 +23,8 @@ static inline size_t unpacked_ea_size(const struct EA_FULL *ea) { - return ea->size ? le32_to_cpu(ea->size) - : ALIGN(struct_size(ea, name, + return ea->size ? le32_to_cpu(ea->size) : + ALIGN(struct_size(ea, name, 1 + ea->name_len + le16_to_cpu(ea->elength)), 4); -- cgit From 16b3dbfb5d5cdfb0fcb66a5065369c935500a437 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Wed, 15 Feb 2023 13:24:23 +0400 Subject: fs/ntfs3: Add missed "nocase" in ntfs_show_options Sort processing ntfs3's mount options in same order they declared. Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 6a412826b43d..521ce31d67a1 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -270,11 +270,11 @@ static const struct fs_parameter_spec ntfs_fs_parameters[] = { fsparam_flag_no("hidden", Opt_nohidden), fsparam_flag_no("hide_dot_files", Opt_hide_dot_files), fsparam_flag_no("windows_names", Opt_windows_names), - fsparam_flag_no("acl", Opt_acl), fsparam_flag_no("showmeta", Opt_showmeta), + fsparam_flag_no("acl", Opt_acl), + fsparam_string("iocharset", Opt_iocharset), fsparam_flag_no("prealloc", Opt_prealloc), fsparam_flag_no("nocase", Opt_nocase), - fsparam_string("iocharset", Opt_iocharset), {} }; @@ -364,6 +364,9 @@ static int ntfs_fs_parse_param(struct fs_context *fc, case Opt_windows_names: opts->windows_names = result.negated ? 0 : 1; break; + case Opt_showmeta: + opts->showmeta = result.negated ? 0 : 1; + break; case Opt_acl: if (!result.negated) #ifdef CONFIG_NTFS3_FS_POSIX_ACL @@ -375,9 +378,6 @@ static int ntfs_fs_parse_param(struct fs_context *fc, else fc->sb_flags &= ~SB_POSIXACL; break; - case Opt_showmeta: - opts->showmeta = result.negated ? 0 : 1; - break; case Opt_iocharset: kfree(opts->nls_name); opts->nls_name = param->string; @@ -547,34 +547,36 @@ static int ntfs_show_options(struct seq_file *m, struct dentry *root) seq_printf(m, ",uid=%u", from_kuid_munged(user_ns, opts->fs_uid)); seq_printf(m, ",gid=%u", from_kgid_munged(user_ns, opts->fs_gid)); - if (opts->fmask) - seq_printf(m, ",fmask=%04o", opts->fs_fmask_inv ^ 0xffff); if (opts->dmask) seq_printf(m, ",dmask=%04o", opts->fs_dmask_inv ^ 0xffff); - if (opts->nls) - seq_printf(m, ",iocharset=%s", opts->nls->charset); - else - seq_puts(m, ",iocharset=utf8"); + if (opts->fmask) + seq_printf(m, ",fmask=%04o", opts->fs_fmask_inv ^ 0xffff); if (opts->sys_immutable) seq_puts(m, ",sys_immutable"); if (opts->discard) seq_puts(m, ",discard"); + if (opts->force) + seq_puts(m, ",force"); if (opts->sparse) seq_puts(m, ",sparse"); - if (opts->showmeta) - seq_puts(m, ",showmeta"); if (opts->nohidden) seq_puts(m, ",nohidden"); - if (opts->windows_names) - seq_puts(m, ",windows_names"); if (opts->hide_dot_files) seq_puts(m, ",hide_dot_files"); - if (opts->force) - seq_puts(m, ",force"); - if (opts->prealloc) - seq_puts(m, ",prealloc"); + if (opts->windows_names) + seq_puts(m, ",windows_names"); + if (opts->showmeta) + seq_puts(m, ",showmeta"); if (sb->s_flags & SB_POSIXACL) seq_puts(m, ",acl"); + if (opts->nls) + seq_printf(m, ",iocharset=%s", opts->nls->charset); + else + seq_puts(m, ",iocharset=utf8"); + if (opts->prealloc) + seq_puts(m, ",prealloc"); + if (opts->nocase) + seq_puts(m, ",nocase"); return 0; } -- cgit From e43f6ec224c1b428260e161f0300afbe2e1194fe Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Wed, 15 Feb 2023 16:06:56 +0400 Subject: fs/ntfs3: Print details about mount fails Added error mesages with error codes. Minor refactoring and code formatting. Signed-off-by: Konstantin Komarov --- fs/ntfs3/frecord.c | 2 +- fs/ntfs3/fsntfs.c | 40 ++++++------- fs/ntfs3/super.c | 172 +++++++++++++++++++++++++++++++---------------------- 3 files changed, 122 insertions(+), 92 deletions(-) diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index 481219f2a7cf..2bfcf1a989c9 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -3360,7 +3360,7 @@ out: ni_unlock(ni); if (err) { - ntfs_err(sb, "%s r=%lx failed, %d.", hint, inode->i_ino, err); + ntfs_inode_err(inode, "%s failed, %d.", hint, err); ntfs_set_state(sbi, NTFS_DIRTY_ERROR); return err; } diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c index 0a82b1bf3ec2..28cc421102e5 100644 --- a/fs/ntfs3/fsntfs.c +++ b/fs/ntfs3/fsntfs.c @@ -223,7 +223,7 @@ int ntfs_extend_init(struct ntfs_sb_info *sbi) inode = ntfs_iget5(sb, &ref, &NAME_EXTEND); if (IS_ERR(inode)) { err = PTR_ERR(inode); - ntfs_err(sb, "Failed to load $Extend."); + ntfs_err(sb, "Failed to load $Extend (%d).", err); inode = NULL; goto out; } @@ -282,7 +282,7 @@ int ntfs_loadlog_and_replay(struct ntfs_inode *ni, struct ntfs_sb_info *sbi) /* Check for 4GB. */ if (ni->vfs_inode.i_size >= 0x100000000ull) { - ntfs_err(sb, "\x24LogFile is too big"); + ntfs_err(sb, "\x24LogFile is large than 4G."); err = -EINVAL; goto out; } @@ -1863,7 +1863,7 @@ int ntfs_security_init(struct ntfs_sb_info *sbi) inode = ntfs_iget5(sb, &ref, &NAME_SECURE); if (IS_ERR(inode)) { err = PTR_ERR(inode); - ntfs_err(sb, "Failed to load $Secure."); + ntfs_err(sb, "Failed to load $Secure (%d).", err); inode = NULL; goto out; } @@ -1874,45 +1874,43 @@ int ntfs_security_init(struct ntfs_sb_info *sbi) attr = ni_find_attr(ni, NULL, &le, ATTR_ROOT, SDH_NAME, ARRAY_SIZE(SDH_NAME), NULL, NULL); - if (!attr) { - err = -EINVAL; - goto out; - } - - if(!(root_sdh = resident_data_ex(attr, sizeof(struct INDEX_ROOT))) || + if (!attr || + !(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) + - le32_to_cpu(root_sdh->ihdr.used) > - le32_to_cpu(attr->res.data_size)) { + le32_to_cpu(root_sdh->ihdr.used) > + le32_to_cpu(attr->res.data_size)) { + ntfs_err(sb, "$Secure::$SDH is corrupted."); err = -EINVAL; goto out; } err = indx_init(indx_sdh, sbi, attr, INDEX_MUTEX_SDH); - if (err) + if (err) { + ntfs_err(sb, "Failed to initialize $Secure::$SDH (%d).", err); goto out; + } attr = ni_find_attr(ni, attr, &le, ATTR_ROOT, SII_NAME, ARRAY_SIZE(SII_NAME), NULL, NULL); - if (!attr) { - err = -EINVAL; - goto out; - } - - if(!(root_sii = resident_data_ex(attr, sizeof(struct INDEX_ROOT))) || + if (!attr || + !(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) + - le32_to_cpu(root_sii->ihdr.used) > - le32_to_cpu(attr->res.data_size)) { + le32_to_cpu(root_sii->ihdr.used) > + le32_to_cpu(attr->res.data_size)) { + ntfs_err(sb, "$Secure::$SII is corrupted."); err = -EINVAL; goto out; } err = indx_init(indx_sii, sbi, attr, INDEX_MUTEX_SII); - if (err) + if (err) { + ntfs_err(sb, "Failed to initialize $Secure::$SII (%d).", err); goto out; + } fnd_sii = fnd_get(); if (!fnd_sii) { diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 521ce31d67a1..e0f78b306f15 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -734,48 +734,81 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, err = -EINVAL; boot = (struct NTFS_BOOT *)bh->b_data; - if (memcmp(boot->system_id, "NTFS ", sizeof("NTFS ") - 1)) + if (memcmp(boot->system_id, "NTFS ", sizeof("NTFS ") - 1)) { + ntfs_err(sb, "Boot's signature is not NTFS."); goto out; + } /* 0x55AA is not mandaroty. Thanks Maxim Suhanov*/ /*if (0x55 != boot->boot_magic[0] || 0xAA != boot->boot_magic[1]) * goto out; */ - boot_sector_size = (u32)boot->bytes_per_sector[1] << 8; - if (boot->bytes_per_sector[0] || boot_sector_size < SECTOR_SIZE || + boot_sector_size = ((u32)boot->bytes_per_sector[1] << 8) | + boot->bytes_per_sector[0]; + if (boot_sector_size < SECTOR_SIZE || !is_power_of_2(boot_sector_size)) { + ntfs_err(sb, "Invalid bytes per sector %u.", boot_sector_size); goto out; } /* cluster size: 512, 1K, 2K, 4K, ... 2M */ sct_per_clst = true_sectors_per_clst(boot); - if ((int)sct_per_clst < 0) - goto out; - if (!is_power_of_2(sct_per_clst)) + if ((int)sct_per_clst < 0 || !is_power_of_2(sct_per_clst)) { + ntfs_err(sb, "Invalid sectors per cluster %u.", sct_per_clst); goto out; + } + + sbi->cluster_size = boot_sector_size * sct_per_clst; + sbi->cluster_bits = cluster_bits = blksize_bits(sbi->cluster_size); + sbi->cluster_mask = sbi->cluster_size - 1; + sbi->cluster_mask_inv = ~(u64)sbi->cluster_mask; mlcn = le64_to_cpu(boot->mft_clst); mlcn2 = le64_to_cpu(boot->mft2_clst); sectors = le64_to_cpu(boot->sectors_per_volume); - if (mlcn * sct_per_clst >= sectors) + if (mlcn * sct_per_clst >= sectors || mlcn2 * sct_per_clst >= sectors) { + ntfs_err( + sb, + "Start of MFT 0x%llx (0x%llx) is out of volume 0x%llx.", + mlcn, mlcn2, sectors); goto out; + } - if (mlcn2 * sct_per_clst >= sectors) - goto out; + sbi->record_size = record_size = + boot->record_size < 0 ? 1 << (-boot->record_size) : + (u32)boot->record_size << cluster_bits; + sbi->record_bits = blksize_bits(record_size); + sbi->attr_size_tr = (5 * record_size >> 4); // ~320 bytes /* Check MFT record size. */ - if ((boot->record_size < 0 && - SECTOR_SIZE > (2U << (-boot->record_size))) || - (boot->record_size >= 0 && !is_power_of_2(boot->record_size))) { + if (record_size < SECTOR_SIZE || !is_power_of_2(record_size)) { + ntfs_err(sb, "Invalid bytes per MFT record %u (%d).", + record_size, boot->record_size); + goto out; + } + + if (record_size > MAXIMUM_BYTES_PER_MFT) { + ntfs_err(sb, "Unsupported bytes per MFT record %u.", + record_size); goto out; } + sbi->index_size = boot->index_size < 0 ? + 1u << (-boot->index_size) : + (u32)boot->index_size << cluster_bits; + /* Check index record size. */ - if ((boot->index_size < 0 && - SECTOR_SIZE > (2U << (-boot->index_size))) || - (boot->index_size >= 0 && !is_power_of_2(boot->index_size))) { + if (sbi->index_size < SECTOR_SIZE || !is_power_of_2(sbi->index_size)) { + ntfs_err(sb, "Invalid bytes per index %u(%d).", sbi->index_size, + boot->index_size); + goto out; + } + + if (sbi->index_size > MAXIMUM_BYTES_PER_INDEX) { + ntfs_err(sb, "Unsupported bytes per index %u.", + sbi->index_size); goto out; } @@ -796,15 +829,15 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, dev_size += sector_size - 1; } - sbi->cluster_size = boot_sector_size * sct_per_clst; - sbi->cluster_bits = blksize_bits(sbi->cluster_size); - sbi->mft.lbo = mlcn << cluster_bits; sbi->mft.lbo2 = mlcn2 << cluster_bits; /* Compare boot's cluster and sector. */ - if (sbi->cluster_size < boot_sector_size) + if (sbi->cluster_size < boot_sector_size) { + ntfs_err(sb, "Invalid bytes per cluster (%u).", + sbi->cluster_size); goto out; + } /* Compare boot's cluster and media sector. */ if (sbi->cluster_size < sector_size) { @@ -816,28 +849,11 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, goto out; } - sbi->cluster_mask = sbi->cluster_size - 1; - sbi->cluster_mask_inv = ~(u64)sbi->cluster_mask; - sbi->record_size = record_size = boot->record_size < 0 - ? 1 << (-boot->record_size) - : (u32)boot->record_size - << sbi->cluster_bits; - - if (record_size > MAXIMUM_BYTES_PER_MFT || record_size < SECTOR_SIZE) - goto out; - - sbi->record_bits = blksize_bits(record_size); - sbi->attr_size_tr = (5 * record_size >> 4); // ~320 bytes - sbi->max_bytes_per_attr = record_size - ALIGN(MFTRECORD_FIXUP_OFFSET_1, 8) - ALIGN(((record_size >> SECTOR_SHIFT) * sizeof(short)), 8) - ALIGN(sizeof(enum ATTR_TYPE), 8); - sbi->index_size = boot->index_size < 0 - ? 1u << (-boot->index_size) - : (u32)boot->index_size << sbi->cluster_bits; - sbi->volume.ser_num = le64_to_cpu(boot->serial_num); /* Warning if RAW volume. */ @@ -928,6 +944,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) int err; struct ntfs_sb_info *sbi = sb->s_fs_info; struct block_device *bdev = sb->s_bdev; + struct ntfs_mount_options *options; struct inode *inode; struct ntfs_inode *ni; size_t i, tt, bad_len, bad_frags; @@ -942,7 +959,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ref.high = 0; sbi->sb = sb; - sbi->options = fc->fs_private; + sbi->options = options = fc->fs_private; fc->fs_private = NULL; sb->s_flags |= SB_NODIRATIME; sb->s_magic = 0x7366746e; // "ntfs" @@ -950,12 +967,12 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) sb->s_export_op = &ntfs_export_ops; sb->s_time_gran = NTFS_TIME_GRAN; // 100 nsec sb->s_xattr = ntfs_xattr_handlers; - sb->s_d_op = sbi->options->nocase ? &ntfs_dentry_ops : NULL; + sb->s_d_op = options->nocase ? &ntfs_dentry_ops : NULL; - sbi->options->nls = ntfs_load_nls(sbi->options->nls_name); - if (IS_ERR(sbi->options->nls)) { - sbi->options->nls = NULL; - errorf(fc, "Cannot load nls %s", sbi->options->nls_name); + options->nls = ntfs_load_nls(options->nls_name); + if (IS_ERR(options->nls)) { + options->nls = NULL; + errorf(fc, "Cannot load nls %s", options->nls_name); err = -EINVAL; goto out; } @@ -980,8 +997,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ref.seq = cpu_to_le16(MFT_REC_VOL); inode = ntfs_iget5(sb, &ref, &NAME_VOLUME); if (IS_ERR(inode)) { - ntfs_err(sb, "Failed to load $Volume."); err = PTR_ERR(inode); + ntfs_err(sb, "Failed to load $Volume (%d).", err); goto out; } @@ -1007,13 +1024,9 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) } attr = ni_find_attr(ni, attr, NULL, ATTR_VOL_INFO, NULL, 0, NULL, NULL); - if (!attr || is_attr_ext(attr)) { - err = -EINVAL; - goto put_inode_out; - } - - info = resident_data_ex(attr, SIZEOF_ATTRIBUTE_VOLUME_INFO); - if (!info) { + if (!attr || is_attr_ext(attr) || + !(info = resident_data_ex(attr, SIZEOF_ATTRIBUTE_VOLUME_INFO))) { + ntfs_err(sb, "$Volume is corrupted."); err = -EINVAL; goto put_inode_out; } @@ -1028,13 +1041,13 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ref.seq = cpu_to_le16(MFT_REC_MIRR); inode = ntfs_iget5(sb, &ref, &NAME_MIRROR); if (IS_ERR(inode)) { - ntfs_err(sb, "Failed to load $MFTMirr."); err = PTR_ERR(inode); + ntfs_err(sb, "Failed to load $MFTMirr (%d).", err); goto out; } - sbi->mft.recs_mirr = - ntfs_up_cluster(sbi, inode->i_size) >> sbi->record_bits; + sbi->mft.recs_mirr = ntfs_up_cluster(sbi, inode->i_size) >> + sbi->record_bits; iput(inode); @@ -1043,8 +1056,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ref.seq = cpu_to_le16(MFT_REC_LOG); inode = ntfs_iget5(sb, &ref, &NAME_LOGFILE); if (IS_ERR(inode)) { - ntfs_err(sb, "Failed to load \x24LogFile."); err = PTR_ERR(inode); + ntfs_err(sb, "Failed to load \x24LogFile (%d).", err); goto out; } @@ -1064,7 +1077,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) goto out; } } else if (sbi->volume.flags & VOLUME_FLAG_DIRTY) { - if (!sb_rdonly(sb) && !sbi->options->force) { + if (!sb_rdonly(sb) && !options->force) { ntfs_warn( sb, "volume is dirty and \"force\" flag is not set!"); @@ -1079,8 +1092,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) inode = ntfs_iget5(sb, &ref, &NAME_MFT); if (IS_ERR(inode)) { - ntfs_err(sb, "Failed to load $MFT."); err = PTR_ERR(inode); + ntfs_err(sb, "Failed to load $MFT (%d).", err); goto out; } @@ -1095,8 +1108,10 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) goto put_inode_out; err = ni_load_all_mi(ni); - if (err) + if (err) { + ntfs_err(sb, "Failed to load $MFT's subrecords (%d).", err); goto put_inode_out; + } sbi->mft.ni = ni; @@ -1105,8 +1120,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ref.seq = cpu_to_le16(MFT_REC_BITMAP); inode = ntfs_iget5(sb, &ref, &NAME_BITMAP); if (IS_ERR(inode)) { - ntfs_err(sb, "Failed to load $Bitmap."); err = PTR_ERR(inode); + ntfs_err(sb, "Failed to load $Bitmap (%d).", err); goto out; } @@ -1120,20 +1135,25 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) /* Check bitmap boundary. */ tt = sbi->used.bitmap.nbits; if (inode->i_size < bitmap_size(tt)) { + ntfs_err(sb, "$Bitmap is corrupted."); err = -EINVAL; goto put_inode_out; } err = wnd_init(&sbi->used.bitmap, sb, tt); - if (err) + if (err) { + ntfs_err(sb, "Failed to initialize $Bitmap (%d).", err); goto put_inode_out; + } iput(inode); /* Compute the MFT zone. */ err = ntfs_refresh_zone(sbi); - if (err) + if (err) { + ntfs_err(sb, "Failed to initialize MFT zone (%d).", err); goto out; + } /* Load $BadClus. */ ref.low = cpu_to_le32(MFT_REC_BADCLUST); @@ -1178,8 +1198,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ref.seq = cpu_to_le16(MFT_REC_ATTR); inode = ntfs_iget5(sb, &ref, &NAME_ATTRDEF); if (IS_ERR(inode)) { - ntfs_err(sb, "Failed to load $AttrDef -> %d", err); err = PTR_ERR(inode); + ntfs_err(sb, "Failed to load $AttrDef (%d)", err); goto out; } @@ -1208,6 +1228,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) if (IS_ERR(page)) { err = PTR_ERR(page); + ntfs_err(sb, "Failed to read $AttrDef (%d).", err); goto put_inode_out; } memcpy(Add2Ptr(t, done), page_address(page), @@ -1215,6 +1236,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ntfs_unmap_page(page); if (!idx && ATTR_STD != t->type) { + ntfs_err(sb, "$AttrDef is corrupted."); err = -EINVAL; goto put_inode_out; } @@ -1249,13 +1271,14 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ref.seq = cpu_to_le16(MFT_REC_UPCASE); inode = ntfs_iget5(sb, &ref, &NAME_UPCASE); if (IS_ERR(inode)) { - ntfs_err(sb, "Failed to load $UpCase."); err = PTR_ERR(inode); + ntfs_err(sb, "Failed to load $UpCase (%d).", err); goto out; } if (inode->i_size != 0x10000 * sizeof(short)) { err = -EINVAL; + ntfs_err(sb, "$UpCase is corrupted."); goto put_inode_out; } @@ -1266,6 +1289,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) if (IS_ERR(page)) { err = PTR_ERR(page); + ntfs_err(sb, "Failed to read $UpCase (%d).", err); goto put_inode_out; } @@ -1291,23 +1315,31 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) if (is_ntfs3(sbi)) { /* Load $Secure. */ err = ntfs_security_init(sbi); - if (err) + if (err) { + ntfs_err(sb, "Failed to initialize $Secure (%d).", err); goto out; + } /* Load $Extend. */ err = ntfs_extend_init(sbi); - if (err) + if (err) { + ntfs_warn(sb, "Failed to initialize $Extend."); goto load_root; + } - /* Load $Extend\$Reparse. */ + /* Load $Extend/$Reparse. */ err = ntfs_reparse_init(sbi); - if (err) + if (err) { + ntfs_warn(sb, "Failed to initialize $Extend/$Reparse."); goto load_root; + } - /* Load $Extend\$ObjId. */ + /* Load $Extend/$ObjId. */ err = ntfs_objid_init(sbi); - if (err) + if (err) { + ntfs_warn(sb, "Failed to initialize $Extend/$ObjId."); goto load_root; + } } load_root: @@ -1316,8 +1348,8 @@ load_root: ref.seq = cpu_to_le16(MFT_REC_ROOT); inode = ntfs_iget5(sb, &ref, &NAME_ROOT); if (IS_ERR(inode) || !inode->i_op) { - ntfs_err(sb, "Failed to load root."); - err = IS_ERR(inode) ? PTR_ERR(inode) : -EINVAL; + err = PTR_ERR(inode); + ntfs_err(sb, "Failed to load root (%d).", err); goto out; } -- cgit From 788ee1605c2e9feed39c3a749fb3e47c6e15c1b9 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Mon, 20 Feb 2023 09:39:35 +0400 Subject: fs/ntfs3: Fix root inode checking Separate checking inode->i_op and inode itself. Reported-by: kernel test robot Reported-by: Dan Carpenter Link: https://lore.kernel.org/r/202302162319.bDJOuyfy-lkp@intel.com/ Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index e0f78b306f15..5158dd31fd97 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -1347,12 +1347,21 @@ load_root: ref.low = cpu_to_le32(MFT_REC_ROOT); ref.seq = cpu_to_le16(MFT_REC_ROOT); inode = ntfs_iget5(sb, &ref, &NAME_ROOT); - if (IS_ERR(inode) || !inode->i_op) { + if (IS_ERR(inode)) { err = PTR_ERR(inode); ntfs_err(sb, "Failed to load root (%d).", err); goto out; } + /* + * Final check. Looks like this case should never occurs. + */ + if (!inode->i_op) { + err = -EINVAL; + ntfs_err(sb, "Failed to load root (%d).", err); + goto put_inode_out; + } + sb->s_root = d_make_root(inode); if (!sb->s_root) { err = -ENOMEM; -- cgit