5.4.18 加载某三方模块使用内核 panic 问题分析

2024-06-06 09:44

本文主要是介绍5.4.18 加载某三方模块使用内核 panic 问题分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

环境信息

内核版本:5.4.18

cpu 架构:arm64

问题描述

加载了产品的某三方 ko 文件使用过程中,会触发如下 panic 信息:

[  218.133479][ 0]  Unable to handle kernel NULL pointer dereference at virtual address 00000000000001f8
........................................................................................................
[  218.164737][ 0]   dsa_slave_dev_check+0x24/0x40
[  218.165445][ 0]   __switchdev_handle_port_obj_add+0x4c/0xfc
[  218.166286][ 0]   switchdev_handle_port_obj_add+0x40/0x60
[  218.167104][ 0]   dsa_slave_switchdev_blocking_event+0xd0/0xdc
[  218.168101][ 0]   notifier_call_chain+0x8c/0xf0
[  218.168803][ 0]   blocking_notifier_call_chain+0x68/0x90
[  218.169606][ 0]   switchdev_port_obj_notify+0x64/0xcc
[  218.170367][ 0]   switchdev_port_obj_add_now+0x60/0x110
[  218.171151][ 0]   switchdev_port_obj_add+0x4c/0x1e0
[  218.171897][ 0]   br_switchdev_port_vlan_add+0x74/0xa0
[  218.172673][ 0]   __vlan_add+0x68/0x690
[  218.173286][ 0]   br_vlan_add+0xf4/0x270
[  218.173910][ 0]   br_vlan_bridge_event+0x12c/0x164
[  218.174649][ 0]   br_device_event+0x1f0/0x3ec
[  218.175340][ 0]   notifier_call_chain+0x8c/0xf0
[  218.176038][ 0]   raw_notifier_call_chain+0x40/0x50
[  218.176786][ 0]   call_netdevice_notifiers_info+0x40/0x84
[  218.177603][ 0]   register_netdevice+0x3d4/0x490
.........................................................................................................
[  218.183456][ 0]  Code: aa1e03e0 d503201f 90002421 913c6021 (f940fe60)
[  218.184412][ 0]  ---[ end trace b95290d7d16d2c50 ]---
[  218.191634][ 1]  Kernel panic - not syncing: Fatal exception

从 panic 信息看,问题出在 register_netdevice 执行过程中,调用内核 notifier chain 过程中触发了内存访问异常,出现问题的点在 dsa_slave_dev_check 函数的 0x24 偏移处。

dsa_slave_dev_check 函数反汇编代码:

