RK3568 linux6.1 死机

一、OOM

root@jenet:~# sysctl -a | grep oom

vm.oom_dump_tasks = 1

vm.oom_kill_allocating_task = 0

vm.panic_on_oom = 0

二、panic

root@jenet:~# sysctl -a | grep panic

fs.xfs.panic_mask = 0

kernel.max_rcu_stall_to_panic = 0

kernel.panic = 0

kernel.panic_on_oops = 0

kernel.panic_on_rcu_stall = 0

kernel.panic_on_warn = 0

kernel.panic_print = 0

vm.panic_on_oom = 0

root@jenet:~#

三、串口异常日志

21528.728557\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21533.677753\] net_ratelimit: 397 callbacks suppressed \[21533.677777\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21533.688851\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21533.691098\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21533.704985\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21533.706235\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21533.719366\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21533.720188\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21533.726428\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21533.736416\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21533.736992\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21539.454695\] net_ratelimit: 337 callbacks suppressed \[21539.454720\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21539.467874\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21539.481457\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21539.495025\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21539.508246\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21539.521441\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21539.535674\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21539.548835\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21539.562277\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[21539.575947\] br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0) \[29522.595222\] Unable to handle kernel paging request at virtual address 97fffc7faa0403e0 \[29522.603172\] Mem abort info: \[29522.605969\] ESR = 0x0000000086000004 \[29522.609717\] EC = 0x21: IABT (current EL), IL = 32 bits \[29522.615031\] SET = 0, FnV = 0 \[29522.618081\] EA = 0, S1PTW = 0 \[29522.621226\] FSC = 0x04: level 0 translation fault \[29522.626105\] \[97fffc7faa0403e0\] address between user and kernel address ranges

1,接收到自己MAC地址包

这条内核日志信息:

`br0: received packet on lan with own address as source address (addr:5c:85:7e:a1:6f:e9, vlan:0)`

其含义是:**网桥 `br0` 在其端口 `lan` 上接收到了一个数据包,而该包的源 MAC 地址(5c:85:7e:a1:6f:e9)正是网桥自身或其成员端口的 MAC 地址。

该日志是由内核源码 `net/bridge/br_fdb.c` 中的 `br_fdb_update` 函数触发的:

```c

// net/bridge/br_fdb.c

void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,

const unsigned char *addr, u16 vid, unsigned long flags)

{

...

fdb = fdb_find_rcu(&br->fdb_hash_tbl, addr, vid);

if (likely(fdb)) {

/* 如果发现收到的包的源地址在本地转发数据库(FDB)中被标记为 BR_FDB_LOCAL */

if (unlikely(test_bit(BR_FDB_LOCAL, &fdb->flags))) {

if (net_ratelimit())

br_warn(br, "received packet on %s with own address as source address (addr:%pM, vlan:%u)\n",

source->dev->name, addr, vid);

}

...

}

}

```

内核认为这是一种异常情况,因为正常情况下,设备不应该从外部接收到由自己发出的包。

这种情况通常指向网络拓扑或配置问题:

  • 网络环路

物理拓扑中存在环路(例如两根网线连接了同一个交换机的两个口,或者回环连接)。

数据包发出后经过外部网络又被发回了接收端。

  • 无线中继/桥接问题

如果你在使用无线网卡做桥接,某些中继器或 AP 可能会将原始包重新广播回来。

  • MAC 地址冲突

网络中存在另一个设备的 MAC 地址与你的 `br0` 或其端口完全相同。

  • 虚拟化/容器配置错误

在使用 Docker 或虚拟机时,虚拟网卡(veth/tap)配置不当,导致流量回流到物理网桥。

  • 交换机芯片 (Switch Chip) 配置

在 RK3568 这类嵌入式平台上,如果使用了外部交换机芯片(如 RTL8367),若 VLAN 隔离或端口镜像配置错误,可能会导致 CPU 发出的包被交换机广播回 CPU。

2,内核页请求异常

**[29522.595222] Unable to handle kernel paging request at virtual address 97fffc7faa0403e0

29522.603172\] Mem abort info: \[29522.605969\] ESR = 0x0000000086000004 \[29522.609717\] EC = 0x21: IABT (current EL), IL = 32 bits \[29522.615031\] SET = 0, FnV = 0 \[29522.618081\] EA = 0, S1PTW = 0 \[29522.621226\] FSC = 0x04: level 0 translation fault \[29522.626105\] \[97fffc7faa0403e0\] address between user and kernel address ranges**

