引用:https://blog.csdn.net/agave7/article/details/119875023
虽然问题不一样,但是分析问题的方法是一致的。
Unable to handle kernel NULL pointer dereference at virtual address 分析
现象
[ 136.847780] br-lan: received packet on eth0.1 with own address as source address (addr:00:02:e7:f5:02:02, vlan:0) [ 138.026055] Unable to handle kernel NULL pointer dereference at virtual address 00000010 [ 138.034175] pgd = c0003000 [ 138.036888] [00000010] *pgd=80000040004003, *pmd=00000000 [ 138.042311] Internal error: Oops: 207 [#1] PREEMPT SMP ARM [ 138.047790] Modules linked in: pppoe ppp_async l2tp_ppp pptp pppox ppp_mppe ppp_generic iptable_nat ipt_REJECT ipt_MASQUERADE xt_time xt_tcpudp xt_state xt_recent xt_policy xt_nat xt_multiport xt_mark xt_mac xt_limit xt_helper xt_esp xt_conntrack xt_connmark xt_connlimit xt_connbytes xt_comment xt_TCPMSS xt_REDIRECT xt_LOG xt_FLOWOFFLOAD slhc openvswitch nf_reject_ipv4 nf_nat_redirect nf_nat_masquerade_ipv6 nf_nat_masquerade_ipv4 nf_conntrack_ipv6 nf_nat_ipv6 nf_conntrack_ipv4 nf_nat_ipv4 nf_nat nf_log_ipv4 nf_flow_table_hw nf_flow_table nf_defrag_ipv6 nf_defrag_ipv4 nf_conntrack_rtcache nf_conntrack libcrc32c iptable_mangle iptable_filter ipt_ah ip_tables crc_ccitt rtc_sunxi ledtrig_heartbeat ip6t_REJECT nf_reject_ipv6 nf_log_ipv6 nf_log_common ip6table_mangle ip6table_filter ip6_tables x_tables [ 138.118356] ip_gre gre l2tp_netlink l2tp_core udp_tunnel ip6_udp_tunnel ipcomp6 xfrm6_tunnel xfrm6_mode_tunnel xfrm6_mode_transport xfrm6_mode_beet esp6 ah6 ipcomp xfrm4_tunnel tunnel6 tun mpls_gso mpls_iptunnel mpls_router af_key xfrm_user xfrm_ipcomp algif_skcipher algif_hash af_alg ecb deflate zlib_deflate crypto_acompress [ 138.147315] CPU: 3 PID: 0 Comm: swapper/3 Not tainted 4.14.63 #0 [ 138.153312] Hardware name: Allwinner sun8i Family [ 138.158012] task: cf844440 task.stack: cf86c000 [ 138.162548] PC is at br_forward+0x4/0x74 [ 138.166467] LR is at br_dev_xmit+0x264/0x290 [ 138.170733] pc : [<c07725a8>] lr : [<c07702f0>] psr: a0000113 [ 138.176990] sp : cf86db6c ip : 00000202 fp : 00000000 [ 138.182207] r10: 00000027 r9 : c0c04a54 r8 : cf2f2540 [ 138.187425] r7 : cf2f2000 r6 : cc95dd80 r5 : 00000000 r4 : 00000000 [ 138.193942] r3 : 00000001 r2 : 00000000 r1 : cc95dd80 r0 : 00000000
分析
根据PC is at br_forward+0x4/0x74 可知道出错在 br_forward 函数中。
/* 位于 linux-4.14.63\net\bridge\br_forward.c */ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, bool local_rcv, bool local_orig) { if (to->flags & BR_ISOLATE_MODE && !local_orig) to = NULL; if (to && should_deliver(to, skb)) { if (local_rcv) deliver_clone(to, skb, local_orig); else __br_forward(to, skb, local_orig); return; } if (!local_rcv) kfree_skb(skb); }
已知在arm 中 r0~rx 寄存器一般用来给函数传参,再结合log:
[ 138.193942] r3 : 00000001 r2 : 00000000 r1 : cc95dd80 r0 : 00000000
可知:br_forward ( r0 ,r1, r2 , r3) 即为 br_forward ( 0 ,cc95dd80, 0 , 1) 。
显然 第一个参数 *to 是 0 ,是个空指针。
而代码中 to-> flags 对空指针进行了引用,flags 相对于 to 的偏移正好是 16 (0x10), to->flags 就等于 0+0x10 = 0x10
访问 0x10 触发了 Unable to handle kernel NULL pointer dereference at virtual address 00000010
解决办法
在代码中加入空指针判断
void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, bool local_rcv, bool local_orig) { if(unlikely(!to)) goto out; if (to->flags & BR_ISOLATE_MODE && !local_orig) to = NULL; if (to && should_deliver(to, skb)) { if (local_rcv) deliver_clone(to, skb, local_orig); else __br_forward(to, skb, local_orig); return; } out: if (!local_rcv) kfree_skb(skb); }
————————————————
版权声明:本文为CSDN博主「★临★」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/agave7/article/details/119875023
- dereference address pointer virtual Unabledereference address pointer virtual error dereference address invalid interfaces networks address unable addresses converting physical virtual 地址 架构virtual address dereference dereference expression assertion amp nil bytesreader dereference参数 pointer pointers