0000000000000540 <dsa_slave_dev_check>:540:       a9be7bfd        stp     x29, x30, [sp,#-32]!544:       910003fd        mov     x29, sp548:       f9000bf3        str     x19, [sp,#16]54c:       aa0003f3        mov     x19, x0550:       d50320ff        hint    #0x7554:       aa1e03e0        mov     x0, x30558:       94000000        bl      0 <_mcount>55c:       90000001        adrp    x1, 0 <dsa_slave_phy_read>560:       91000021        add     x1, x1, #0x0564:       f940fe60        ldr     x0, [x19,#504]568:       f9400bf3        ldr     x19, [sp,#16]56c:       eb01001f        cmp     x0, x1570:       1a9f17e0        cset    w0, eq574:       a8c27bfd        ldp     x29, x30, [sp],#32578:       d65f03c0        ret57c:       d503201f        nop

出现问题的地方:

     564:       f940fe60        ldr     x0, [x19,#504]

504 的十六进制数就是 1f8,dsa_slave_dev_check 函数代码如下:

static bool dsa_slave_dev_check(const struct net_device *dev)
{return dev->netdev_ops == &dsa_slave_netdev_ops;
}

显然,问题出在获取 netdev_ops 过程中,表明传入的 net_device 结构为 NULL,需要进一步分析问题触发的原因。

源码分析

追溯源码确定问题的关键在 br_vlan_bridge_event 函数中,相关代码如下:

/* Must be protected by RTNL. */
int br_vlan_bridge_event(struct net_device *dev, unsigned long event, void *ptr)
{struct netdev_notifier_changeupper_info *info;struct net_bridge *br = netdev_priv(dev);bool changed;int ret = 0;switch (event) {case NETDEV_REGISTER:ret = br_vlan_add(br, br->default_pvid,BRIDGE_VLAN_INFO_PVID |BRIDGE_VLAN_INFO_UNTAGGED |BRIDGE_VLAN_INFO_BRENTRY, &changed, NULL);

这里直接将 net device 的 priv 数据转化为 net_bridge 结构使用,继续向上追溯,确认关键逻辑如下:

        if (dev->priv_flags & IFF_EBRIDGE) {err = br_vlan_bridge_event(dev, event, ptr);

当 netdev 的 priv_flags 设置了 IFF_EBRIDGE 标志后,会将 net_device 的 priv 结构作为 net_bridge 使用,而此结构并未初始化,进而触发了问题。

产品反馈

产品同步 5.10 内核此内核模块都能正常使用,没有 panic 问题。怀疑是 dsa-core 模块的问题。分析两个版本内核中这两个项目的编译信息,得到如下内容:

5.10:编译为模块

5.4.18:编译进内核

于是怀疑是 5.10 并未加载 dsa-core 模块触发的问题,为了验证修改 5.4.18 将 dsa-core 编译为模块,测试验证堆栈变更为如下内容:


[  451.784754][ 1] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000338
....................................................................................................
[  451.817166][ 1]   __vlan_add+0x2fc/0x690
[  451.817784][ 1]   br_vlan_add+0xf4/0x270
[  451.818404][ 1]   br_vlan_bridge_event+0x12c/0x164
[  451.819135][ 1]   br_device_event+0x1f0/0x3ec
[  451.819810][ 1]   notifier_call_chain+0x8c/0xf0
[  451.820510][ 1]   raw_notifier_call_chain+0x40/0x50
[  451.821261][ 1]   call_netdevice_notifiers_info+0x40/0x84
[  451.822068][ 1]   register_netdevice+0x3d4/0x490
..............................................................................................
[  451.827680][ 1] [  T963] Code: a94573fb 3707ece0 79402263 aa1703e1 (f9419f42) 
[  451.828637][ 1] [  T963] ---[ end trace 9c20b105b7211e5f ]---
[  451.836189][ 1] [  T963] Kernel panic - not syncing: Fatal exception

反汇编相关内容如下:

/* check if we should use the vlan entry, returns false if it's only context */
static inline bool br_vlan_should_use(const struct net_bridge_vlan *v)
{if (br_vlan_is_master(v)) {1a80:       3707ece0        tbnz    w0, #0, 181c <__vlan_add+0x8c>goto out;}/* Add the dev mac and count the vlan only if it's usable */if (br_vlan_should_use(v)) {err = br_fdb_insert(br, p, dev->dev_addr, v->vid);1a84:       79402263        ldrh    w3, [x19,#16]1a88:       aa1703e1        mov     x1, x231a8c:       f9419f42        ldr     x2, [x26,#824]

异常指令位于 1a8c 处,此处是在访问 dev->dev_addr,表明问题还是 dev 结构为 NULL。

5.10 与 5.4.18 相关代码对比

未见明显差异,代码几乎完全相同。

5.10 上加载 dsa-core 模块测试

5.10 上加载了 dsa-core 模块后使用产品 ko 也不会触发问题,明明是几乎完全一致的代码,不应该有这样的区别,分析一度陷入僵局。

进一步分析发现 5.10 上未加载 bridge 内核模块,尝试加载后复现问题,仍旧能够正常工作,实在有点不能解释,难道是函数未调用到?

于是进一步使用 ftrace 跟踪相关函数,很久不用 ftrace 使用起来有些不太顺畅,最后也没有跟踪到相关函数调用,一度怀疑是用法不对。

为什么 5.10 不出问题?

一通抠脑壳后发现 5.10 的 /proc/kallsyms 文件中并没有 vlan_add 相关符号,于是检索内核源码,发现这个函数在开启了 BRIDGE_VLAN_FILTERING 之后才会编译进 bridge 内核模块中。bridge 模块 Makefile 文件内容如下:

bridge-y        := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \br_ioctl.o br_stp.o br_stp_bpdu.o \br_stp_if.o br_stp_timer.o br_netlink.o \br_netlink_tunnel.o br_arp_nd_proxy.obridge-$(CONFIG_SYSFS) += br_sysfs_if.o br_sysfs_br.obridge-$(subst m,y,$(CONFIG_BRIDGE_NETFILTER)) += br_nf_core.obr_netfilter-y := br_netfilter_hooks.o
br_netfilter-$(subst m,y,$(CONFIG_IPV6)) += br_netfilter_ipv6.o
obj-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.obridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o br_mdb.obridge-$(CONFIG_BRIDGE_VLAN_FILTERING) += br_vlan.o br_vlan_tunnel.o br_vlan_options.o

5.10 内核中的相关配置如下:

# CONFIG_BRIDGE_VLAN_FILTERING is not set
CONFIG_NET_SWITCHDEV=y
CONFIG_BRIDGE=m
CONFIG_NET_DSA=m

可以看到并没有开启此功能,于是单独编译 bridge,开启 VLAN_FILTERING,加载 bridge 模块后加载产品 ko 测试也会触发 panic,部分信息摘录如下:

[  234.935733] BUG: kernel NULL pointer dereference, address: 0000000000000320
...............................................................................
[  234.945997] RIP: 0010:__vlan_add+0x309/0xa50 [bridge]
...............................................................................
[  234.967415]  br_vlan_add+0x1dc/0x3a0 [bridge]
[  234.968293]  ? __ipv6_dev_mc_inc+0x1d9/0x350
[  234.969144]  br_vlan_bridge_event+0x175/0x1a0 [bridge]
[  234.970139]  ? failover_get_bymac+0x8e/0xa0
[  234.970979]  br_device_event+0x1bf/0x300 [bridge]
[  234.971902]  raw_notifier_call_chain+0x46/0x60
[  234.972762]  call_netdevice_notifiers_info+0x50/0x90
[  234.973724]  register_netdevice+0x479/0x5a0
...............................................................................

堆栈与 5.4.18 一致,表明问题出在不同的内核 bridge 相关内核配置不同上,实际是产品使用方法不正确。

解决方法

  1. 将 bridge 编译为模块、关闭 BRIDGE_VLAN_FILTER 功能
  2. 产品内核模块修改,去掉设置的 IFF_EBRIDGE 标志(建议)

总结

最开始一头扎进代码中,通过分析改代码得出的结论是产品异常使用问题。同步这个结论,产品反馈好几个内核版本都没有问题,于是并未坚持这一结论,继续进行分析。

分析对比了正常运行的 5.10.64 内核的代码,发现与 5.4.18 几乎一模一样,理论上应当出现相同的问题,实际测试确定正常工作,一度有些不知道怎么开展。

不过既然有正常的基线,就先基于基线进行分析,尝试使用 ftrace 跟踪内核符号调用,发现并没有跟踪到相应的调用信息,却并没有怀疑两个内核在相关模块编译上的差异。经过一通折腾,最后看到 bridge 模块编译配置,确认了问题为 5.10.64 上并未加载 bridge 功能。尝试加载后重试也能正常工作,在 /proc/kallsyms 中搜索 5.4.18 崩溃的关键函数名,没有找到,这才发现有一个关键的配置项目——BRIDGE_VLAN_FILTER 并未开启,才找到了问题点。

为了进一步验证,手动编译 5.10.64 内核的 bridge 模块,设置开启 BRIDGE_VLAN_FILTER 功能,再次配置产品业务,此时触发了与 5.4.18 相同的问题。

最后产品去掉 net_device 初始化过程中对 priv_flags IFF_EBRIDGE 标志的设定,验证功能正常,此问题得到解决,这时我已经抠了两天脑壳。。。

这篇关于5.4.18 加载某三方模块使用内核 panic 问题分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1035752

相关文章

linux生产者,消费者问题

pthread_cond_wait() :用于阻塞当前线程,等待别的线程使用pthread_cond_signal()或pthread_cond_broadcast来唤醒它。 pthread_cond_wait() 必须与pthread_mutex 配套使用。pthread_cond_wait()函数一进入wait状态就会自动release mutex。当其他线程通过pthread

C语言中联合体union的使用

本文编辑整理自: http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=179471 一、前言 “联合体”(union)与“结构体”(struct)有一些相似之处。但两者有本质上的不同。在结构体中,各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和。而在“联合”中,各成员共享一段内存空间, 一个联合变量

问题:第一次世界大战的起止时间是 #其他#学习方法#微信

问题:第一次世界大战的起止时间是 A.1913 ~1918 年 B.1913 ~1918 年 C.1914 ~1918 年 D.1914 ~1919 年 参考答案如图所示

Tolua使用笔记(上)

目录   1.准备工作 2.运行例子 01.HelloWorld:在C#中,创建和销毁Lua虚拟机 和 简单调用。 02.ScriptsFromFile:在C#中,对一个lua文件的执行调用 03.CallLuaFunction:在C#中,对lua函数的操作 04.AccessingLuaVariables:在C#中,对lua变量的操作 05.LuaCoroutine:在Lua中,

【Linux进阶】UNIX体系结构分解——操作系统,内核,shell

1.什么是操作系统? 从严格意义上说,可将操作系统定义为一种软件,它控制计算机硬件资源,提供程序运行环境。我们通常将这种软件称为内核(kerel),因为它相对较小,而且位于环境的核心。  从广义上说,操作系统包括了内核和一些其他软件,这些软件使得计算机能够发挥作用,并使计算机具有自己的特生。这里所说的其他软件包括系统实用程序(system utility)、应用程序、shell以及公用函数库等

Vim使用基础篇

本文内容大部分来自 vimtutor,自带的教程的总结。在终端输入vimtutor 即可进入教程。 先总结一下,然后再分别介绍正常模式,插入模式,和可视模式三种模式下的命令。 目录 看完以后的汇总 1.正常模式(Normal模式) 1.移动光标 2.删除 3.【:】输入符 4.撤销 5.替换 6.重复命令【. ; ,】 7.复制粘贴 8.缩进 2.插入模式 INSERT

2024.6.24 IDEA中文乱码问题(服务器 控制台 TOMcat)实测已解决

1.问题产生原因: 1.文件编码不一致:如果文件的编码方式与IDEA设置的编码方式不一致,就会产生乱码。确保文件和IDEA使用相同的编码,通常是UTF-8。2.IDEA设置问题:检查IDEA的全局编码设置和项目编码设置是否正确。3.终端或控制台编码问题:如果你在终端或控制台看到乱码,可能是终端的编码设置问题。确保终端使用的是支持你的文件的编码方式。 2.解决方案: 1.File -> S

Lipowerline5.0 雷达电力应用软件下载使用

1.配网数据处理分析 针对配网线路点云数据,优化了分类算法,支持杆塔、导线、交跨线、建筑物、地面点和其他线路的自动分类;一键生成危险点报告和交跨报告;还能生成点云数据采集航线和自主巡检航线。 获取软件安装包联系邮箱:2895356150@qq.com,资源源于网络,本介绍用于学习使用,如有侵权请您联系删除! 2.新增快速版,简洁易上手 支持快速版和专业版切换使用,快速版界面简洁,保留主

如何免费的去使用connectedpapers?

免费使用connectedpapers 1. 打开谷歌浏览器2. 按住ctrl+shift+N,进入无痕模式3. 不需要登录(也就是访客模式)4. 两次用完,关闭无痕模式(继续重复步骤 2 - 4) 1. 打开谷歌浏览器 2. 按住ctrl+shift+N,进入无痕模式 输入网址:https://www.connectedpapers.com/ 3. 不需要登录(也就是

vcpkg安装opencv中的特殊问题记录(无法找到opencv_corexd.dll)

我是按照网上的vcpkg安装opencv方法进行的(比如这篇:从0开始在visual studio上安装opencv(超详细,针对小白)),但是中间出现了一些别人没有遇到的问题,虽然原因没有找到,但是本人给出一些暂时的解决办法: 问题1: 我在安装库命令行使用的是 .\vcpkg.exe install opencv 我的电脑是x64,vcpkg在这条命令后默认下载的也是opencv2:x6