这是一个典型的ARM64内核指令异常(Instruction Abort),通过日志可以得出以下结论:

2.1 核心异常信息解读

  • Unable to handle kernel paging request: 内核访问了一个未映射到页表的虚拟地址。
  • virtual address 97fffc7faa0403e0 : 这是一个非常奇怪的地址。在 ARM64 中,内核空间通常以 0xFFFF... 开头,用户空间以 0x0000... 开头。该地址(以 9 开头)处于两者之间的"非法真空地带"(Canonical Address violation),所以日志明确提示:address between user and kernel address ranges
  • EC = 0x21 (IABT) : IABT 代表 Instruction Abort 。这说明 CPU 尝试执行该地址处的代码,而不是读写数据。
  • FSC = 0x04 (level 0 translation fault): 转换表第 0 级就出错了,说明这个地址在页表中完全不存在。

2.2 异常是由什么导致的?

由于是指令执行异常 (Instruction Abort) 且地址为非法乱码,最常见的病因有以下几种:

A. 函数指针被篡改 (Function Pointer Corruption)

这是最常见的原因。内核代码调用了一个函数指针,但该指针由于某种原因变成了乱码。

  • 原因:结构体被释放后继续使用(Use-After-Free),该内存被重新填充了其他非指针数据;或者发生了越界写(Buffer Overflow),覆盖了结构体中的回调函数指针。
B. 栈被破坏导致返回地址错误 (Stack Corruption)

如果一个函数体内的局部变量发生溢出,可能会覆盖保存堆栈上的 返回地址 (LR/Link Register)

  • 表现 :当函数执行结束尝试返回(执行 RET 指令)时,CPU 从栈上加载了一个被破坏的地址并跳转过去,从而触发异常。
C. 野指针调用 (Uninitialized Pointer)

代码中定义了函数指针但没有初始化,或者初始化为某个特定值,导致执行时跳转到了一个随机的内存位置。

D. 内存位翻转 (Bit Flip / Hardware Issue)

虽然概率较低,但在某些不稳定的硬件环境下,DRAM 中的位翻转可能导致指针值从 0xFFFF... 变成 0x97FF... 这种奇怪的值。

2.3 如何进一步定位?

仅凭这段日志很难直接定位到具体的代码行,建议你查看该日志之后的 "Call Trace"(堆栈回溯)部分:

1)查看 pc 指针 :在异常发生时,pc (Program Counter) 应该指向的就是 97fffc7faa0403e0

2)查看lr寄存器:lr(link register)通常保存了是谁跳转到了这个非法地址。找到lr对应的函数,就是出问题的调用点。

3)检查call trace:

  • 如果call trace是完整的,向上找到一个正常的内核函数,那就是崩溃点;
  • 如果call trace也是乱码,说明栈已经被彻底破坏了。

2.4 lr和pc指针重启后还有效吗?

这涉及到地址空间和符号化分析的概念。地址本身是静态的,只要内核镜像(Image/vmlinux)没变,地址对应的代码位置就是有效的。

PC(Program Counter):指向崩溃瞬间正在执行的那条指令的虚拟地址。

LR(Link Register):指向函数返回后的下一条指令的虚拟地址(即谁调用了当前函数)

虽然系统重启了,硬件寄存器的值清空了,但是内核代码在内存中的布局通常是固定的(除非开启了KASLR),RK3568上没有开启此功能:

我们并不需要"活着的"进程,需要的是带有调试信息的内核镜像文件vmlinux。

第一步:确认是哪个"进程"闯的祸

虽然系统重启了,但崩溃日志(如果完整的话)会打印出:CPU: 0 PID: 1234 Comm: my_app Not tainted ...

  • Comm: my_app: 这就是崩溃时正在运行的进程名称。
  • PID:1234: 这是当时的进程号。通过这个信息,就知道是哪个应用程序触发了这段内核路径。
第二步:将地址还原为代码行 (addr2line)

拿到崩溃日志里的pc或lr地址后,在编译内核的那台电脑上执行:

aarch64-linux-gnu-addr2line -e vmlinux -f -p [你的PC地址]

  • vmlinux:必须是对应你板子上运行的那个版本的、未压缩且带符号表的内核文件(在内核源码根目录)。
  • 结果 :它会直接告诉你:哪个 .c 文件第几行 代码。

2.5 pc和lr

pc和lr指向的是虚拟地址,在没有开启kaslr时,虚拟地址也是固定的吗?

是的,在没有开启KASLR的情况下,内核主镜像(核心代码)的虚拟地址事完全固定不变的。当你编译完内核生成vmlinux文件的那一刻起,内核中所有函数和静态变量的虚拟地址就已经被链接器(Linker)写死了。这就意味着,只要不重新编译内核,每次系统启动后,同一个函数(比如sys_read)在内存中的虚拟地址都是一模一样的。因此,崩溃日志里打印出的pc和lr虚拟地址,每次也都是固定的。

这正是为什么我们可以事后使用addr2line工具,通过一个地址精准地反推出对应C语言代码行号的原因。因为这本"地址映射字典"(即带有调试信息的vmlinux文件)是静态且唯一的。

需要注意的两个特殊情况。虽然主内核的虚拟地址是固定的,但以下两种情况例外:

2.5.1 动态加载的.ko模块

即使关闭了KASLR,内核模块的虚拟地址也不是固定的。

  • 因为模块是在系统运行过程中,通过insmod或modprobe动态加载到内存(通常是vmalloc区域)中的。每次启动,或者以不同顺序加载模块,它被分配到的其实虚拟地址(基地址)都可能不同。
  • 如果pc指向的是某个.ko驱动,必须查看崩溃日志里的Modules linked in: 部分。那里通常会打印出发生崩溃时该模块被加载的具体基地址。然后计算 偏移量 = pc地址 - 模块基地址。最后用下面的公式来定位代码

addr2line -e your_driver.ko 相对偏移量

2.5.2 用户空间程序(APP/动态库)

用户空间进程的崩溃(比如Segmentation fault),程序的虚拟地址是否固定取决于是否开启了ASLR(Address Space Layout Raddmization),作用于用户态,由/proc/sys/kernel/randomize_va_space控制。它的值决定了用户程序加载时,栈、堆、共享库、mmap 基址等是否被随机化。

含义 说明
0 完全关闭 不进行任何用户态地址随机化。所有进程每次运行时的地址布局都固定,攻击容易。
1 保守随机化 开启栈、共享库(如 ld.so)、mmap 区域、VDSO 等的随机化。包括堆随机的部分(某些旧内核可能略有差异,但主流行为如此)。
2 完整随机化(默认) 在"1"的基础上,增加 (brk) 的随机化。这是当前所有主流 Linux 发行版的默认设置。

四、KASLR

KASLR 是 Kernel Address Space Layout Randomization 的缩写,中文常译为"内核地址空间布局随机化"。它是一项重要的内核安全功能,它通过随机化内核代码和数据的加载地址,能有效防御许多内核漏洞攻击。

1,工作原理:给内核代码"加个锁"

它的核心思想,可以理解为给整个Linux内核在启动时套上一层随机寻址的壳。

  • 打破固定模式:在没有KASLR时,内核的启动地址是固定的,攻击者容易预测并加以利用。开启KASLR后,内核的.text(代码段)、.data(数据段)等关键区域会在一个巨大的地址空间中被随机放置。
  • 提升成功门槛:由于地址每次都不同,攻击者很难裁到内核的具体位置,这使能利用内核漏洞的难度大增。
  • 多重随机化:KASLR不仅会随机化内核映像自身的基址(CONFIG_RADOMIZE_BASE),还会进一步随机化线性映射区、vmalloc区和vmemap区等关键内存区域的布局。

2,开了了KASLR时,如何定位

如果开启了KASLR,崩溃日志通常会打印一个KASLR Offset(偏移量)。需要用 崩溃地址-偏移量得到原始地址,再用addrline分析。

相关推荐
FreeGo~1 小时前
Linux 系统编程 进程篇 (五)
java·linux·服务器
nbwenren1 小时前
办公AI实测:Gemini3、GPT-4o、Claude3.5谁更强?
服务器·数据库·php
杨云龙UP1 小时前
Oracle数据库启动失败:ORA-29701、ORA-01565、ORA-17503故障处理记录_20260429
linux·运维·数据库·oracle·centos
Agent产品评测局1 小时前
离散制造业生产流程优化,AI落地实操步骤详解:从传统自动化到企业级智能体的技术范式跃迁
运维·人工智能·ai·自动化
handler012 小时前
Git 核心指令速查
linux·c语言·c++·笔记·git·学习
Gary Studio2 小时前
ubuntu 16.04一键换源
linux·运维·ubuntu
又来敲代码了2 小时前
k8s的部署
linux·运维·云原生·容器·kubernetes
梦·D·2 小时前
安全运维工具箱sskit_v1.0.3 部署
运维
CDN3602 小时前
DNS 负载均衡技术架构与调度策略解析
运维·架构·负载均衡