引用: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
标签:kernel,handle,dereference,nf,br,skb,forward,local,xt From: https://www.cnblogs.com/lianglianglu/p/17293141.html