* [syzbot] [udf?] KASAN: slab-out-of-bounds Read in udf_get_filelongad (2)
@ 2024-09-03 9:55 syzbot
2024-09-10 7:28 ` Zhao Mengmeng
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: syzbot @ 2024-09-03 9:55 UTC (permalink / raw)
To: jack, linux-kernel, syzkaller-bugs
Hello,
syzbot found the following issue on:
HEAD commit: 67784a74e258 Merge tag 'ata-6.11-rc7' of git://git.kernel...
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=14eb2b0b980000
kernel config: https://syzkaller.appspot.com/x/.config?x=660f6eb11f9c7dc5
dashboard link: https://syzkaller.appspot.com/bug?extid=7a4842f0b1801230a989
compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=10f2ea63980000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=13608f33980000
Downloadable assets:
disk image (non-bootable): https://storage.googleapis.com/syzbot-assets/7bc7510fe41f/non_bootable_disk-67784a74.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/e2f2583cf0b1/vmlinux-67784a74.xz
kernel image: https://storage.googleapis.com/syzbot-assets/0fedd864addd/bzImage-67784a74.xz
mounted in repro: https://storage.googleapis.com/syzbot-assets/0604f67569f1/mount_0.gz
IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+7a4842f0b1801230a989@syzkaller.appspotmail.com
loop0: rw=0, sector=117, nr_sectors = 1 limit=0
syz-executor135: attempt to access beyond end of device
loop0: rw=0, sector=117, nr_sectors = 1 limit=0
==================================================================
BUG: KASAN: slab-out-of-bounds in udf_get_filelongad+0x167/0x1b0 fs/udf/directory.c:526
Read of size 4 at addr ffff888012113f30 by task syz-executor135/5106
CPU: 0 UID: 0 PID: 5106 Comm: syz-executor135 Not tainted 6.11.0-rc6-syzkaller-00019-g67784a74e258 #0
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:93 [inline]
dump_stack_lvl+0x241/0x360 lib/dump_stack.c:119
print_address_description mm/kasan/report.c:377 [inline]
print_report+0x169/0x550 mm/kasan/report.c:488
kasan_report+0x143/0x180 mm/kasan/report.c:601
udf_get_filelongad+0x167/0x1b0 fs/udf/directory.c:526
udf_current_aext+0x435/0x9e0 fs/udf/inode.c:2235
udf_next_aext+0x8c/0x4a0 fs/udf/inode.c:2171
udf_extend_file fs/udf/inode.c:677 [inline]
udf_setsize+0xa8a/0x1280 fs/udf/inode.c:1265
udf_setattr+0x3c7/0x5d0 fs/udf/file.c:236
notify_change+0xbca/0xe90 fs/attr.c:503
do_truncate fs/open.c:65 [inline]
do_ftruncate+0x46b/0x590 fs/open.c:181
do_sys_ftruncate fs/open.c:199 [inline]
__do_sys_ftruncate fs/open.c:207 [inline]
__se_sys_ftruncate fs/open.c:205 [inline]
__x64_sys_ftruncate+0x95/0xf0 fs/open.c:205
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f13639ac249
Code: 28 00 00 00 75 05 48 83 c4 28 c3 e8 f1 17 00 00 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007fff0302d508 EFLAGS: 00000246 ORIG_RAX: 000000000000004d
RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f13639ac249
RDX: 00007f13639ac249 RSI: 0000008002007ffb RDI: 0000000000000005
RBP: 00000000000013f1 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 00007fff0302d550
R13: 00007fff0302d630 R14: 431bde82d7b634db R15: 00007f13639f501d
</TASK>
Allocated by task 5061:
kasan_save_stack mm/kasan/common.c:47 [inline]
kasan_save_track+0x3f/0x80 mm/kasan/common.c:68
poison_kmalloc_redzone mm/kasan/common.c:370 [inline]
__kasan_kmalloc+0x98/0xb0 mm/kasan/common.c:387
kasan_kmalloc include/linux/kasan.h:211 [inline]
__do_kmalloc_node mm/slub.c:4158 [inline]
__kmalloc_node_track_caller_noprof+0x225/0x440 mm/slub.c:4177
kmalloc_reserve+0x111/0x2a0 net/core/skbuff.c:605
pskb_expand_head+0x202/0x1390 net/core/skbuff.c:2259
__skb_pad+0x329/0x5c0 net/core/skbuff.c:2537
__skb_put_padto include/linux/skbuff.h:3720 [inline]
skb_put_padto include/linux/skbuff.h:3739 [inline]
eth_skb_pad include/linux/etherdevice.h:656 [inline]
e1000_xmit_frame+0x3938/0x5130 drivers/net/ethernet/intel/e1000/e1000_main.c:3123
__netdev_start_xmit include/linux/netdevice.h:4913 [inline]
netdev_start_xmit include/linux/netdevice.h:4922 [inline]
xmit_one net/core/dev.c:3580 [inline]
dev_hard_start_xmit+0x27a/0x7e0 net/core/dev.c:3596
sch_direct_xmit+0x2b6/0x5f0 net/sched/sch_generic.c:343
__dev_xmit_skb net/core/dev.c:3809 [inline]
__dev_queue_xmit+0x1a7f/0x3e90 net/core/dev.c:4389
dev_queue_xmit include/linux/netdevice.h:3105 [inline]
neigh_hh_output include/net/neighbour.h:526 [inline]
neigh_output include/net/neighbour.h:540 [inline]
ip_finish_output2+0xd41/0x1390 net/ipv4/ip_output.c:235
ip_local_out net/ipv4/ip_output.c:129 [inline]
__ip_queue_xmit+0x118c/0x1b80 net/ipv4/ip_output.c:535
__tcp_transmit_skb+0x2544/0x3b30 net/ipv4/tcp_output.c:1466
tcp_cleanup_rbuf net/ipv4/tcp.c:1513 [inline]
tcp_recvmsg_locked+0x1d00/0x2640 net/ipv4/tcp.c:2563
tcp_recvmsg+0x25d/0x920 net/ipv4/tcp.c:2593
inet_recvmsg+0x150/0x2d0 net/ipv4/af_inet.c:885
sock_recvmsg_nosec net/socket.c:1046 [inline]
sock_recvmsg+0x1ae/0x280 net/socket.c:1068
sock_read_iter+0x2ca/0x3e0 net/socket.c:1138
new_sync_read fs/read_write.c:395 [inline]
vfs_read+0x9bd/0xbc0 fs/read_write.c:476
ksys_read+0x1a0/0x2c0 fs/read_write.c:619
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Freed by task 5061:
kasan_save_stack mm/kasan/common.c:47 [inline]
kasan_save_track+0x3f/0x80 mm/kasan/common.c:68
kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:579
poison_slab_object+0xe0/0x150 mm/kasan/common.c:240
__kasan_slab_free+0x37/0x60 mm/kasan/common.c:256
kasan_slab_free include/linux/kasan.h:184 [inline]
slab_free_hook mm/slub.c:2252 [inline]
slab_free mm/slub.c:4473 [inline]
kfree+0x149/0x360 mm/slub.c:4594
skb_kfree_head net/core/skbuff.c:1084 [inline]
skb_free_head net/core/skbuff.c:1096 [inline]
skb_release_data+0x676/0x880 net/core/skbuff.c:1123
skb_release_all net/core/skbuff.c:1188 [inline]
napi_consume_skb+0x146/0x1f0 net/core/skbuff.c:1508
e1000_unmap_and_free_tx_resource drivers/net/ethernet/intel/e1000/e1000_main.c:1967 [inline]
e1000_clean_tx_irq drivers/net/ethernet/intel/e1000/e1000_main.c:3857 [inline]
e1000_clean+0x518/0x3ec0 drivers/net/ethernet/intel/e1000/e1000_main.c:3798
__napi_poll+0xcb/0x490 net/core/dev.c:6772
napi_poll net/core/dev.c:6841 [inline]
net_rx_action+0x89b/0x1240 net/core/dev.c:6963
handle_softirqs+0x2c4/0x970 kernel/softirq.c:554
do_softirq+0x11b/0x1e0 kernel/softirq.c:455
__local_bh_enable_ip+0x1bb/0x200 kernel/softirq.c:382
local_bh_enable include/linux/bottom_half.h:33 [inline]
rcu_read_unlock_bh include/linux/rcupdate.h:908 [inline]
__dev_queue_xmit+0x1763/0x3e90 net/core/dev.c:4450
dev_queue_xmit include/linux/netdevice.h:3105 [inline]
neigh_hh_output include/net/neighbour.h:526 [inline]
neigh_output include/net/neighbour.h:540 [inline]
ip_finish_output2+0xd41/0x1390 net/ipv4/ip_output.c:235
ip_local_out net/ipv4/ip_output.c:129 [inline]
__ip_queue_xmit+0x118c/0x1b80 net/ipv4/ip_output.c:535
__tcp_transmit_skb+0x2544/0x3b30 net/ipv4/tcp_output.c:1466
tcp_cleanup_rbuf net/ipv4/tcp.c:1513 [inline]
tcp_recvmsg_locked+0x1d00/0x2640 net/ipv4/tcp.c:2563
tcp_recvmsg+0x25d/0x920 net/ipv4/tcp.c:2593
inet_recvmsg+0x150/0x2d0 net/ipv4/af_inet.c:885
sock_recvmsg_nosec net/socket.c:1046 [inline]
sock_recvmsg+0x1ae/0x280 net/socket.c:1068
sock_read_iter+0x2ca/0x3e0 net/socket.c:1138
new_sync_read fs/read_write.c:395 [inline]
vfs_read+0x9bd/0xbc0 fs/read_write.c:476
ksys_read+0x1a0/0x2c0 fs/read_write.c:619
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x77/0x7f
The buggy address belongs to the object at ffff888012113800
which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 816 bytes to the right of
allocated 1024-byte region [ffff888012113800, ffff888012113c00)
The buggy address belongs to the physical page:
page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x12110
head: order:2 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0xfff00000000040(head|node=0|zone=1|lastcpupid=0x7ff)
page_type: 0xfdffffff(slab)
raw: 00fff00000000040 ffff88801ac41dc0 dead000000000122 0000000000000000
raw: 0000000000000000 0000000000080008 00000001fdffffff 0000000000000000
head: 00fff00000000040 ffff88801ac41dc0 dead000000000122 0000000000000000
head: 0000000000000000 0000000000080008 00000001fdffffff 0000000000000000
head: 00fff00000000002 ffffea0000484401 ffffffffffffffff 0000000000000000
head: ffff888000000004 0000000000000000 00000000ffffffff 0000000000000000
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 2, migratetype Unmovable, gfp_mask 0xd2820(GFP_ATOMIC|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 5061, tgid 5061 (sshd), ts 83597267288, free_ts 71025249904
set_page_owner include/linux/page_owner.h:32 [inline]
post_alloc_hook+0x1f3/0x230 mm/page_alloc.c:1493
prep_new_page mm/page_alloc.c:1501 [inline]
get_page_from_freelist+0x2e4c/0x2f10 mm/page_alloc.c:3439
__alloc_pages_noprof+0x256/0x6c0 mm/page_alloc.c:4695
__alloc_pages_node_noprof include/linux/gfp.h:269 [inline]
alloc_pages_node_noprof include/linux/gfp.h:296 [inline]
alloc_slab_page+0x5f/0x120 mm/slub.c:2321
allocate_slab+0x5a/0x2f0 mm/slub.c:2484
new_slab mm/slub.c:2537 [inline]
___slab_alloc+0xcd1/0x14b0 mm/slub.c:3723
__slab_alloc+0x58/0xa0 mm/slub.c:3813
__slab_alloc_node mm/slub.c:3866 [inline]
slab_alloc_node mm/slub.c:4025 [inline]
__do_kmalloc_node mm/slub.c:4157 [inline]
__kmalloc_node_track_caller_noprof+0x281/0x440 mm/slub.c:4177
kmalloc_reserve+0x111/0x2a0 net/core/skbuff.c:605
pskb_expand_head+0x202/0x1390 net/core/skbuff.c:2259
__skb_pad+0x329/0x5c0 net/core/skbuff.c:2537
__skb_put_padto include/linux/skbuff.h:3720 [inline]
skb_put_padto include/linux/skbuff.h:3739 [inline]
eth_skb_pad include/linux/etherdevice.h:656 [inline]
e1000_xmit_frame+0x3938/0x5130 drivers/net/ethernet/intel/e1000/e1000_main.c:3123
__netdev_start_xmit include/linux/netdevice.h:4913 [inline]
netdev_start_xmit include/linux/netdevice.h:4922 [inline]
xmit_one net/core/dev.c:3580 [inline]
dev_hard_start_xmit+0x27a/0x7e0 net/core/dev.c:3596
sch_direct_xmit+0x2b6/0x5f0 net/sched/sch_generic.c:343
__dev_xmit_skb net/core/dev.c:3809 [inline]
__dev_queue_xmit+0x1a7f/0x3e90 net/core/dev.c:4389
dev_queue_xmit include/linux/netdevice.h:3105 [inline]
neigh_hh_output include/net/neighbour.h:526 [inline]
neigh_output include/net/neighbour.h:540 [inline]
ip_finish_output2+0xd41/0x1390 net/ipv4/ip_output.c:235
page last free pid 8 tgid 8 stack trace:
reset_page_owner include/linux/page_owner.h:25 [inline]
free_pages_prepare mm/page_alloc.c:1094 [inline]
free_unref_page+0xd22/0xea0 mm/page_alloc.c:2612
vfree+0x186/0x2e0 mm/vmalloc.c:3364
delayed_vfree_work+0x56/0x80 mm/vmalloc.c:3285
process_one_work kernel/workqueue.c:3231 [inline]
process_scheduled_works+0xa2c/0x1830 kernel/workqueue.c:3312
worker_thread+0x86d/0xd10 kernel/workqueue.c:3389
kthread+0x2f0/0x390 kernel/kthread.c:389
ret_from_fork+0x4b/0x80 arch/x86/kernel/process.c:147
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:244
Memory state around the buggy address:
ffff888012113e00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff888012113e80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff888012113f00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
^
ffff888012113f80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff888012114000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
==================================================================
---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.
syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title
If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.
If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)
If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report
If you want to undo deduplication, reply with:
#syz undup
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [syzbot] [udf?] KASAN: slab-out-of-bounds Read in udf_get_filelongad (2) 2024-09-03 9:55 [syzbot] [udf?] KASAN: slab-out-of-bounds Read in udf_get_filelongad (2) syzbot @ 2024-09-10 7:28 ` Zhao Mengmeng 2024-09-10 7:43 ` syzbot 2024-09-11 9:44 ` [syzbot] " syzbot 2024-09-30 23:50 ` Zhao Mengmeng 2 siblings, 1 reply; 10+ messages in thread From: Zhao Mengmeng @ 2024-09-10 7:28 UTC (permalink / raw) To: syzbot+7a4842f0b1801230a989; +Cc: jack, linux-kernel, syzkaller-bugs [-- Attachment #1: Type: text/plain, Size: 9 bytes --] #syz test [-- Attachment #2: test.patch --] [-- Type: text/x-patch, Size: 607 bytes --] diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 4726a4d014b6..350962bfc71f 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -666,7 +666,7 @@ static int udf_extend_file(struct inode *inode, loff_t newsize) elen > ((loff_t)offset + 1) << inode->i_blkbits); if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) || - (epos.bh && epos.offset == sizeof(struct allocExtDesc))) { + (epos.offset == sizeof(struct allocExtDesc))) { /* File has no extents at all or has empty last * indirect extent! Create a fake extent... */ extent.extLocation.logicalBlockNum = 0; ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [syzbot] [udf?] KASAN: slab-out-of-bounds Read in udf_get_filelongad (2) 2024-09-10 7:28 ` Zhao Mengmeng @ 2024-09-10 7:43 ` syzbot 2024-09-18 8:53 ` Zhao Mengmeng 0 siblings, 1 reply; 10+ messages in thread From: syzbot @ 2024-09-10 7:43 UTC (permalink / raw) To: jack, linux-kernel, syzkaller-bugs, zhaomengmeng Hello, syzbot has tested the proposed patch but the reproducer is still triggering an issue: WARNING in __udf_add_aext loop0: rw=0, sector=117, nr_sectors = 1 limit=0 syz.0.15: attempt to access beyond end of device loop0: rw=0, sector=117, nr_sectors = 1 limit=0 ------------[ cut here ]------------ WARNING: CPU: 0 PID: 5602 at fs/udf/inode.c:2043 __udf_add_aext+0x571/0x700 fs/udf/inode.c:2042 Modules linked in: CPU: 0 UID: 0 PID: 5602 Comm: syz.0.15 Not tainted 6.11.0-rc7-syzkaller-gbc83b4d1f086-dirty #0 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014 RIP: 0010:__udf_add_aext+0x571/0x700 fs/udf/inode.c:2042 Code: 41 5f 5d c3 cc cc cc cc e8 5c d7 74 fe 90 0f 0b 90 e9 e7 fb ff ff e8 4e d7 74 fe 90 0f 0b 90 e9 54 fc ff ff e8 40 d7 74 fe 90 <0f> 0b 90 e9 45 fd ff ff 44 89 f9 80 e1 07 80 c1 03 38 c1 0f 8c c7 RSP: 0018:ffffc900026b78f8 EFLAGS: 00010293 RAX: ffffffff831eb570 RBX: 0000000000000120 RCX: ffff888000990000 RDX: 0000000000000000 RSI: 0000000000000120 RDI: ffffffffffffff40 RBP: 00000000bffffe00 R08: ffffffff831eb2b0 R09: ffffffff831eb066 R10: 0000000000000002 R11: ffff888000990000 R12: ffffc900026b7b80 R13: ffffffffffffff40 R14: dffffc0000000000 R15: 0000000000000010 FS: 00007f2deb03b6c0(0000) GS:ffff88801fe00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fa084b2c000 CR3: 0000000054cbe000 CR4: 0000000000350ef0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: <TASK> udf_add_aext fs/udf/inode.c:2104 [inline] udf_do_extend_file+0xaf7/0x11e0 fs/udf/inode.c:540 udf_extend_file fs/udf/inode.c:692 [inline] udf_setsize+0xcc2/0x1320 fs/udf/inode.c:1265 udf_setattr+0x3c7/0x5d0 fs/udf/file.c:236 notify_change+0xbca/0xe90 fs/attr.c:503 do_truncate fs/open.c:65 [inline] do_ftruncate+0x46b/0x590 fs/open.c:181 do_sys_ftruncate fs/open.c:199 [inline] __do_sys_ftruncate fs/open.c:207 [inline] __se_sys_ftruncate fs/open.c:205 [inline] __x64_sys_ftruncate+0x95/0xf0 fs/open.c:205 do_syscall_x64 arch/x86/entry/common.c:52 [inline] do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f2dea179eb9 Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007f2deb03b038 EFLAGS: 00000246 ORIG_RAX: 000000000000004d RAX: ffffffffffffffda RBX: 00007f2dea315f80 RCX: 00007f2dea179eb9 RDX: 0000000000000000 RSI: 0000008002007ffb RDI: 0000000000000005 RBP: 00007f2dea1e793e R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 0000000000000000 R14: 00007f2dea315f80 R15: 00007ffec4d97f58 </TASK> Tested on: commit: bc83b4d1 Merge tag 'bcachefs-2024-09-09' of git://evil.. git tree: upstream console output: https://syzkaller.appspot.com/x/log.txt?x=10303f29980000 kernel config: https://syzkaller.appspot.com/x/.config?x=61d235cb8d15001c dashboard link: https://syzkaller.appspot.com/bug?extid=7a4842f0b1801230a989 compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40 patch: https://syzkaller.appspot.com/x/patch.diff?x=1686f43b980000 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [syzbot] [udf?] KASAN: slab-out-of-bounds Read in udf_get_filelongad (2) 2024-09-10 7:43 ` syzbot @ 2024-09-18 8:53 ` Zhao Mengmeng 2024-09-18 9:15 ` syzbot 0 siblings, 1 reply; 10+ messages in thread From: Zhao Mengmeng @ 2024-09-18 8:53 UTC (permalink / raw) To: syzbot+7a4842f0b1801230a989 Cc: jack, linux-kernel, syzkaller-bugs, zhaomengmeng [-- Attachment #1: Type: text/plain, Size: 88 bytes --] #syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 67784a74e258 [-- Attachment #2: test.patch --] [-- Type: text/x-patch, Size: 20414 bytes --] diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index d8fc11765d61..b216c43cf433 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c @@ -384,7 +384,7 @@ static void udf_table_free_blocks(struct super_block *sb, epos.bh = oepos.bh = NULL; while (count && - (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) { + !udf_next_aext(table, &epos, &eloc, &elen, &etype, 1)) { if (((eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) == start)) { if ((0x3FFFFFFF - elen) < @@ -517,7 +517,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb, eloc.logicalBlockNum = 0xFFFFFFFF; while (first_block != eloc.logicalBlockNum && - (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) { + !udf_next_aext(table, &epos, &eloc, &elen, &etype, 1)) { udf_debug("eloc=%u, elen=%u, first_block=%u\n", eloc.logicalBlockNum, elen, first_block); ; /* empty loop body */ @@ -584,7 +584,7 @@ static udf_pblk_t udf_table_new_block(struct super_block *sb, epos.bh = goal_epos.bh = NULL; while (spread && - (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) { + !udf_next_aext(table, &epos, &eloc, &elen, &etype, 1)) { if (goal >= eloc.logicalBlockNum) { if (goal < eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) diff --git a/fs/udf/directory.c b/fs/udf/directory.c index 93153665eb37..cb40e1ade9f6 100644 --- a/fs/udf/directory.c +++ b/fs/udf/directory.c @@ -166,13 +166,16 @@ static struct buffer_head *udf_fiiter_bread_blk(struct udf_fileident_iter *iter) */ static int udf_fiiter_advance_blk(struct udf_fileident_iter *iter) { + int8_t etype; + int err = 0; iter->loffset++; if (iter->loffset < DIV_ROUND_UP(iter->elen, 1<<iter->dir->i_blkbits)) return 0; iter->loffset = 0; - if (udf_next_aext(iter->dir, &iter->epos, &iter->eloc, &iter->elen, 1) - != (EXT_RECORDED_ALLOCATED >> 30)) { + err = udf_next_aext(iter->dir, &iter->epos, &iter->eloc, &iter->elen, + &etype, 1); + if (err || etype != (EXT_RECORDED_ALLOCATED >> 30)) { if (iter->pos == iter->dir->i_size) { iter->elen = 0; return 0; @@ -240,6 +243,7 @@ int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir, { struct udf_inode_info *iinfo = UDF_I(dir); int err = 0; + int8_t etype; iter->dir = dir; iter->bh[0] = iter->bh[1] = NULL; @@ -259,9 +263,9 @@ int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir, goto out; } - if (inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos, - &iter->eloc, &iter->elen, &iter->loffset) != - (EXT_RECORDED_ALLOCATED >> 30)) { + err = inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos, &iter->eloc, + &iter->elen, &iter->loffset, &etype); + if (err || etype != (EXT_RECORDED_ALLOCATED >> 30)) { if (pos == dir->i_size) return 0; udf_err(dir->i_sb, @@ -457,6 +461,7 @@ int udf_fiiter_append_blk(struct udf_fileident_iter *iter) sector_t block; uint32_t old_elen = iter->elen; int err; + int8_t etype; if (WARN_ON_ONCE(iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)) return -EINVAL; @@ -471,8 +476,9 @@ int udf_fiiter_append_blk(struct udf_fileident_iter *iter) udf_fiiter_update_elen(iter, old_elen); return err; } - if (inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen, - &iter->loffset) != (EXT_RECORDED_ALLOCATED >> 30)) { + err = inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen, + &iter->loffset, &etype); + if (err || etype != (EXT_RECORDED_ALLOCATED >> 30)) { udf_err(iter->dir->i_sb, "block %llu not allocated in directory (ino %lu)\n", (unsigned long long)block, iter->dir->i_ino); diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 4726a4d014b6..f1b8f0a0d202 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -418,10 +418,11 @@ static int udf_map_block(struct inode *inode, struct udf_map_rq *map) uint32_t elen; sector_t offset; struct extent_position epos = {}; + int8_t etype; down_read(&iinfo->i_data_sem); - if (inode_bmap(inode, map->lblk, &epos, &eloc, &elen, &offset) - == (EXT_RECORDED_ALLOCATED >> 30)) { + inode_bmap(inode, map->lblk, &epos, &eloc, &elen, &offset, &etype); + if (etype == (EXT_RECORDED_ALLOCATED >> 30)) { map->pblk = udf_get_lb_pblock(inode->i_sb, &eloc, offset); map->oflags |= UDF_BLK_MAPPED; @@ -545,6 +546,7 @@ static int udf_do_extend_file(struct inode *inode, } else { struct kernel_lb_addr tmploc; uint32_t tmplen; + int8_t tmptype; udf_write_aext(inode, last_pos, &last_ext->extLocation, last_ext->extLength, 1); @@ -555,7 +557,7 @@ static int udf_do_extend_file(struct inode *inode, * empty indirect extent. */ if (new_block_bytes) - udf_next_aext(inode, last_pos, &tmploc, &tmplen, 0); + udf_next_aext(inode, last_pos, &tmploc, &tmplen, &tmptype, 0); } iinfo->i_lenExtents += add; @@ -659,8 +661,10 @@ static int udf_extend_file(struct inode *inode, loff_t newsize) */ udf_discard_prealloc(inode); - etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset); - within_last_ext = (etype != -1); + err = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset, &etype); + if (err < 0 && err != -ENODATA) + goto out; + within_last_ext = (!err); /* We don't expect extents past EOF... */ WARN_ON_ONCE(within_last_ext && elen > ((loff_t)offset + 1) << inode->i_blkbits); @@ -674,8 +678,8 @@ static int udf_extend_file(struct inode *inode, loff_t newsize) extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED; } else { epos.offset -= adsize; - etype = udf_next_aext(inode, &epos, &extent.extLocation, - &extent.extLength, 0); + udf_next_aext(inode, &epos, &extent.extLocation, + &extent.extLength, &etype, 0); extent.extLength |= etype << 30; } @@ -712,7 +716,7 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) loff_t lbcount = 0, b_off = 0; udf_pblk_t newblocknum; sector_t offset = 0; - int8_t etype; + int8_t etype, tmpetype; struct udf_inode_info *iinfo = UDF_I(inode); udf_pblk_t goal = 0, pgoal = iinfo->i_location.logicalBlockNum; int lastblock = 0; @@ -748,8 +752,8 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) prev_epos.offset = cur_epos.offset; cur_epos.offset = next_epos.offset; - etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 1); - if (etype == -1) + ret = udf_next_aext(inode, &next_epos, &eloc, &elen, &etype, 1); + if (ret) break; c = !c; @@ -771,8 +775,8 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) * Move prev_epos and cur_epos into indirect extent if we are at * the pointer to it */ - udf_next_aext(inode, &prev_epos, &tmpeloc, &tmpelen, 0); - udf_next_aext(inode, &cur_epos, &tmpeloc, &tmpelen, 0); + udf_next_aext(inode, &prev_epos, &tmpeloc, &tmpelen, &tmpetype, 0); + udf_next_aext(inode, &cur_epos, &tmpeloc, &tmpelen, &tmpetype, 0); /* if the extent is allocated and recorded, return the block if the extent is not a multiple of the blocksize, round up */ @@ -793,7 +797,7 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) } /* Are we beyond EOF and preallocated extent? */ - if (etype == -1) { + if (ret < 0) { loff_t hole_len; isBeyondEOF = true; @@ -846,8 +850,7 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) /* if the current block is located in an extent, read the next extent */ - etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0); - if (etype != -1) { + if (!udf_next_aext(inode, &next_epos, &eloc, &elen, &etype, 0)) { laarr[c + 1].extLength = (etype << 30) | elen; laarr[c + 1].extLocation = eloc; count++; @@ -1172,6 +1175,7 @@ static int udf_update_extents(struct inode *inode, struct kernel_long_ad *laarr, int start = 0, i; struct kernel_lb_addr tmploc; uint32_t tmplen; + int8_t tmptype; int err; if (startnum > endnum) { @@ -1190,13 +1194,13 @@ static int udf_update_extents(struct inode *inode, struct kernel_long_ad *laarr, if (err < 0) return err; udf_next_aext(inode, epos, &laarr[i].extLocation, - &laarr[i].extLength, 1); + &laarr[i].extLength, &tmptype, 1); start++; } } for (i = start; i < endnum; i++) { - udf_next_aext(inode, epos, &tmploc, &tmplen, 0); + udf_next_aext(inode, epos, &tmploc, &tmplen, &tmptype, 0); udf_write_aext(inode, epos, &laarr[i].extLocation, laarr[i].extLength, 1); } @@ -1955,6 +1959,7 @@ int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block, struct extent_position nepos; struct kernel_lb_addr neloc; int ver, adsize; + int err = 0; if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT) adsize = sizeof(struct short_ad); @@ -1999,10 +2004,12 @@ int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block, if (epos->offset + adsize > sb->s_blocksize) { struct kernel_lb_addr cp_loc; uint32_t cp_len; - int cp_type; + int8_t cp_type; epos->offset -= adsize; - cp_type = udf_current_aext(inode, epos, &cp_loc, &cp_len, 0); + err = udf_current_aext(inode, epos, &cp_loc, &cp_len, &cp_type, 0); + if (err < 0) + goto err_out; cp_len |= ((uint32_t)cp_type) << 30; __udf_add_aext(inode, &nepos, &cp_loc, cp_len, 1); @@ -2017,6 +2024,9 @@ int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block, *epos = nepos; return 0; +err_out: + brelse(epos->bh); + return err; } /* @@ -2162,21 +2172,24 @@ void udf_write_aext(struct inode *inode, struct extent_position *epos, */ #define UDF_MAX_INDIR_EXTS 16 -int8_t udf_next_aext(struct inode *inode, struct extent_position *epos, - struct kernel_lb_addr *eloc, uint32_t *elen, int inc) +int udf_next_aext(struct inode *inode, struct extent_position *epos, + struct kernel_lb_addr *eloc, uint32_t *elen, int8_t *etype, + int inc) { - int8_t etype; unsigned int indirections = 0; + int err = 0; + + while ((err = udf_current_aext(inode, epos, eloc, elen, etype, inc))) { + if (err || *etype != (EXT_NEXT_EXTENT_ALLOCDESCS >> 30)) + break; - while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) == - (EXT_NEXT_EXTENT_ALLOCDESCS >> 30)) { udf_pblk_t block; if (++indirections > UDF_MAX_INDIR_EXTS) { udf_err(inode->i_sb, "too many indirect extents in inode %lu\n", inode->i_ino); - return -1; + return -EFSCORRUPTED; } epos->block = *eloc; @@ -2186,18 +2199,18 @@ int8_t udf_next_aext(struct inode *inode, struct extent_position *epos, epos->bh = sb_bread(inode->i_sb, block); if (!epos->bh) { udf_debug("reading block %u failed!\n", block); - return -1; + return -EIO; } } - return etype; + return err; } -int8_t udf_current_aext(struct inode *inode, struct extent_position *epos, - struct kernel_lb_addr *eloc, uint32_t *elen, int inc) +int udf_current_aext(struct inode *inode, struct extent_position *epos, + struct kernel_lb_addr *eloc, uint32_t *elen, int8_t *etype, + int inc) { int alen; - int8_t etype; uint8_t *ptr; struct short_ad *sad; struct long_ad *lad; @@ -2224,8 +2237,8 @@ int8_t udf_current_aext(struct inode *inode, struct extent_position *epos, case ICBTAG_FLAG_AD_SHORT: sad = udf_get_fileshortad(ptr, alen, &epos->offset, inc); if (!sad) - return -1; - etype = le32_to_cpu(sad->extLength) >> 30; + return -ENODATA; + *etype = le32_to_cpu(sad->extLength) >> 30; eloc->logicalBlockNum = le32_to_cpu(sad->extPosition); eloc->partitionReferenceNum = iinfo->i_location.partitionReferenceNum; @@ -2234,17 +2247,17 @@ int8_t udf_current_aext(struct inode *inode, struct extent_position *epos, case ICBTAG_FLAG_AD_LONG: lad = udf_get_filelongad(ptr, alen, &epos->offset, inc); if (!lad) - return -1; - etype = le32_to_cpu(lad->extLength) >> 30; + return -ENODATA; + *etype = le32_to_cpu(lad->extLength) >> 30; *eloc = lelb_to_cpu(lad->extLocation); *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK; break; default: udf_debug("alloc_type = %u unsupported\n", iinfo->i_alloc_type); - return -1; + return -EINVAL; } - return etype; + return 0; } static int udf_insert_aext(struct inode *inode, struct extent_position epos, @@ -2258,7 +2271,7 @@ static int udf_insert_aext(struct inode *inode, struct extent_position epos, if (epos.bh) get_bh(epos.bh); - while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1) { + while (!udf_next_aext(inode, &epos, &oeloc, &oelen, &etype, 0)) { udf_write_aext(inode, &epos, &neloc, nelen, 1); neloc = oeloc; nelen = (etype << 30) | oelen; @@ -2293,10 +2306,10 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos) adsize = 0; oepos = epos; - if (udf_next_aext(inode, &epos, &eloc, &elen, 1) == -1) + if (udf_next_aext(inode, &epos, &eloc, &elen, &etype, 1)) return -1; - while ((etype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) { + while (!udf_next_aext(inode, &epos, &eloc, &elen, &etype, 1)) { udf_write_aext(inode, &oepos, &eloc, (etype << 30) | elen, 1); if (oepos.bh != epos.bh) { oepos.block = epos.block; @@ -2353,14 +2366,19 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos) return (elen >> 30); } -int8_t inode_bmap(struct inode *inode, sector_t block, - struct extent_position *pos, struct kernel_lb_addr *eloc, - uint32_t *elen, sector_t *offset) +/* + * return 0 when iudf_next_aext() loop success. + * return err < 0 and err != -ENODATA indicates error. + * return err == -ENODATA indicates hit EOF. + */ +int inode_bmap(struct inode *inode, sector_t block, struct extent_position *pos, + struct kernel_lb_addr *eloc, uint32_t *elen, sector_t *offset, + int8_t *etype) { unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; loff_t lbcount = 0, bcount = (loff_t) block << blocksize_bits; - int8_t etype; struct udf_inode_info *iinfo; + int err = 0; iinfo = UDF_I(inode); if (!udf_read_extent_cache(inode, bcount, &lbcount, pos)) { @@ -2370,11 +2388,11 @@ int8_t inode_bmap(struct inode *inode, sector_t block, } *elen = 0; do { - etype = udf_next_aext(inode, pos, eloc, elen, 1); - if (etype == -1) { + err = udf_next_aext(inode, pos, eloc, elen, etype, 1); + if (err < 0) { *offset = (bcount - lbcount) >> blocksize_bits; iinfo->i_lenExtents = lbcount; - return -1; + return err; } lbcount += *elen; } while (lbcount <= bcount); @@ -2382,5 +2400,5 @@ int8_t inode_bmap(struct inode *inode, sector_t block, udf_update_extent_cache(inode, lbcount - *elen, pos); *offset = (bcount + *elen - lbcount) >> blocksize_bits; - return etype; + return 0; } diff --git a/fs/udf/partition.c b/fs/udf/partition.c index af877991edc1..c441d4ae1f96 100644 --- a/fs/udf/partition.c +++ b/fs/udf/partition.c @@ -282,9 +282,11 @@ static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block, sector_t ext_offset; struct extent_position epos = {}; uint32_t phyblock; + int8_t etype; + int err = 0; - if (inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset) != - (EXT_RECORDED_ALLOCATED >> 30)) + err = inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset, &etype); + if (err || etype != (EXT_RECORDED_ALLOCATED >> 30)) phyblock = 0xFFFFFFFF; else { map = &UDF_SB(sb)->s_partmaps[partition]; diff --git a/fs/udf/super.c b/fs/udf/super.c index 3460ecc826d1..8c34224e1aee 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -2482,13 +2482,14 @@ static unsigned int udf_count_free_table(struct super_block *sb, uint32_t elen; struct kernel_lb_addr eloc; struct extent_position epos; + int8_t etype; mutex_lock(&UDF_SB(sb)->s_alloc_mutex); epos.block = UDF_I(table)->i_location; epos.offset = sizeof(struct unallocSpaceEntry); epos.bh = NULL; - while (udf_next_aext(table, &epos, &eloc, &elen, 1) != -1) + while (!udf_next_aext(table, &epos, &eloc, &elen, &etype, 1)) accum += (elen >> table->i_sb->s_blocksize_bits); brelse(epos.bh); diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c index a686c10fd709..a70b6ae4ab8a 100644 --- a/fs/udf/truncate.c +++ b/fs/udf/truncate.c @@ -85,7 +85,7 @@ void udf_truncate_tail_extent(struct inode *inode) BUG(); /* Find the last extent in the file */ - while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) { + while (!udf_next_aext(inode, &epos, &eloc, &elen, &netype, 1)) { etype = netype; lbcount += elen; if (lbcount > inode->i_size) { @@ -101,7 +101,7 @@ void udf_truncate_tail_extent(struct inode *inode) epos.offset -= adsize; extent_trunc(inode, &epos, &eloc, etype, elen, nelen); epos.offset += adsize; - if (udf_next_aext(inode, &epos, &eloc, &elen, 1) != -1) + if (!udf_next_aext(inode, &epos, &eloc, &elen, &netype, 1)) udf_err(inode->i_sb, "Extent after EOF in inode %u\n", (unsigned)inode->i_ino); @@ -132,13 +132,13 @@ void udf_discard_prealloc(struct inode *inode) epos.block = iinfo->i_location; /* Find the last extent in the file */ - while (udf_next_aext(inode, &epos, &eloc, &elen, 0) != -1) { + while (!udf_next_aext(inode, &epos, &eloc, &elen, &etype, 0)) { brelse(prev_epos.bh); prev_epos = epos; if (prev_epos.bh) get_bh(prev_epos.bh); - etype = udf_next_aext(inode, &epos, &eloc, &elen, 1); + udf_next_aext(inode, &epos, &eloc, &elen, &etype, 1); lbcount += elen; } if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) { @@ -188,6 +188,7 @@ int udf_truncate_extents(struct inode *inode) loff_t byte_offset; int adsize; struct udf_inode_info *iinfo = UDF_I(inode); + int err = 0; if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) adsize = sizeof(struct short_ad); @@ -196,10 +197,10 @@ int udf_truncate_extents(struct inode *inode) else BUG(); - etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset); + err = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset, &etype); byte_offset = (offset << sb->s_blocksize_bits) + (inode->i_size & (sb->s_blocksize - 1)); - if (etype == -1) { + if (err < 0) { /* We should extend the file? */ WARN_ON(byte_offset); return 0; @@ -217,8 +218,7 @@ int udf_truncate_extents(struct inode *inode) else lenalloc -= sizeof(struct allocExtDesc); - while ((etype = udf_current_aext(inode, &epos, &eloc, - &elen, 0)) != -1) { + while (!udf_current_aext(inode, &epos, &eloc, &elen, &etype, 0)) { if (etype == (EXT_NEXT_EXTENT_ALLOCDESCS >> 30)) { udf_write_aext(inode, &epos, &neloc, nelen, 0); if (indirect_ext_len) { diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 88692512a466..c9b1956157d3 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -157,8 +157,8 @@ extern struct buffer_head *udf_bread(struct inode *inode, udf_pblk_t block, extern int udf_setsize(struct inode *, loff_t); extern void udf_evict_inode(struct inode *); extern int udf_write_inode(struct inode *, struct writeback_control *wbc); -extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *, - struct kernel_lb_addr *, uint32_t *, sector_t *); +extern int inode_bmap(struct inode *, sector_t, struct extent_position *, + struct kernel_lb_addr *, uint32_t *, sector_t *, int8_t *); int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); extern int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block, struct extent_position *epos); @@ -169,10 +169,10 @@ extern int udf_add_aext(struct inode *, struct extent_position *, extern void udf_write_aext(struct inode *, struct extent_position *, struct kernel_lb_addr *, uint32_t, int); extern int8_t udf_delete_aext(struct inode *, struct extent_position); -extern int8_t udf_next_aext(struct inode *, struct extent_position *, - struct kernel_lb_addr *, uint32_t *, int); -extern int8_t udf_current_aext(struct inode *, struct extent_position *, - struct kernel_lb_addr *, uint32_t *, int); +extern int udf_next_aext(struct inode *, struct extent_position *, + struct kernel_lb_addr *, uint32_t *, int8_t *, int); +extern int udf_current_aext(struct inode *, struct extent_position *, + struct kernel_lb_addr *, uint32_t *, int8_t *, int); extern void udf_update_extra_perms(struct inode *inode, umode_t mode); /* misc.c */ ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [syzbot] [udf?] KASAN: slab-out-of-bounds Read in udf_get_filelongad (2) 2024-09-18 8:53 ` Zhao Mengmeng @ 2024-09-18 9:15 ` syzbot 2024-09-26 11:36 ` Zhao Mengmeng 0 siblings, 1 reply; 10+ messages in thread From: syzbot @ 2024-09-18 9:15 UTC (permalink / raw) To: jack, linux-kernel, syzkaller-bugs, zhaomengmeng, zhaomzhao Hello, syzbot has tested the proposed patch and the reproducer did not trigger any issue: Reported-by: syzbot+7a4842f0b1801230a989@syzkaller.appspotmail.com Tested-by: syzbot+7a4842f0b1801230a989@syzkaller.appspotmail.com Tested on: commit: 67784a74 Merge tag 'ata-6.11-rc7' of git://git.kernel... git tree: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git console output: https://syzkaller.appspot.com/x/log.txt?x=13a7bfc7980000 kernel config: https://syzkaller.appspot.com/x/.config?x=660f6eb11f9c7dc5 dashboard link: https://syzkaller.appspot.com/bug?extid=7a4842f0b1801230a989 compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40 patch: https://syzkaller.appspot.com/x/patch.diff?x=12939207980000 Note: testing is done by a robot and is best-effort only. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [syzbot] [udf?] KASAN: slab-out-of-bounds Read in udf_get_filelongad (2) 2024-09-18 9:15 ` syzbot @ 2024-09-26 11:36 ` Zhao Mengmeng 2024-09-26 12:03 ` syzbot 0 siblings, 1 reply; 10+ messages in thread From: Zhao Mengmeng @ 2024-09-26 11:36 UTC (permalink / raw) To: syzbot+7a4842f0b1801230a989 Cc: jack, linux-kernel, syzkaller-bugs, zhaomengmeng [-- Attachment #1: Type: text/plain, Size: 88 bytes --] #syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 67784a74e258 [-- Attachment #2: test.patch --] [-- Type: text/x-patch, Size: 26702 bytes --] diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index d8fc11765d61..99cf8fbc805e 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c @@ -370,6 +370,7 @@ static void udf_table_free_blocks(struct super_block *sb, struct extent_position oepos, epos; int8_t etype; struct udf_inode_info *iinfo; + int err = 0; mutex_lock(&sbi->s_alloc_mutex); iinfo = UDF_I(table); @@ -384,7 +385,7 @@ static void udf_table_free_blocks(struct super_block *sb, epos.bh = oepos.bh = NULL; while (count && - (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) { + !(err = udf_next_aext(table, &epos, &eloc, &elen, &etype, 1))) { if (((eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) == start)) { if ((0x3FFFFFFF - elen) < @@ -435,6 +436,9 @@ static void udf_table_free_blocks(struct super_block *sb, } } + if (UDF_EXT_ERR(err)) + goto error_return; + if (count) { /* * NOTE: we CANNOT use udf_add_aext here, as it can try to @@ -460,8 +464,6 @@ static void udf_table_free_blocks(struct super_block *sb, else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) adsize = sizeof(struct long_ad); else { - brelse(oepos.bh); - brelse(epos.bh); goto error_return; } @@ -479,10 +481,10 @@ static void udf_table_free_blocks(struct super_block *sb, __udf_add_aext(table, &epos, &eloc, elen, 1); } +error_return: brelse(epos.bh); brelse(oepos.bh); -error_return: mutex_unlock(&sbi->s_alloc_mutex); return; } @@ -498,6 +500,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb, struct extent_position epos; int8_t etype = -1; struct udf_inode_info *iinfo; + int err = 0; if (first_block >= sbi->s_partmaps[partition].s_partition_len) return 0; @@ -517,12 +520,15 @@ static int udf_table_prealloc_blocks(struct super_block *sb, eloc.logicalBlockNum = 0xFFFFFFFF; while (first_block != eloc.logicalBlockNum && - (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) { + !(err = udf_next_aext(table, &epos, &eloc, &elen, &etype, 1))) { udf_debug("eloc=%u, elen=%u, first_block=%u\n", eloc.logicalBlockNum, elen, first_block); ; /* empty loop body */ } + if (UDF_EXT_ERR(err)) + goto err_out; + if (first_block == eloc.logicalBlockNum) { epos.offset -= adsize; @@ -539,6 +545,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb, alloc_count = 0; } +err_out: brelse(epos.bh); if (alloc_count) @@ -560,6 +567,7 @@ static udf_pblk_t udf_table_new_block(struct super_block *sb, struct extent_position epos, goal_epos; int8_t etype; struct udf_inode_info *iinfo = UDF_I(table); + int ret = 0; *err = -ENOSPC; @@ -584,7 +592,7 @@ static udf_pblk_t udf_table_new_block(struct super_block *sb, epos.bh = goal_epos.bh = NULL; while (spread && - (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) { + !(ret = udf_next_aext(table, &epos, &eloc, &elen, &etype, 1))) { if (goal >= eloc.logicalBlockNum) { if (goal < eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) @@ -612,7 +620,7 @@ static udf_pblk_t udf_table_new_block(struct super_block *sb, brelse(epos.bh); - if (spread == 0xFFFFFFFF) { + if (UDF_EXT_ERR(ret) || spread == 0xFFFFFFFF) { brelse(goal_epos.bh); mutex_unlock(&sbi->s_alloc_mutex); return 0; diff --git a/fs/udf/directory.c b/fs/udf/directory.c index 93153665eb37..4b8bb77eaffa 100644 --- a/fs/udf/directory.c +++ b/fs/udf/directory.c @@ -166,13 +166,19 @@ static struct buffer_head *udf_fiiter_bread_blk(struct udf_fileident_iter *iter) */ static int udf_fiiter_advance_blk(struct udf_fileident_iter *iter) { + int8_t etype = -1; + int err = 0; + iter->loffset++; if (iter->loffset < DIV_ROUND_UP(iter->elen, 1<<iter->dir->i_blkbits)) return 0; iter->loffset = 0; - if (udf_next_aext(iter->dir, &iter->epos, &iter->eloc, &iter->elen, 1) - != (EXT_RECORDED_ALLOCATED >> 30)) { + err = udf_next_aext(iter->dir, &iter->epos, &iter->eloc, &iter->elen, + &etype, 1); + if (UDF_EXT_ERR(err)) + return err; + else if (UDF_EXT_EOF(err) || etype != (EXT_RECORDED_ALLOCATED >> 30)) { if (iter->pos == iter->dir->i_size) { iter->elen = 0; return 0; @@ -240,6 +246,7 @@ int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir, { struct udf_inode_info *iinfo = UDF_I(dir); int err = 0; + int8_t etype; iter->dir = dir; iter->bh[0] = iter->bh[1] = NULL; @@ -259,9 +266,9 @@ int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir, goto out; } - if (inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos, - &iter->eloc, &iter->elen, &iter->loffset) != - (EXT_RECORDED_ALLOCATED >> 30)) { + err = inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos, &iter->eloc, + &iter->elen, &iter->loffset, &etype); + if (err || etype != (EXT_RECORDED_ALLOCATED >> 30)) { if (pos == dir->i_size) return 0; udf_err(dir->i_sb, @@ -457,6 +464,7 @@ int udf_fiiter_append_blk(struct udf_fileident_iter *iter) sector_t block; uint32_t old_elen = iter->elen; int err; + int8_t etype; if (WARN_ON_ONCE(iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)) return -EINVAL; @@ -471,8 +479,9 @@ int udf_fiiter_append_blk(struct udf_fileident_iter *iter) udf_fiiter_update_elen(iter, old_elen); return err; } - if (inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen, - &iter->loffset) != (EXT_RECORDED_ALLOCATED >> 30)) { + err = inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen, + &iter->loffset, &etype); + if (err || etype != (EXT_RECORDED_ALLOCATED >> 30)) { udf_err(iter->dir->i_sb, "block %llu not allocated in directory (ino %lu)\n", (unsigned long long)block, iter->dir->i_ino); diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 4726a4d014b6..be9356f0eecf 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -418,10 +418,11 @@ static int udf_map_block(struct inode *inode, struct udf_map_rq *map) uint32_t elen; sector_t offset; struct extent_position epos = {}; + int8_t etype; down_read(&iinfo->i_data_sem); - if (inode_bmap(inode, map->lblk, &epos, &eloc, &elen, &offset) - == (EXT_RECORDED_ALLOCATED >> 30)) { + err = inode_bmap(inode, map->lblk, &epos, &eloc, &elen, &offset, &etype); + if (!err && etype == (EXT_RECORDED_ALLOCATED >> 30)) { map->pblk = udf_get_lb_pblock(inode->i_sb, &eloc, offset); map->oflags |= UDF_BLK_MAPPED; @@ -545,6 +546,7 @@ static int udf_do_extend_file(struct inode *inode, } else { struct kernel_lb_addr tmploc; uint32_t tmplen; + int8_t tmptype; udf_write_aext(inode, last_pos, &last_ext->extLocation, last_ext->extLength, 1); @@ -554,8 +556,12 @@ static int udf_do_extend_file(struct inode *inode, * more extents, we may need to enter possible following * empty indirect extent. */ - if (new_block_bytes) - udf_next_aext(inode, last_pos, &tmploc, &tmplen, 0); + if (new_block_bytes) { + err = udf_next_aext(inode, last_pos, &tmploc, &tmplen, + &tmptype, 0); + if (UDF_EXT_ERR(err)) + goto out_err; + } } iinfo->i_lenExtents += add; @@ -659,8 +665,10 @@ static int udf_extend_file(struct inode *inode, loff_t newsize) */ udf_discard_prealloc(inode); - etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset); - within_last_ext = (etype != -1); + err = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset, &etype); + if (UDF_EXT_ERR(err)) + goto out; + within_last_ext = (!err); /* We don't expect extents past EOF... */ WARN_ON_ONCE(within_last_ext && elen > ((loff_t)offset + 1) << inode->i_blkbits); @@ -674,8 +682,10 @@ static int udf_extend_file(struct inode *inode, loff_t newsize) extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED; } else { epos.offset -= adsize; - etype = udf_next_aext(inode, &epos, &extent.extLocation, - &extent.extLength, 0); + err = udf_next_aext(inode, &epos, &extent.extLocation, + &extent.extLength, &etype, 0); + if (UDF_EXT_ERR(err)) + goto out; extent.extLength |= etype << 30; } @@ -712,11 +722,11 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) loff_t lbcount = 0, b_off = 0; udf_pblk_t newblocknum; sector_t offset = 0; - int8_t etype; + int8_t etype, tmpetype; struct udf_inode_info *iinfo = UDF_I(inode); udf_pblk_t goal = 0, pgoal = iinfo->i_location.logicalBlockNum; int lastblock = 0; - bool isBeyondEOF; + bool isBeyondEOF = false; int ret = 0; prev_epos.offset = udf_file_entry_alloc_offset(inode); @@ -748,9 +758,12 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) prev_epos.offset = cur_epos.offset; cur_epos.offset = next_epos.offset; - etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 1); - if (etype == -1) + ret = udf_next_aext(inode, &next_epos, &eloc, &elen, &etype, 1); + if (UDF_EXT_EOF(ret)) { + isBeyondEOF = true; break; + } else if (ret < 0) + goto out_free; c = !c; @@ -771,8 +784,12 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) * Move prev_epos and cur_epos into indirect extent if we are at * the pointer to it */ - udf_next_aext(inode, &prev_epos, &tmpeloc, &tmpelen, 0); - udf_next_aext(inode, &cur_epos, &tmpeloc, &tmpelen, 0); + ret = udf_next_aext(inode, &prev_epos, &tmpeloc, &tmpelen, &tmpetype, 0); + if (UDF_EXT_ERR(ret)) + goto out_free; + ret = udf_next_aext(inode, &cur_epos, &tmpeloc, &tmpelen, &tmpetype, 0); + if (UDF_EXT_ERR(ret)) + goto out_free; /* if the extent is allocated and recorded, return the block if the extent is not a multiple of the blocksize, round up */ @@ -793,10 +810,9 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) } /* Are we beyond EOF and preallocated extent? */ - if (etype == -1) { + if (isBeyondEOF) { loff_t hole_len; - isBeyondEOF = true; if (count) { if (c) laarr[0] = laarr[1]; @@ -832,7 +848,6 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) endnum = c + 1; lastblock = 1; } else { - isBeyondEOF = false; endnum = startnum = ((count > 2) ? 2 : count); /* if the current extent is in position 0, @@ -846,15 +861,17 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) /* if the current block is located in an extent, read the next extent */ - etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0); - if (etype != -1) { + ret = udf_next_aext(inode, &next_epos, &eloc, &elen, &etype, 0); + if (!ret) { laarr[c + 1].extLength = (etype << 30) | elen; laarr[c + 1].extLocation = eloc; count++; startnum++; endnum++; - } else + } else if (UDF_EXT_EOF(ret)) lastblock = 1; + else + goto out_free; } /* if the current extent is not recorded but allocated, get the @@ -1172,6 +1189,7 @@ static int udf_update_extents(struct inode *inode, struct kernel_long_ad *laarr, int start = 0, i; struct kernel_lb_addr tmploc; uint32_t tmplen; + int8_t tmpetype; int err; if (startnum > endnum) { @@ -1189,14 +1207,19 @@ static int udf_update_extents(struct inode *inode, struct kernel_long_ad *laarr, */ if (err < 0) return err; - udf_next_aext(inode, epos, &laarr[i].extLocation, - &laarr[i].extLength, 1); + err = udf_next_aext(inode, epos, &laarr[i].extLocation, + &laarr[i].extLength, &tmpetype, 1); + if (UDF_EXT_ERR(err)) + return err; start++; } } for (i = start; i < endnum; i++) { - udf_next_aext(inode, epos, &tmploc, &tmplen, 0); + err = udf_next_aext(inode, epos, &tmploc, &tmplen, &tmpetype, 0); + if (UDF_EXT_ERR(err)) + return err; + udf_write_aext(inode, epos, &laarr[i].extLocation, laarr[i].extLength, 1); } @@ -1955,6 +1978,7 @@ int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block, struct extent_position nepos; struct kernel_lb_addr neloc; int ver, adsize; + int err = 0; if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT) adsize = sizeof(struct short_ad); @@ -1999,10 +2023,12 @@ int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block, if (epos->offset + adsize > sb->s_blocksize) { struct kernel_lb_addr cp_loc; uint32_t cp_len; - int cp_type; + int8_t cp_type; epos->offset -= adsize; - cp_type = udf_current_aext(inode, epos, &cp_loc, &cp_len, 0); + err = udf_current_aext(inode, epos, &cp_loc, &cp_len, &cp_type, 0); + if (err < 0) + goto err_out; cp_len |= ((uint32_t)cp_type) << 30; __udf_add_aext(inode, &nepos, &cp_loc, cp_len, 1); @@ -2017,6 +2043,9 @@ int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block, *epos = nepos; return 0; +err_out: + brelse(bh); + return err; } /* @@ -2162,21 +2191,24 @@ void udf_write_aext(struct inode *inode, struct extent_position *epos, */ #define UDF_MAX_INDIR_EXTS 16 -int8_t udf_next_aext(struct inode *inode, struct extent_position *epos, - struct kernel_lb_addr *eloc, uint32_t *elen, int inc) +int udf_next_aext(struct inode *inode, struct extent_position *epos, + struct kernel_lb_addr *eloc, uint32_t *elen, int8_t *etype, + int inc) { - int8_t etype; unsigned int indirections = 0; + int err = 0; + + while ((err = udf_current_aext(inode, epos, eloc, elen, etype, inc))) { + if (err || *etype != (EXT_NEXT_EXTENT_ALLOCDESCS >> 30)) + break; - while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) == - (EXT_NEXT_EXTENT_ALLOCDESCS >> 30)) { udf_pblk_t block; if (++indirections > UDF_MAX_INDIR_EXTS) { udf_err(inode->i_sb, "too many indirect extents in inode %lu\n", inode->i_ino); - return -1; + return -EFSCORRUPTED; } epos->block = *eloc; @@ -2186,18 +2218,18 @@ int8_t udf_next_aext(struct inode *inode, struct extent_position *epos, epos->bh = sb_bread(inode->i_sb, block); if (!epos->bh) { udf_debug("reading block %u failed!\n", block); - return -1; + return -EIO; } } - return etype; + return err; } -int8_t udf_current_aext(struct inode *inode, struct extent_position *epos, - struct kernel_lb_addr *eloc, uint32_t *elen, int inc) +int udf_current_aext(struct inode *inode, struct extent_position *epos, + struct kernel_lb_addr *eloc, uint32_t *elen, int8_t *etype, + int inc) { int alen; - int8_t etype; uint8_t *ptr; struct short_ad *sad; struct long_ad *lad; @@ -2224,8 +2256,8 @@ int8_t udf_current_aext(struct inode *inode, struct extent_position *epos, case ICBTAG_FLAG_AD_SHORT: sad = udf_get_fileshortad(ptr, alen, &epos->offset, inc); if (!sad) - return -1; - etype = le32_to_cpu(sad->extLength) >> 30; + return -ENODATA; + *etype = le32_to_cpu(sad->extLength) >> 30; eloc->logicalBlockNum = le32_to_cpu(sad->extPosition); eloc->partitionReferenceNum = iinfo->i_location.partitionReferenceNum; @@ -2234,17 +2266,17 @@ int8_t udf_current_aext(struct inode *inode, struct extent_position *epos, case ICBTAG_FLAG_AD_LONG: lad = udf_get_filelongad(ptr, alen, &epos->offset, inc); if (!lad) - return -1; - etype = le32_to_cpu(lad->extLength) >> 30; + return -ENODATA; + *etype = le32_to_cpu(lad->extLength) >> 30; *eloc = lelb_to_cpu(lad->extLocation); *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK; break; default: udf_debug("alloc_type = %u unsupported\n", iinfo->i_alloc_type); - return -1; + return -EINVAL; } - return etype; + return 0; } static int udf_insert_aext(struct inode *inode, struct extent_position epos, @@ -2258,12 +2290,14 @@ static int udf_insert_aext(struct inode *inode, struct extent_position epos, if (epos.bh) get_bh(epos.bh); - while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1) { + while (!(err = udf_next_aext(inode, &epos, &oeloc, + &oelen, &etype, 0))) { udf_write_aext(inode, &epos, &neloc, nelen, 1); neloc = oeloc; nelen = (etype << 30) | oelen; } - err = udf_add_aext(inode, &epos, &neloc, nelen, 1); + if (UDF_EXT_EOF(err)) + err = udf_add_aext(inode, &epos, &neloc, nelen, 1); brelse(epos.bh); return err; @@ -2278,6 +2312,7 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos) struct udf_inode_info *iinfo; struct kernel_lb_addr eloc; uint32_t elen; + int err = 0; if (epos.bh) { get_bh(epos.bh); @@ -2293,10 +2328,11 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos) adsize = 0; oepos = epos; - if (udf_next_aext(inode, &epos, &eloc, &elen, 1) == -1) + err = udf_next_aext(inode, &epos, &eloc, &elen, &etype, 1); + if (UDF_EXT_ERR(err)) return -1; - while ((etype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) { + while (!(err = udf_next_aext(inode, &epos, &eloc, &elen, &etype, 1))) { udf_write_aext(inode, &oepos, &eloc, (etype << 30) | elen, 1); if (oepos.bh != epos.bh) { oepos.block = epos.block; @@ -2306,6 +2342,11 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos) oepos.offset = epos.offset - adsize; } } + if (UDF_EXT_ERR(err)) { + brelse(epos.bh); + brelse(oepos.bh); + return -1; + } memset(&eloc, 0x00, sizeof(struct kernel_lb_addr)); elen = 0; @@ -2353,14 +2394,19 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos) return (elen >> 30); } -int8_t inode_bmap(struct inode *inode, sector_t block, - struct extent_position *pos, struct kernel_lb_addr *eloc, - uint32_t *elen, sector_t *offset) +/* + * return 0 when iudf_next_aext() loop success. + * return err < 0 and err != -ENODATA indicates error. + * return err == -ENODATA indicates hit EOF. + */ +int inode_bmap(struct inode *inode, sector_t block, struct extent_position *pos, + struct kernel_lb_addr *eloc, uint32_t *elen, sector_t *offset, + int8_t *etype) { unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; loff_t lbcount = 0, bcount = (loff_t) block << blocksize_bits; - int8_t etype; struct udf_inode_info *iinfo; + int err = 0; iinfo = UDF_I(inode); if (!udf_read_extent_cache(inode, bcount, &lbcount, pos)) { @@ -2370,17 +2416,18 @@ int8_t inode_bmap(struct inode *inode, sector_t block, } *elen = 0; do { - etype = udf_next_aext(inode, pos, eloc, elen, 1); - if (etype == -1) { + err = udf_next_aext(inode, pos, eloc, elen, etype, 1); + if (UDF_EXT_EOF(err)) { *offset = (bcount - lbcount) >> blocksize_bits; iinfo->i_lenExtents = lbcount; - return -1; } + if (err < 0) + return err; lbcount += *elen; } while (lbcount <= bcount); /* update extent cache */ udf_update_extent_cache(inode, lbcount - *elen, pos); *offset = (bcount + *elen - lbcount) >> blocksize_bits; - return etype; + return 0; } diff --git a/fs/udf/partition.c b/fs/udf/partition.c index af877991edc1..c441d4ae1f96 100644 --- a/fs/udf/partition.c +++ b/fs/udf/partition.c @@ -282,9 +282,11 @@ static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block, sector_t ext_offset; struct extent_position epos = {}; uint32_t phyblock; + int8_t etype; + int err = 0; - if (inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset) != - (EXT_RECORDED_ALLOCATED >> 30)) + err = inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset, &etype); + if (err || etype != (EXT_RECORDED_ALLOCATED >> 30)) phyblock = 0xFFFFFFFF; else { map = &UDF_SB(sb)->s_partmaps[partition]; diff --git a/fs/udf/super.c b/fs/udf/super.c index 3460ecc826d1..8c34224e1aee 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -2482,13 +2482,14 @@ static unsigned int udf_count_free_table(struct super_block *sb, uint32_t elen; struct kernel_lb_addr eloc; struct extent_position epos; + int8_t etype; mutex_lock(&UDF_SB(sb)->s_alloc_mutex); epos.block = UDF_I(table)->i_location; epos.offset = sizeof(struct unallocSpaceEntry); epos.bh = NULL; - while (udf_next_aext(table, &epos, &eloc, &elen, 1) != -1) + while (!udf_next_aext(table, &epos, &eloc, &elen, &etype, 1)) accum += (elen >> table->i_sb->s_blocksize_bits); brelse(epos.bh); diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c index a686c10fd709..d13ba9fd1309 100644 --- a/fs/udf/truncate.c +++ b/fs/udf/truncate.c @@ -69,6 +69,7 @@ void udf_truncate_tail_extent(struct inode *inode) int8_t etype = -1, netype; int adsize; struct udf_inode_info *iinfo = UDF_I(inode); + int err = 0; if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB || inode->i_size == iinfo->i_lenExtents) @@ -85,7 +86,7 @@ void udf_truncate_tail_extent(struct inode *inode) BUG(); /* Find the last extent in the file */ - while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) { + while (!(err = udf_next_aext(inode, &epos, &eloc, &elen, &netype, 1))) { etype = netype; lbcount += elen; if (lbcount > inode->i_size) { @@ -101,7 +102,7 @@ void udf_truncate_tail_extent(struct inode *inode) epos.offset -= adsize; extent_trunc(inode, &epos, &eloc, etype, elen, nelen); epos.offset += adsize; - if (udf_next_aext(inode, &epos, &eloc, &elen, 1) != -1) + if (!udf_next_aext(inode, &epos, &eloc, &elen, &netype, 1)) udf_err(inode->i_sb, "Extent after EOF in inode %u\n", (unsigned)inode->i_ino); @@ -110,7 +111,8 @@ void udf_truncate_tail_extent(struct inode *inode) } /* This inode entry is in-memory only and thus we don't have to mark * the inode dirty */ - iinfo->i_lenExtents = inode->i_size; + if (UDF_EXT_EOF(err)) + iinfo->i_lenExtents = inode->i_size; brelse(epos.bh); } @@ -124,6 +126,8 @@ void udf_discard_prealloc(struct inode *inode) int8_t etype = -1; struct udf_inode_info *iinfo = UDF_I(inode); int bsize = i_blocksize(inode); + int8_t tmpetype = -1; + int err = 0; if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB || ALIGN(inode->i_size, bsize) == ALIGN(iinfo->i_lenExtents, bsize)) @@ -132,16 +136,22 @@ void udf_discard_prealloc(struct inode *inode) epos.block = iinfo->i_location; /* Find the last extent in the file */ - while (udf_next_aext(inode, &epos, &eloc, &elen, 0) != -1) { + while (!(err = udf_next_aext(inode, &epos, &eloc, &elen, &tmpetype, + 0))) { brelse(prev_epos.bh); prev_epos = epos; if (prev_epos.bh) get_bh(prev_epos.bh); - etype = udf_next_aext(inode, &epos, &eloc, &elen, 1); + err = udf_next_aext(inode, &epos, &eloc, &elen, &etype, 1); + if (err < 0) + break; lbcount += elen; } - if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) { + if (UDF_EXT_ERR(err)) + goto out; + + if (!err && etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) { lbcount -= elen; udf_delete_aext(inode, prev_epos); udf_free_blocks(inode->i_sb, inode, &eloc, 0, @@ -150,6 +160,7 @@ void udf_discard_prealloc(struct inode *inode) /* This inode entry is in-memory only and thus we don't have to mark * the inode dirty */ iinfo->i_lenExtents = lbcount; +out: brelse(epos.bh); brelse(prev_epos.bh); } @@ -188,6 +199,7 @@ int udf_truncate_extents(struct inode *inode) loff_t byte_offset; int adsize; struct udf_inode_info *iinfo = UDF_I(inode); + int err = 0; if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) adsize = sizeof(struct short_ad); @@ -196,10 +208,12 @@ int udf_truncate_extents(struct inode *inode) else BUG(); - etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset); + err = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset, &etype); byte_offset = (offset << sb->s_blocksize_bits) + - (inode->i_size & (sb->s_blocksize - 1)); - if (etype == -1) { + (inode->i_size & (sb->s_blocksize - 1)); + if (UDF_EXT_ERR(err)) + return err; + if (UDF_EXT_EOF(err)) { /* We should extend the file? */ WARN_ON(byte_offset); return 0; @@ -217,8 +231,8 @@ int udf_truncate_extents(struct inode *inode) else lenalloc -= sizeof(struct allocExtDesc); - while ((etype = udf_current_aext(inode, &epos, &eloc, - &elen, 0)) != -1) { + while (!(err = udf_current_aext(inode, &epos, &eloc, &elen, &etype, + 0))) { if (etype == (EXT_NEXT_EXTENT_ALLOCDESCS >> 30)) { udf_write_aext(inode, &epos, &neloc, nelen, 0); if (indirect_ext_len) { @@ -253,6 +267,11 @@ int udf_truncate_extents(struct inode *inode) } } + if (UDF_EXT_ERR(err)) { + brelse(epos.bh); + return err; + } + if (indirect_ext_len) { BUG_ON(!epos.bh); udf_free_blocks(sb, NULL, &epos.block, 0, indirect_ext_len); diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 88692512a466..a156ed95189a 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -43,6 +43,9 @@ extern __printf(3, 4) void _udf_warn(struct super_block *sb, #define UDF_NAME_LEN 254 #define UDF_NAME_LEN_CS0 255 +#define UDF_EXT_EOF(err) ((err) == -ENODATA) +#define UDF_EXT_ERR(err) (((err) < 0) && (!UDF_EXT_EOF(err))) + static inline size_t udf_file_entry_alloc_offset(struct inode *inode) { struct udf_inode_info *iinfo = UDF_I(inode); @@ -157,8 +160,9 @@ extern struct buffer_head *udf_bread(struct inode *inode, udf_pblk_t block, extern int udf_setsize(struct inode *, loff_t); extern void udf_evict_inode(struct inode *); extern int udf_write_inode(struct inode *, struct writeback_control *wbc); -extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *, - struct kernel_lb_addr *, uint32_t *, sector_t *); +extern int inode_bmap(struct inode *inode, sector_t block, + struct extent_position *pos, struct kernel_lb_addr *eloc, + uint32_t *elen, sector_t *offset, int8_t *etype); int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); extern int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block, struct extent_position *epos); @@ -169,10 +173,12 @@ extern int udf_add_aext(struct inode *, struct extent_position *, extern void udf_write_aext(struct inode *, struct extent_position *, struct kernel_lb_addr *, uint32_t, int); extern int8_t udf_delete_aext(struct inode *, struct extent_position); -extern int8_t udf_next_aext(struct inode *, struct extent_position *, - struct kernel_lb_addr *, uint32_t *, int); -extern int8_t udf_current_aext(struct inode *, struct extent_position *, - struct kernel_lb_addr *, uint32_t *, int); +extern int udf_next_aext(struct inode *inode, struct extent_position *epos, + struct kernel_lb_addr *eloc, uint32_t *elen, + int8_t *etype, int inc); +extern int udf_current_aext(struct inode *inode, struct extent_position *epos, + struct kernel_lb_addr *eloc, uint32_t *elen, + int8_t *etype, int inc); extern void udf_update_extra_perms(struct inode *inode, umode_t mode); /* misc.c */ ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [syzbot] [udf?] KASAN: slab-out-of-bounds Read in udf_get_filelongad (2) 2024-09-26 11:36 ` Zhao Mengmeng @ 2024-09-26 12:03 ` syzbot 0 siblings, 0 replies; 10+ messages in thread From: syzbot @ 2024-09-26 12:03 UTC (permalink / raw) To: jack, linux-kernel, syzkaller-bugs, zhaomengmeng, zhaomzhao Hello, syzbot has tested the proposed patch and the reproducer did not trigger any issue: Reported-by: syzbot+7a4842f0b1801230a989@syzkaller.appspotmail.com Tested-by: syzbot+7a4842f0b1801230a989@syzkaller.appspotmail.com Tested on: commit: 67784a74 Merge tag 'ata-6.11-rc7' of git://git.kernel... git tree: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git console output: https://syzkaller.appspot.com/x/log.txt?x=1125b627980000 kernel config: https://syzkaller.appspot.com/x/.config?x=660f6eb11f9c7dc5 dashboard link: https://syzkaller.appspot.com/bug?extid=7a4842f0b1801230a989 compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40 patch: https://syzkaller.appspot.com/x/patch.diff?x=1459b627980000 Note: testing is done by a robot and is best-effort only. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [syzbot] Re: [syzbot] [udf?] KASAN: slab-out-of-bounds Read in udf_get_filelongad (2) 2024-09-03 9:55 [syzbot] [udf?] KASAN: slab-out-of-bounds Read in udf_get_filelongad (2) syzbot 2024-09-10 7:28 ` Zhao Mengmeng @ 2024-09-11 9:44 ` syzbot 2024-09-30 23:50 ` Zhao Mengmeng 2 siblings, 0 replies; 10+ messages in thread From: syzbot @ 2024-09-11 9:44 UTC (permalink / raw) To: linux-kernel, syzkaller-bugs For archival purposes, forwarding an incoming command email to linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com. *** Subject: Re: [syzbot] [udf?] KASAN: slab-out-of-bounds Read in udf_get_filelongad (2) Author: zhaomengmeng@kylinos.cn On 2024/9/10 15:43, syzbot wrote: > Hello, > > syzbot has tested the proposed patch but the reproducer is still triggering an issue: > WARNING in __udf_add_aext > > loop0: rw=0, sector=117, nr_sectors = 1 limit=0 > syz.0.15: attempt to access beyond end of device > loop0: rw=0, sector=117, nr_sectors = 1 limit=0 > ------------[ cut here ]------------ > WARNING: CPU: 0 PID: 5602 at fs/udf/inode.c:2043 __udf_add_aext+0x571/0x700 fs/udf/inode.c:2042 > Modules linked in: > CPU: 0 UID: 0 PID: 5602 Comm: syz.0.15 Not tainted 6.11.0-rc7-syzkaller-gbc83b4d1f086-dirty #0 > Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014 > RIP: 0010:__udf_add_aext+0x571/0x700 fs/udf/inode.c:2042 > Code: 41 5f 5d c3 cc cc cc cc e8 5c d7 74 fe 90 0f 0b 90 e9 e7 fb ff ff e8 4e d7 74 fe 90 0f 0b 90 e9 54 fc ff ff e8 40 d7 74 fe 90 <0f> 0b 90 e9 45 fd ff ff 44 89 f9 80 e1 07 80 c1 03 38 c1 0f 8c c7 > RSP: 0018:ffffc900026b78f8 EFLAGS: 00010293 > RAX: ffffffff831eb570 RBX: 0000000000000120 RCX: ffff888000990000 > RDX: 0000000000000000 RSI: 0000000000000120 RDI: ffffffffffffff40 > RBP: 00000000bffffe00 R08: ffffffff831eb2b0 R09: ffffffff831eb066 > R10: 0000000000000002 R11: ffff888000990000 R12: ffffc900026b7b80 > R13: ffffffffffffff40 R14: dffffc0000000000 R15: 0000000000000010 > FS: 00007f2deb03b6c0(0000) GS:ffff88801fe00000(0000) knlGS:0000000000000000 > CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 > CR2: 00007fa084b2c000 CR3: 0000000054cbe000 CR4: 0000000000350ef0 > DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 > DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 > Call Trace: > <TASK> > udf_add_aext fs/udf/inode.c:2104 [inline] > udf_do_extend_file+0xaf7/0x11e0 fs/udf/inode.c:540 > udf_extend_file fs/udf/inode.c:692 [inline] > udf_setsize+0xcc2/0x1320 fs/udf/inode.c:1265 > udf_setattr+0x3c7/0x5d0 fs/udf/file.c:236 > notify_change+0xbca/0xe90 fs/attr.c:503 > do_truncate fs/open.c:65 [inline] > do_ftruncate+0x46b/0x590 fs/open.c:181 > do_sys_ftruncate fs/open.c:199 [inline] > __do_sys_ftruncate fs/open.c:207 [inline] > __se_sys_ftruncate fs/open.c:205 [inline] > __x64_sys_ftruncate+0x95/0xf0 fs/open.c:205 > do_syscall_x64 arch/x86/entry/common.c:52 [inline] > do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83 > entry_SYSCALL_64_after_hwframe+0x77/0x7f > RIP: 0033:0x7f2dea179eb9 > Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48 > RSP: 002b:00007f2deb03b038 EFLAGS: 00000246 ORIG_RAX: 000000000000004d > RAX: ffffffffffffffda RBX: 00007f2dea315f80 RCX: 00007f2dea179eb9 > RDX: 0000000000000000 RSI: 0000008002007ffb RDI: 0000000000000005 > RBP: 00007f2dea1e793e R08: 0000000000000000 R09: 0000000000000000 > R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 > R13: 0000000000000000 R14: 00007f2dea315f80 R15: 00007ffec4d97f58 > </TASK> > > > Tested on: > > commit: bc83b4d1 Merge tag 'bcachefs-2024-09-09' of git://evil.. > git tree: upstream > console output: https://syzkaller.appspot.com/x/log.txt?x=10303f29980000 > kernel config: https://syzkaller.appspot.com/x/.config?x=61d235cb8d15001c > dashboard link: https://syzkaller.appspot.com/bug?extid=7a4842f0b1801230a989 > compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40 > patch: https://syzkaller.appspot.com/x/patch.diff?x=1686f43b980000 > #syz test ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [syzbot] [udf?] KASAN: slab-out-of-bounds Read in udf_get_filelongad (2) 2024-09-03 9:55 [syzbot] [udf?] KASAN: slab-out-of-bounds Read in udf_get_filelongad (2) syzbot 2024-09-10 7:28 ` Zhao Mengmeng 2024-09-11 9:44 ` [syzbot] " syzbot @ 2024-09-30 23:50 ` Zhao Mengmeng 2024-10-01 0:18 ` syzbot 2 siblings, 1 reply; 10+ messages in thread From: Zhao Mengmeng @ 2024-09-30 23:50 UTC (permalink / raw) To: syzbot+7a4842f0b1801230a989; +Cc: jack, linux-kernel, syzkaller-bugs [-- Attachment #1: Type: text/plain, Size: 88 bytes --] #syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 67784a74e258 [-- Attachment #2: test.patch --] [-- Type: text/x-patch, Size: 26715 bytes --] diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index d8fc11765d61..efa110545e59 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c @@ -370,6 +370,7 @@ static void udf_table_free_blocks(struct super_block *sb, struct extent_position oepos, epos; int8_t etype; struct udf_inode_info *iinfo; + int err = 0; mutex_lock(&sbi->s_alloc_mutex); iinfo = UDF_I(table); @@ -383,8 +384,8 @@ static void udf_table_free_blocks(struct super_block *sb, epos.block = oepos.block = iinfo->i_location; epos.bh = oepos.bh = NULL; - while (count && - (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) { + while (count && ((err = udf_next_aext(table, &epos, &eloc, &elen, + &etype, 1)) == 1)) { if (((eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) == start)) { if ((0x3FFFFFFF - elen) < @@ -435,6 +436,9 @@ static void udf_table_free_blocks(struct super_block *sb, } } + if (err < 0) + goto error_return; + if (count) { /* * NOTE: we CANNOT use udf_add_aext here, as it can try to @@ -460,8 +464,6 @@ static void udf_table_free_blocks(struct super_block *sb, else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) adsize = sizeof(struct long_ad); else { - brelse(oepos.bh); - brelse(epos.bh); goto error_return; } @@ -479,10 +481,10 @@ static void udf_table_free_blocks(struct super_block *sb, __udf_add_aext(table, &epos, &eloc, elen, 1); } +error_return: brelse(epos.bh); brelse(oepos.bh); -error_return: mutex_unlock(&sbi->s_alloc_mutex); return; } @@ -498,6 +500,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb, struct extent_position epos; int8_t etype = -1; struct udf_inode_info *iinfo; + int err = 0; if (first_block >= sbi->s_partmaps[partition].s_partition_len) return 0; @@ -517,12 +520,16 @@ static int udf_table_prealloc_blocks(struct super_block *sb, eloc.logicalBlockNum = 0xFFFFFFFF; while (first_block != eloc.logicalBlockNum && - (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) { + (err = udf_next_aext(table, &epos, &eloc, + &elen, &etype, 1)) == 1) { udf_debug("eloc=%u, elen=%u, first_block=%u\n", eloc.logicalBlockNum, elen, first_block); ; /* empty loop body */ } + if (err < 0) + goto err_out; + if (first_block == eloc.logicalBlockNum) { epos.offset -= adsize; @@ -539,6 +546,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb, alloc_count = 0; } +err_out: brelse(epos.bh); if (alloc_count) @@ -560,6 +568,7 @@ static udf_pblk_t udf_table_new_block(struct super_block *sb, struct extent_position epos, goal_epos; int8_t etype; struct udf_inode_info *iinfo = UDF_I(table); + int ret = 0; *err = -ENOSPC; @@ -583,8 +592,8 @@ static udf_pblk_t udf_table_new_block(struct super_block *sb, epos.block = iinfo->i_location; epos.bh = goal_epos.bh = NULL; - while (spread && - (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) { + while (spread && (ret = udf_next_aext(table, &epos, &eloc, &elen, + &etype, 1)) == 1) { if (goal >= eloc.logicalBlockNum) { if (goal < eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) @@ -612,7 +621,7 @@ static udf_pblk_t udf_table_new_block(struct super_block *sb, brelse(epos.bh); - if (spread == 0xFFFFFFFF) { + if (ret < 0 || spread == 0xFFFFFFFF) { brelse(goal_epos.bh); mutex_unlock(&sbi->s_alloc_mutex); return 0; diff --git a/fs/udf/directory.c b/fs/udf/directory.c index 93153665eb37..e6de599cb4e8 100644 --- a/fs/udf/directory.c +++ b/fs/udf/directory.c @@ -166,13 +166,19 @@ static struct buffer_head *udf_fiiter_bread_blk(struct udf_fileident_iter *iter) */ static int udf_fiiter_advance_blk(struct udf_fileident_iter *iter) { + int8_t etype = -1; + int err = 0; + iter->loffset++; if (iter->loffset < DIV_ROUND_UP(iter->elen, 1<<iter->dir->i_blkbits)) return 0; iter->loffset = 0; - if (udf_next_aext(iter->dir, &iter->epos, &iter->eloc, &iter->elen, 1) - != (EXT_RECORDED_ALLOCATED >> 30)) { + err = udf_next_aext(iter->dir, &iter->epos, &iter->eloc, + &iter->elen, &etype, 1); + if (err < 0) + return err; + else if (err == 0 || etype != (EXT_RECORDED_ALLOCATED >> 30)) { if (iter->pos == iter->dir->i_size) { iter->elen = 0; return 0; @@ -240,6 +246,7 @@ int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir, { struct udf_inode_info *iinfo = UDF_I(dir); int err = 0; + int8_t etype; iter->dir = dir; iter->bh[0] = iter->bh[1] = NULL; @@ -259,9 +266,9 @@ int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir, goto out; } - if (inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos, - &iter->eloc, &iter->elen, &iter->loffset) != - (EXT_RECORDED_ALLOCATED >> 30)) { + err = inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos, + &iter->eloc, &iter->elen, &iter->loffset, &etype); + if (err <= 0 || etype != (EXT_RECORDED_ALLOCATED >> 30)) { if (pos == dir->i_size) return 0; udf_err(dir->i_sb, @@ -457,6 +464,7 @@ int udf_fiiter_append_blk(struct udf_fileident_iter *iter) sector_t block; uint32_t old_elen = iter->elen; int err; + int8_t etype; if (WARN_ON_ONCE(iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)) return -EINVAL; @@ -471,8 +479,9 @@ int udf_fiiter_append_blk(struct udf_fileident_iter *iter) udf_fiiter_update_elen(iter, old_elen); return err; } - if (inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen, - &iter->loffset) != (EXT_RECORDED_ALLOCATED >> 30)) { + err = inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen, + &iter->loffset, &etype); + if (err <= 0 || etype != (EXT_RECORDED_ALLOCATED >> 30)) { udf_err(iter->dir->i_sb, "block %llu not allocated in directory (ino %lu)\n", (unsigned long long)block, iter->dir->i_ino); diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 4726a4d014b6..c275a5f3a0f6 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -418,10 +418,11 @@ static int udf_map_block(struct inode *inode, struct udf_map_rq *map) uint32_t elen; sector_t offset; struct extent_position epos = {}; + int8_t etype; down_read(&iinfo->i_data_sem); - if (inode_bmap(inode, map->lblk, &epos, &eloc, &elen, &offset) - == (EXT_RECORDED_ALLOCATED >> 30)) { + err = inode_bmap(inode, map->lblk, &epos, &eloc, &elen, &offset, &etype); + if (err == 1 && etype == (EXT_RECORDED_ALLOCATED >> 30)) { map->pblk = udf_get_lb_pblock(inode->i_sb, &eloc, offset); map->oflags |= UDF_BLK_MAPPED; @@ -545,6 +546,7 @@ static int udf_do_extend_file(struct inode *inode, } else { struct kernel_lb_addr tmploc; uint32_t tmplen; + int8_t tmptype; udf_write_aext(inode, last_pos, &last_ext->extLocation, last_ext->extLength, 1); @@ -554,8 +556,12 @@ static int udf_do_extend_file(struct inode *inode, * more extents, we may need to enter possible following * empty indirect extent. */ - if (new_block_bytes) - udf_next_aext(inode, last_pos, &tmploc, &tmplen, 0); + if (new_block_bytes) { + err = udf_next_aext(inode, last_pos, &tmploc, &tmplen, + &tmptype, 0); + if (err < 0) + goto out_err; + } } iinfo->i_lenExtents += add; @@ -659,8 +665,10 @@ static int udf_extend_file(struct inode *inode, loff_t newsize) */ udf_discard_prealloc(inode); - etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset); - within_last_ext = (etype != -1); + err = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset, &etype); + if (err < 0) + goto out; + within_last_ext = (err == 1); /* We don't expect extents past EOF... */ WARN_ON_ONCE(within_last_ext && elen > ((loff_t)offset + 1) << inode->i_blkbits); @@ -674,8 +682,10 @@ static int udf_extend_file(struct inode *inode, loff_t newsize) extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED; } else { epos.offset -= adsize; - etype = udf_next_aext(inode, &epos, &extent.extLocation, - &extent.extLength, 0); + err = udf_next_aext(inode, &epos, &extent.extLocation, + &extent.extLength, &etype, 0); + if (err != 1) + goto out; extent.extLength |= etype << 30; } @@ -712,11 +722,11 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) loff_t lbcount = 0, b_off = 0; udf_pblk_t newblocknum; sector_t offset = 0; - int8_t etype; + int8_t etype, tmpetype; struct udf_inode_info *iinfo = UDF_I(inode); udf_pblk_t goal = 0, pgoal = iinfo->i_location.logicalBlockNum; int lastblock = 0; - bool isBeyondEOF; + bool isBeyondEOF = false; int ret = 0; prev_epos.offset = udf_file_entry_alloc_offset(inode); @@ -748,9 +758,13 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) prev_epos.offset = cur_epos.offset; cur_epos.offset = next_epos.offset; - etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 1); - if (etype == -1) + ret = udf_next_aext(inode, &next_epos, &eloc, &elen, &etype, 1); + if (ret < 0) + goto out_free; + else if (ret == 0) { + isBeyondEOF = true; break; + } c = !c; @@ -771,13 +785,17 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) * Move prev_epos and cur_epos into indirect extent if we are at * the pointer to it */ - udf_next_aext(inode, &prev_epos, &tmpeloc, &tmpelen, 0); - udf_next_aext(inode, &cur_epos, &tmpeloc, &tmpelen, 0); + if (udf_next_aext(inode, &prev_epos, &tmpeloc, + &tmpelen, &tmpetype, 0) < 0) + goto out_free; + if (udf_next_aext(inode, &cur_epos, &tmpeloc, + &tmpelen, &tmpetype, 0) < 0) + goto out_free; /* if the extent is allocated and recorded, return the block if the extent is not a multiple of the blocksize, round up */ - if (etype == (EXT_RECORDED_ALLOCATED >> 30)) { + if (ret == 1 && etype == (EXT_RECORDED_ALLOCATED >> 30)) { if (elen & (inode->i_sb->s_blocksize - 1)) { elen = EXT_RECORDED_ALLOCATED | ((elen + inode->i_sb->s_blocksize - 1) & @@ -793,10 +811,9 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) } /* Are we beyond EOF and preallocated extent? */ - if (etype == -1) { + if (isBeyondEOF) { loff_t hole_len; - isBeyondEOF = true; if (count) { if (c) laarr[0] = laarr[1]; @@ -832,7 +849,6 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) endnum = c + 1; lastblock = 1; } else { - isBeyondEOF = false; endnum = startnum = ((count > 2) ? 2 : count); /* if the current extent is in position 0, @@ -846,15 +862,17 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map) /* if the current block is located in an extent, read the next extent */ - etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0); - if (etype != -1) { + ret = udf_next_aext(inode, &next_epos, &eloc, &elen, &etype, 0); + if (ret == 1) { laarr[c + 1].extLength = (etype << 30) | elen; laarr[c + 1].extLocation = eloc; count++; startnum++; endnum++; - } else + } else if (ret == 0) lastblock = 1; + else + goto out_free; } /* if the current extent is not recorded but allocated, get the @@ -1172,6 +1190,7 @@ static int udf_update_extents(struct inode *inode, struct kernel_long_ad *laarr, int start = 0, i; struct kernel_lb_addr tmploc; uint32_t tmplen; + int8_t tmpetype; int err; if (startnum > endnum) { @@ -1189,14 +1208,19 @@ static int udf_update_extents(struct inode *inode, struct kernel_long_ad *laarr, */ if (err < 0) return err; - udf_next_aext(inode, epos, &laarr[i].extLocation, - &laarr[i].extLength, 1); + err = udf_next_aext(inode, epos, &laarr[i].extLocation, + &laarr[i].extLength, &tmpetype, 1); + if (err < 0) + return err; start++; } } for (i = start; i < endnum; i++) { - udf_next_aext(inode, epos, &tmploc, &tmplen, 0); + err = udf_next_aext(inode, epos, &tmploc, &tmplen, &tmpetype, 0); + if (err < 0) + return err; + udf_write_aext(inode, epos, &laarr[i].extLocation, laarr[i].extLength, 1); } @@ -1955,6 +1979,7 @@ int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block, struct extent_position nepos; struct kernel_lb_addr neloc; int ver, adsize; + int err = 0; if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT) adsize = sizeof(struct short_ad); @@ -1999,10 +2024,12 @@ int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block, if (epos->offset + adsize > sb->s_blocksize) { struct kernel_lb_addr cp_loc; uint32_t cp_len; - int cp_type; + int8_t cp_type; epos->offset -= adsize; - cp_type = udf_current_aext(inode, epos, &cp_loc, &cp_len, 0); + err = udf_current_aext(inode, epos, &cp_loc, &cp_len, &cp_type, 0); + if (err != 1) + goto err_out; cp_len |= ((uint32_t)cp_type) << 30; __udf_add_aext(inode, &nepos, &cp_loc, cp_len, 1); @@ -2017,6 +2044,9 @@ int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block, *epos = nepos; return 0; +err_out: + brelse(bh); + return err; } /* @@ -2162,21 +2192,27 @@ void udf_write_aext(struct inode *inode, struct extent_position *epos, */ #define UDF_MAX_INDIR_EXTS 16 -int8_t udf_next_aext(struct inode *inode, struct extent_position *epos, - struct kernel_lb_addr *eloc, uint32_t *elen, int inc) +/* + * Returns 1 on success, -errno on error, 0 on hit EOF. + */ +int udf_next_aext(struct inode *inode, struct extent_position *epos, + struct kernel_lb_addr *eloc, uint32_t *elen, int8_t *etype, + int inc) { - int8_t etype; unsigned int indirections = 0; + int err = 0; - while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) == - (EXT_NEXT_EXTENT_ALLOCDESCS >> 30)) { + while ((err = udf_current_aext(inode, epos, eloc, elen, + etype, inc)) == 1) { + if (*etype != (EXT_NEXT_EXTENT_ALLOCDESCS >> 30)) + break; udf_pblk_t block; if (++indirections > UDF_MAX_INDIR_EXTS) { udf_err(inode->i_sb, "too many indirect extents in inode %lu\n", inode->i_ino); - return -1; + return -EFSCORRUPTED; } epos->block = *eloc; @@ -2186,18 +2222,21 @@ int8_t udf_next_aext(struct inode *inode, struct extent_position *epos, epos->bh = sb_bread(inode->i_sb, block); if (!epos->bh) { udf_debug("reading block %u failed!\n", block); - return -1; + return -EIO; } } - return etype; + return err; } -int8_t udf_current_aext(struct inode *inode, struct extent_position *epos, - struct kernel_lb_addr *eloc, uint32_t *elen, int inc) +/* + * Returns 1 on success, -errno on error, 0 on hit EOF. + */ +int udf_current_aext(struct inode *inode, struct extent_position *epos, + struct kernel_lb_addr *eloc, uint32_t *elen, int8_t *etype, + int inc) { int alen; - int8_t etype; uint8_t *ptr; struct short_ad *sad; struct long_ad *lad; @@ -2224,8 +2263,8 @@ int8_t udf_current_aext(struct inode *inode, struct extent_position *epos, case ICBTAG_FLAG_AD_SHORT: sad = udf_get_fileshortad(ptr, alen, &epos->offset, inc); if (!sad) - return -1; - etype = le32_to_cpu(sad->extLength) >> 30; + return 0; + *etype = le32_to_cpu(sad->extLength) >> 30; eloc->logicalBlockNum = le32_to_cpu(sad->extPosition); eloc->partitionReferenceNum = iinfo->i_location.partitionReferenceNum; @@ -2234,17 +2273,17 @@ int8_t udf_current_aext(struct inode *inode, struct extent_position *epos, case ICBTAG_FLAG_AD_LONG: lad = udf_get_filelongad(ptr, alen, &epos->offset, inc); if (!lad) - return -1; - etype = le32_to_cpu(lad->extLength) >> 30; + return 0; + *etype = le32_to_cpu(lad->extLength) >> 30; *eloc = lelb_to_cpu(lad->extLocation); *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK; break; default: udf_debug("alloc_type = %u unsupported\n", iinfo->i_alloc_type); - return -1; + return -EINVAL; } - return etype; + return 1; } static int udf_insert_aext(struct inode *inode, struct extent_position epos, @@ -2258,12 +2297,14 @@ static int udf_insert_aext(struct inode *inode, struct extent_position epos, if (epos.bh) get_bh(epos.bh); - while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1) { + while ((err = udf_next_aext(inode, &epos, &oeloc, + &oelen, &etype, 0)) == 1) { udf_write_aext(inode, &epos, &neloc, nelen, 1); neloc = oeloc; nelen = (etype << 30) | oelen; } - err = udf_add_aext(inode, &epos, &neloc, nelen, 1); + if (err == 0) + err = udf_add_aext(inode, &epos, &neloc, nelen, 1); brelse(epos.bh); return err; @@ -2278,6 +2319,7 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos) struct udf_inode_info *iinfo; struct kernel_lb_addr eloc; uint32_t elen; + int err = 0; if (epos.bh) { get_bh(epos.bh); @@ -2293,10 +2335,11 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos) adsize = 0; oepos = epos; - if (udf_next_aext(inode, &epos, &eloc, &elen, 1) == -1) + if (udf_next_aext(inode, &epos, &eloc, &elen, &etype, 1) <= 0) return -1; - while ((etype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) { + while ((err = udf_next_aext(inode, &epos, &eloc, + &elen, &etype, 1)) == 1) { udf_write_aext(inode, &oepos, &eloc, (etype << 30) | elen, 1); if (oepos.bh != epos.bh) { oepos.block = epos.block; @@ -2306,6 +2349,11 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos) oepos.offset = epos.offset - adsize; } } + if (err < 0) { + brelse(epos.bh); + brelse(oepos.bh); + return -1; + } memset(&eloc, 0x00, sizeof(struct kernel_lb_addr)); elen = 0; @@ -2353,14 +2401,17 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos) return (elen >> 30); } -int8_t inode_bmap(struct inode *inode, sector_t block, - struct extent_position *pos, struct kernel_lb_addr *eloc, - uint32_t *elen, sector_t *offset) +/* + * Returns 1 on success, -errno on error, 0 on hit EOF. + */ +int inode_bmap(struct inode *inode, sector_t block, struct extent_position *pos, + struct kernel_lb_addr *eloc, uint32_t *elen, sector_t *offset, + int8_t *etype) { unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; loff_t lbcount = 0, bcount = (loff_t) block << blocksize_bits; - int8_t etype; struct udf_inode_info *iinfo; + int err = 0; iinfo = UDF_I(inode); if (!udf_read_extent_cache(inode, bcount, &lbcount, pos)) { @@ -2370,11 +2421,13 @@ int8_t inode_bmap(struct inode *inode, sector_t block, } *elen = 0; do { - etype = udf_next_aext(inode, pos, eloc, elen, 1); - if (etype == -1) { - *offset = (bcount - lbcount) >> blocksize_bits; - iinfo->i_lenExtents = lbcount; - return -1; + err = udf_next_aext(inode, pos, eloc, elen, etype, 1); + if (err <= 0) { + if (err == 0) { + *offset = (bcount - lbcount) >> blocksize_bits; + iinfo->i_lenExtents = lbcount; + } + return err; } lbcount += *elen; } while (lbcount <= bcount); @@ -2382,5 +2435,5 @@ int8_t inode_bmap(struct inode *inode, sector_t block, udf_update_extent_cache(inode, lbcount - *elen, pos); *offset = (bcount + *elen - lbcount) >> blocksize_bits; - return etype; + return 1; } diff --git a/fs/udf/partition.c b/fs/udf/partition.c index af877991edc1..2b85c9501bed 100644 --- a/fs/udf/partition.c +++ b/fs/udf/partition.c @@ -282,9 +282,11 @@ static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block, sector_t ext_offset; struct extent_position epos = {}; uint32_t phyblock; + int8_t etype; + int err = 0; - if (inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset) != - (EXT_RECORDED_ALLOCATED >> 30)) + err = inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset, &etype); + if (err <= 0 || etype != (EXT_RECORDED_ALLOCATED >> 30)) phyblock = 0xFFFFFFFF; else { map = &UDF_SB(sb)->s_partmaps[partition]; diff --git a/fs/udf/super.c b/fs/udf/super.c index 3460ecc826d1..4bb7f600b99f 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -2482,13 +2482,14 @@ static unsigned int udf_count_free_table(struct super_block *sb, uint32_t elen; struct kernel_lb_addr eloc; struct extent_position epos; + int8_t etype; mutex_lock(&UDF_SB(sb)->s_alloc_mutex); epos.block = UDF_I(table)->i_location; epos.offset = sizeof(struct unallocSpaceEntry); epos.bh = NULL; - while (udf_next_aext(table, &epos, &eloc, &elen, 1) != -1) + while (udf_next_aext(table, &epos, &eloc, &elen, &etype, 1) == 1) accum += (elen >> table->i_sb->s_blocksize_bits); brelse(epos.bh); diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c index a686c10fd709..03774282361b 100644 --- a/fs/udf/truncate.c +++ b/fs/udf/truncate.c @@ -69,6 +69,7 @@ void udf_truncate_tail_extent(struct inode *inode) int8_t etype = -1, netype; int adsize; struct udf_inode_info *iinfo = UDF_I(inode); + int err = 0; if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB || inode->i_size == iinfo->i_lenExtents) @@ -85,7 +86,8 @@ void udf_truncate_tail_extent(struct inode *inode) BUG(); /* Find the last extent in the file */ - while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) { + while ((err = udf_next_aext(inode, &epos, &eloc, + &elen, &netype, 1)) == 1) { etype = netype; lbcount += elen; if (lbcount > inode->i_size) { @@ -101,7 +103,8 @@ void udf_truncate_tail_extent(struct inode *inode) epos.offset -= adsize; extent_trunc(inode, &epos, &eloc, etype, elen, nelen); epos.offset += adsize; - if (udf_next_aext(inode, &epos, &eloc, &elen, 1) != -1) + if (udf_next_aext(inode, &epos, &eloc, &elen, + &netype, 1) == 1) udf_err(inode->i_sb, "Extent after EOF in inode %u\n", (unsigned)inode->i_ino); @@ -110,7 +113,8 @@ void udf_truncate_tail_extent(struct inode *inode) } /* This inode entry is in-memory only and thus we don't have to mark * the inode dirty */ - iinfo->i_lenExtents = inode->i_size; + if (err == 0) + iinfo->i_lenExtents = inode->i_size; brelse(epos.bh); } @@ -124,6 +128,8 @@ void udf_discard_prealloc(struct inode *inode) int8_t etype = -1; struct udf_inode_info *iinfo = UDF_I(inode); int bsize = i_blocksize(inode); + int8_t tmpetype = -1; + int err = 0; if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB || ALIGN(inode->i_size, bsize) == ALIGN(iinfo->i_lenExtents, bsize)) @@ -132,16 +138,22 @@ void udf_discard_prealloc(struct inode *inode) epos.block = iinfo->i_location; /* Find the last extent in the file */ - while (udf_next_aext(inode, &epos, &eloc, &elen, 0) != -1) { + while ((err = udf_next_aext(inode, &epos, &eloc, + &elen, &tmpetype, 0)) == 1) { brelse(prev_epos.bh); prev_epos = epos; if (prev_epos.bh) get_bh(prev_epos.bh); - etype = udf_next_aext(inode, &epos, &eloc, &elen, 1); + err = udf_next_aext(inode, &epos, &eloc, &elen, &etype, 1); + if (err <= 0) + break; lbcount += elen; } - if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) { + if (err < 0) + goto out; + + if (err == 1 && etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) { lbcount -= elen; udf_delete_aext(inode, prev_epos); udf_free_blocks(inode->i_sb, inode, &eloc, 0, @@ -150,6 +162,7 @@ void udf_discard_prealloc(struct inode *inode) /* This inode entry is in-memory only and thus we don't have to mark * the inode dirty */ iinfo->i_lenExtents = lbcount; +out: brelse(epos.bh); brelse(prev_epos.bh); } @@ -188,6 +201,7 @@ int udf_truncate_extents(struct inode *inode) loff_t byte_offset; int adsize; struct udf_inode_info *iinfo = UDF_I(inode); + int err = 0; if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) adsize = sizeof(struct short_ad); @@ -196,10 +210,12 @@ int udf_truncate_extents(struct inode *inode) else BUG(); - etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset); + err = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset, &etype); byte_offset = (offset << sb->s_blocksize_bits) + (inode->i_size & (sb->s_blocksize - 1)); - if (etype == -1) { + if (err < 0) + return err; + else if (err == 0) { /* We should extend the file? */ WARN_ON(byte_offset); return 0; @@ -217,8 +233,8 @@ int udf_truncate_extents(struct inode *inode) else lenalloc -= sizeof(struct allocExtDesc); - while ((etype = udf_current_aext(inode, &epos, &eloc, - &elen, 0)) != -1) { + while ((err = udf_current_aext(inode, &epos, &eloc, + &elen, &etype, 0)) == 1) { if (etype == (EXT_NEXT_EXTENT_ALLOCDESCS >> 30)) { udf_write_aext(inode, &epos, &neloc, nelen, 0); if (indirect_ext_len) { @@ -253,6 +269,11 @@ int udf_truncate_extents(struct inode *inode) } } + if (err < 0) { + brelse(epos.bh); + return err; + } + if (indirect_ext_len) { BUG_ON(!epos.bh); udf_free_blocks(sb, NULL, &epos.block, 0, indirect_ext_len); diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 88692512a466..d159f20d61e8 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -157,8 +157,9 @@ extern struct buffer_head *udf_bread(struct inode *inode, udf_pblk_t block, extern int udf_setsize(struct inode *, loff_t); extern void udf_evict_inode(struct inode *); extern int udf_write_inode(struct inode *, struct writeback_control *wbc); -extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *, - struct kernel_lb_addr *, uint32_t *, sector_t *); +extern int inode_bmap(struct inode *inode, sector_t block, + struct extent_position *pos, struct kernel_lb_addr *eloc, + uint32_t *elen, sector_t *offset, int8_t *etype); int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); extern int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block, struct extent_position *epos); @@ -169,10 +170,12 @@ extern int udf_add_aext(struct inode *, struct extent_position *, extern void udf_write_aext(struct inode *, struct extent_position *, struct kernel_lb_addr *, uint32_t, int); extern int8_t udf_delete_aext(struct inode *, struct extent_position); -extern int8_t udf_next_aext(struct inode *, struct extent_position *, - struct kernel_lb_addr *, uint32_t *, int); -extern int8_t udf_current_aext(struct inode *, struct extent_position *, - struct kernel_lb_addr *, uint32_t *, int); +extern int udf_next_aext(struct inode *inode, struct extent_position *epos, + struct kernel_lb_addr *eloc, uint32_t *elen, + int8_t *etype, int inc); +extern int udf_current_aext(struct inode *inode, struct extent_position *epos, + struct kernel_lb_addr *eloc, uint32_t *elen, + int8_t *etype, int inc); extern void udf_update_extra_perms(struct inode *inode, umode_t mode); /* misc.c */ ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [syzbot] [udf?] KASAN: slab-out-of-bounds Read in udf_get_filelongad (2) 2024-09-30 23:50 ` Zhao Mengmeng @ 2024-10-01 0:18 ` syzbot 0 siblings, 0 replies; 10+ messages in thread From: syzbot @ 2024-10-01 0:18 UTC (permalink / raw) To: jack, linux-kernel, syzkaller-bugs, zhaomzhao Hello, syzbot has tested the proposed patch and the reproducer did not trigger any issue: Reported-by: syzbot+7a4842f0b1801230a989@syzkaller.appspotmail.com Tested-by: syzbot+7a4842f0b1801230a989@syzkaller.appspotmail.com Tested on: commit: 67784a74 Merge tag 'ata-6.11-rc7' of git://git.kernel... git tree: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git console output: https://syzkaller.appspot.com/x/log.txt?x=12097d07980000 kernel config: https://syzkaller.appspot.com/x/.config?x=660f6eb11f9c7dc5 dashboard link: https://syzkaller.appspot.com/bug?extid=7a4842f0b1801230a989 compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40 patch: https://syzkaller.appspot.com/x/patch.diff?x=16211980580000 Note: testing is done by a robot and is best-effort only. ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2024-10-01 0:18 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-09-03 9:55 [syzbot] [udf?] KASAN: slab-out-of-bounds Read in udf_get_filelongad (2) syzbot 2024-09-10 7:28 ` Zhao Mengmeng 2024-09-10 7:43 ` syzbot 2024-09-18 8:53 ` Zhao Mengmeng 2024-09-18 9:15 ` syzbot 2024-09-26 11:36 ` Zhao Mengmeng 2024-09-26 12:03 ` syzbot 2024-09-11 9:44 ` [syzbot] " syzbot 2024-09-30 23:50 ` Zhao Mengmeng 2024-10-01 0:18 ` syzbot
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox