Re: [PATCH] writeback: expired dirty inodes can lead to a NULL dereference kernel panic issue in 'move_expired_inodes' function

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Apr 08, 2022 at 04:18:33PM +0900, Paran Lee wrote:
> writeback: expired dirty inodes can lead to a NULL dereference kernel panic issue in 'move_expired_inodes' function
> 
> Hello, Colin Ian King.
> 
> I am Paran Lee.
> 
> While tracing the null dereference kernel panic issue during the stress-ng(stress-ng-proc) test,
> I found the inode code block that could cause a null dereference kernel panic.
> 
> If this issue is confirmed as a bug that may have occurred in the past, wouldn't it be added to the link below?
> 
> @ Bugs found with stress-ng
> - https://github.com/ColinIanKing/stress-ng#bugs-found-with-stress-ng
> 
> * kernel log
> 
> [21881.096120] ICMPv6: process `stress-ng-procf' is using deprecated sysctl (syscall) net.ipv6.neigh.default.base_reachable_time - use net.ipv6.neigh.default.base_reachable_time_ms instead
> [22009.051158] BUG: unable to handle kernel NULL pointer dereference at 0000000000000008
> [22009.051167] IP: move_expired_inodes+0x59/0x1a0
> [22009.051168] PGD 0 P4D 0
> [22009.051170] Oops: 0002 [#1] SMP NOPTI
> ...
> [22009.051221] RIP: 0010:move_expired_inodes+0x59/0x1a0
> ...
> [22009.051257] Call Trace:
> [22009.051260]  queue_io+0x66/0x110
> [22009.051262]  wb_writeback+0x253/0x300
> [22009.051264]  wb_workfn+0xc0/0x400
> [22009.051265]  ? wb_workfn+0xc0/0x400
> [22009.051268]  ? __switch_to_asm+0x35/0x70
> [22009.051272]  process_one_work+0x1de/0x420
> [22009.051274]  worker_thread+0x32/0x410
> [22009.051276]  kthread+0x121/0x140
> [22009.051277]  ? process_one_work+0x420/0x420
> [22009.051279]  ? kthread_create_worker_on_cpu+0x70/0x70
> [22009.051280]  ret_from_fork+0x1f/0x40
> [22009.051282] Code: 04 25 28 00 00 00 48 89 45 d0 31 c0 4c 89 75 c8 c7 45 b0 00 00 00 00 c7 45 b4 00 00 00 00 eb 76 48 8b 3b 48 8b 43 08 83 45 b0 01 <48> 89 47 08 48 89 38 48 8b 45 c0 48 89 58 08 48 89 03 48 8d 43
> [22009.051293] RIP: move_expired_inodes+0x59/0x1a0 RSP: ffffa2f68413bcb0
> 
> * trace log on crash utility
> 
>       KERNEL: vmlinux-4.15.0-166-generic
>     DUMPFILE: 202204072123-wb_inode-delaying_queue-list-null-check/dump.202204072123  [PARTIAL DUMP]
>         CPUS: 4
>         DATE: Fri Apr  8 06:23:30 2022
>       UPTIME: 01:35:27
> LOAD AVERAGE: 8.30, 8.37, 9.17
>        TASKS: 668
>     NODENAME: ubuntu1804
>      RELEASE: 4.15.0-166-generic
>      VERSION: #174-Ubuntu SMP Wed Dec 8 19:07:44 UTC 2021
>      MACHINE: x86_64  (2394 Mhz)
>       MEMORY: 16 GB
>        PANIC: "BUG: unable to handle kernel NULL pointer dereference at 0000000000000008"
>          PID: 22864
>      COMMAND: "kworker/u8:0"
>         TASK: ffff91490b55d880  [THREAD_INFO: ffff91490b55d880]
>          CPU: 0
>        STATE: TASK_RUNNING (PANIC)
> 
> crash> bt
> ...
>  #9 [ffffa2f68413bc00] page_fault at ffffffffae401615
>     [exception RIP: move_expired_inodes+89]
>     RIP: ffffffffadcb11f9  RSP: ffffa2f68413bcb0  RFLAGS: 00010202
>     RAX: 0000000000000000  RBX: ffff9148083af9b8  RCX: ffff91496659a090
>     RDX: 000000010052d046  RSI: ffff91496659a080  RDI: 0000000000000000
>     RBP: ffffa2f68413bd08   R8: ffff91496676727f   R9: ffff914951111f76
>     R10: ffffa2f68413bdf8  R11: 0000000000000334  R12: 0000000000000000
>     R13: ffff91496659a070  R14: ffffa2f68413bcc8  R15: ffff91496659a080
>     ORIG_RAX: ffffffffffffffff  CS: 0010  SS: 0018
> #10 [ffffa2f68413bd10] queue_io at ffffffffadcb32d6
> #11 [ffffa2f68413bd48] wb_writeback at ffffffffadcb77a3
> #12 [ffffa2f68413bde8] wb_workfn at ffffffffadcb7eb0
> #13 [ffffa2f68413be80] process_one_work at ffffffffadaaa68e
> #14 [ffffa2f68413bec8] worker_thread at ffffffffadaaa902
> #15 [ffffa2f68413bf08] kthread at ffffffffadab1361
> #16 [ffffa2f68413bf50] ret_from_fork at ffffffffae4001ef
> 
> crash> dis ffffffffadcb32c6 20
> ...
> 0xffffffffadcb32c6 <queue_io+86>:       jg     0xffffffffadcb32e0 <queue_io+112>
> 0xffffffffadcb32c8 <queue_io+88>:       mov    %rsi,%r14
> 0xffffffffadcb32cb <queue_io+91>:       mov    %r12,%rsi
> 0xffffffffadcb32ce <queue_io+94>:       mov    %rdx,%r13
> 0xffffffffadcb32d1 <queue_io+97>:       callq  0xffffffffadcb11a0 <move_expired_inodes>
> 
> crash> dis 0xffffffffadcb11a0
> 0xffffffffadcb11a0 <move_expired_inodes>:       nopl   0x0(%rax,%rax,1) [FTRACE NOP]
> ...
> 0xffffffffadcb11ec <move_expired_inodes+76>:    jmp    0xffffffffadcb1264 <move_expired_inodes+196>
> 0xffffffffadcb11ee <move_expired_inodes+78>:    mov    (%rbx),%rdi
> 0xffffffffadcb11f1 <move_expired_inodes+81>:    mov    0x8(%rbx),%rax
> 0xffffffffadcb11f5 <move_expired_inodes+85>:    addl   $0x1,-0x50(%rbp)
> 0xffffffffadcb11f9 <move_expired_inodes+89>:    mov    %rax,0x8(%rdi)    <<<<<< Don't you think this is the NULL dereference RIP point of it?
> 0xffffffffadcb11fd <move_expired_inodes+93>:    mov    %rdi,(%rax)
> ...
> 0xffffffffadcb121e <move_expired_inodes+126>:   callq  0xffffffffae3cd460 <_raw_spin_lock>
> 
> Have a good day.
> Paran Lee.
> 
> Signed-off-by: Paran Lee <p4ranlee@xxxxxxxxx>
> ---
>  fs/fs-writeback.c | 11 +++++++++--
>  1 file changed, 9 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
> index 591fe9cf1659..23a7a567e443 100644
> --- a/fs/fs-writeback.c
> +++ b/fs/fs-writeback.c
> @@ -1357,12 +1357,14 @@ static int move_expired_inodes(struct list_head *delaying_queue,
>  	LIST_HEAD(tmp);
>  	struct list_head *pos, *node;
>  	struct super_block *sb = NULL;
> -	struct inode *inode;
> +	struct inode *inode = NULL;
>  	int do_sb_sort = 0;
>  	int moved = 0;
>  
>  	while (!list_empty(delaying_queue)) {
>  		inode = wb_inode(delaying_queue->prev);
> +		if(!inode)
> +			continue;
>  		if (inode_dirtied_after(inode, dirtied_before))
>  			break;
>  		list_move(&inode->i_io_list, &tmp);
> @@ -1385,7 +1387,12 @@ static int move_expired_inodes(struct list_head *delaying_queue,
>  
>  	/* Move inodes from one superblock together */
>  	while (!list_empty(&tmp)) {
> -		sb = wb_inode(tmp.prev)->i_sb;
> +		inode = wb_inode(tmp.prev);
> +		if(!inode)
> +			continue;
> +		sb = inode->i_sb;
> +		if(!sb)
> +			continue;
>  		list_for_each_prev_safe(pos, node, &tmp) {
>  			inode = wb_inode(pos);
>  			if (inode->i_sb == sb)
> -- 
> 2.25.1
> 

<formletter>

This is not the correct way to submit patches for inclusion in the
stable kernel tree.  Please read:
    https://www.kernel.org/doc/html/latest/process/stable-kernel-rules.html
for how to do this properly.

</formletter>



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux