测试注入未纠正错误时,在 CentOS 内核 4.18 中崩溃,但在上游内核 5.15 中通过
这个问题可能与:
总结一下调用轨迹:
[ 242.337362] kernel BUG at arch/x86/kernel/cpu/mce/core.c:1364!
我检查了这个内核(CentOS 8.5.2111内核),第1364行是:
1363 out_ist:
1364 nmi_exit();
PS CentOS 内核中的代码看起来与上游内核有很大不同。
然后触发BUG_ON(!in_nmi());
(以我的理解)
#define nmi_exit() \
do { \
lockdep_hardirq_exit(); \
rcu_nmi_exit(); \
BUG_ON(!in_nmi()); \
__preempt_count_sub(NMI_OFFSET + HARDIRQ_OFFSET); \
ftrace_nmi_exit(); \
lockdep_on(); \
printk_nmi_exit(); \
arch_nmi_exit(); \
} while (0)
这是 CentOS 4.18 内核下载:
https://vault.centos.org/8.5.2111/BaseOS/Source/SPackages/kernel-4.18.0-348.el8.src.rpm
总体日志:
[root@localhost GreenTea]# ./einj_mem_uc -f 'single'
0: single vaddr = xxxxxxxx paddr = xxxxx[ 242.248140] core: Uncorrected hardware memory error in user-access at xxxxxxxx
[ 242.248410] {1}[Hardware Error]: Hardware error from APEI Generic Hardware Error Source: 0
[ 242.257296] BUG: scheduling while atomic: einj_mem_uc/9237/0x00110000
a400
[ 242.258700] Memory failure: xxxx: Killing einj_mem_uc:9237 due to hardware memory corruption
[ 242.267021] {1}[Hardware Error]: event severity: recoverable
[ 242.267022] {1}[Hardware Error]: Error 0, type: recoverable
[ 242.267023] {1}[Hardware Error]: fru_text: Card01, ChnG, DIMM0
[ 242.267023] {1}[Hardware Error]: section_type: memory error
[ 242.267024] {1}[Hardware Error]: error_status: 0x0000000000000400
[ 242.267024] {1}[Hardware Error]: physical_address: 0x00000004805da400
[ 242.267026] {1}[Hardware Error]: node: 0 card: 6 module: 0 rank: 0 bank: 16 device: 0 row: 8835 column: 16
[ 242.267026] {1}[Hardware Error]: error_type: 4, single-symbol chipkill ECC
[ 242.267027] {1}[Hardware Error]: DIMM location: _Node0_Channel6_Dimm0 CPU0_G0
[ 242.267053] Memory failure: xxxxx: already hardware poisoned
[ 242.274392] Memory failure: xxxxx: recovery action for dirty LRU page: Recovered
[ 242.285519] EDAC skx MC3: HANDLING MCE MEMORY ERROR
[ 242.318662] ------------[ cut here ]------------
[ 242.326171] EDAC skx MC3: CPU 0: Machine Check Event: 0x0 Bank 255: 0xb40000000000009f
[ 242.337362] kernel BUG at arch/x86/kernel/cpu/mce/core.c:1364!
[ 242.337366] invalid opcode: 0000 [#1] SMP NOPTI
[ 242.337367] CPU: 139 PID: 9237 Comm: einj_mem_uc Kdump: loaded Tainted: G M W --------- - - 4.18.0-348.el8.x86_64 #1
[ 242.337368] Hardware name: Foo Inc. Foo BIOS 4C012 01/21/2022
[ 242.345383] EDAC skx MC3: TSC 0x0
[ 242.345383] EDAC skx MC3: ADDR 0x4805da400
[ 242.353765] RIP: 0010:do_machine_check+0xb10/0xc70
[ 242.353766] Code: 42 bf f4 01 00 00 e8 df 92 92 00 8b 05 b9 cb e2 01 41 39 c7 7e 2d 4c 89 ee 4c 89 e7 e8 09 ec ff ff 85 c0 74 dc e9 17 fe ff ff <0f> 0b 0f 0b 8b 35 1a 6c 7e 01 e9 05 fb ff ff c7 05 87 cb e2 01 01
[ 242.353766] RSP: 0018:ff2f652d53383e58 EFLAGS: 00010046
[ 242.353767] RAX: 0000000080000000 RBX: 00000000004805da RCX: 3ffffffffffffffe
[ 242.353768] RDX: ff121aa3ffbeaf40 RSI: 0000000000000001 RDI: ff121a69005db000
[ 242.360497] EDAC skx MC3: MISC 0x0
[ 242.360498] EDAC skx MC3: PROCESSOR 0:0x806f6 TIME 1529665988 SOCKET 0 APIC 0x0
[ 242.369175] RBP: ff121a65a70f3c80 R08: ff121a6480000010 R09: 0000000000000000
[ 242.369176] R10: 0000000000000002 R11: 0000000000000003 R12: 0000000000000000
[ 242.369176] R13: 0000000000000000 R14: ff121aa3ffb95ce0 R15: 0000000000000014
[ 242.369177] FS: 00007fe1bde23640(0000) GS:ff121aa3ffbc0000(0000) knlGS:0000000000000000
[ 242.369177] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 242.369177] CR2: 00007f50808270cc CR3: 00000001d0118001 CR4: 0000000000771ee0
[ 242.369178] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 242.369178] DR3: 0000000000000000 DR6: 00000000fffe07f0 DR7: 0000000000000400
[ 242.369179] PKRU: 55555554
[ 242.369179] Call Trace:
[ 242.369182] ? machine_check+0x25/0x40
[ 242.374751] EDAC MC3: 1 UE memory read error on CPU_SrcID#0_MC#3_Chan#0_DIMM#0 (channel:0 slot:0 page:0x4805da offset:0x400 grain:32 - err_code:0x0000:0x009f SystemAddress:0x4805da400 ProcessorSocketId:0x0 MemoryControllerId:0x3 ChannelAddress:0x800bb400 ChannelId:0x0 RankAddress:0x2002ed00 PhysicalRankId:0x0 DimmSlotId:0x0 DimmRankId:0x0 Row:0x2283 Column:0x10 Bank:0x0 BankGroup:0x4 ChipSelect:0x0)
[ 242.380013] machine_check+0x2f/0x40
[ 242.380015] RIP: 0033:0x403f5b
[ 242.380015] Code: 89 05 cd 37 20 00 8b 05 c7 37 20 00 c3 53 48 8b 1d 92 37 20 00 e8 2b d5 ff ff 48 8d 84 1b 76 14 40 00 48 f7 db 48 21 d8 5b c3 <0f> be 07 c3 0f be 07 0f be 57 01 01 d0 c3 48 8b 47 ff c3 c6 07 61
[ 242.380016] RSP: 002b:00007ffcfb9e6098 EFLAGS: 00010206
[ 242.380016] RAX: 0000000000607280 RBX: 0000000000607280 RCX: 0000000001b7b010
[ 242.380017] RDX: 0000000000000000 RSI: 0000000000000001 RDI: 00007fe1bde21400
[ 242.380017] RBP: 00007fe1bde21400 R08: 0000000001b7b04a R09: 0000000000000000
[ 242.380017] R10: 0000000000000000 R11: 0000000000000206 R12: 0000000000000001
[ 242.380018] R13: 00007ffcfb9e6410 R14: 0000000000000000 R15: 0000000000000000
[ 242.380018] Modules linked in: einj xt_CHECKSUM ipt_MASQUERADE xt_conntrack ipt_REJECT nft_compat nf_nat_tftp nft_objref nf_conntrack_tftp nft_counter tun bridge stp llc nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct nf_tables_set nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 ip_set nf_tables nfnetlink sunrpc vfat fat sd_mod sg intel_rapl_msr intel_rapl_common i10nm_edac nfit libnvdimm x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel iTCO_wdt intel_pmt_telemetry intel_pmt_crashlog iTCO_vendor_support intel_pmt_class kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcspkr rapl intel_th_gth ipmi_ssif uas intel_th_pci isst_if_mbox_pci isst_if_mmio idxd usb_storage joydev intel_pmt intel_th i2c_i801 isst_if_common i2c_ismt wmi acpi_ipmi ipmi_si ipmi_devintf ipmi_msghandler acpi_pad acpi_power_meter xfs libcrc32c ast i2c_algo_bit drm_vram_helper drm_kms_helper syscopyarea sysfillrect
[ 242.380033] sysimgblt fb_sys_fops drm_ttm_helper ttm crc32c_intel nvme ahci drm nvme_core libahci libata t10_pi pinctrl_emmitsburg dm_mirror dm_region_hash dm_log dm_mod fuse
[ 0.000000] Linux version 4.18.0-348.el8.x86_64 ([email protected]) (gcc version 8.5.0 20210514 (Red Hat 8.5.0-3) (GCC)) #1 SMP Mon Oct 4 12:17:22 EDT 2021
看起来(?)nmi_exit();
引起了这种恐慌,但为什么操作码是0000?
该日志的根本原因是什么kernel BUG at arch/x86/kernel/cpu/mce/core.c:1364!
以及为什么内核在调用跟踪期间重新启动。
20220908更新:
#define nmi_enter() \
do { \
arch_nmi_enter(); \
printk_nmi_enter(); \
lockdep_off(); \
ftrace_nmi_enter(); \
BUG_ON(in_nmi() == NMI_MASK); \
__preempt_count_add(NMI_OFFSET + HARDIRQ_OFFSET); \
rcu_nmi_enter(); \
lockdep_hardirq_enter(); \
} while (0)
#define nmi_exit() \
do { \
lockdep_hardirq_exit(); \
rcu_nmi_exit(); \
BUG_ON(!in_nmi()); \
__preempt_count_sub(NMI_OFFSET + HARDIRQ_OFFSET); \
ftrace_nmi_exit(); \
lockdep_on(); \
printk_nmi_exit(); \
arch_nmi_exit(); \
} while (0)
根据我的理解,如果发生第二次进入do_machine_check()
,则不应导致BUG_ON(!in_nmi())
触发。
前任:
__preempt_count_add(NMI_OFFSET + HARDIRQ_OFFSET);
__preempt_count_add(NMI_OFFSET + HARDIRQ_OFFSET);
BUG_ON(!in_nmi());
__preempt_count_add
不是“或”运算。
static inline void __preempt_count_add(int val)
{
u32 pc = READ_ONCE(current_thread_info()->preempt.count);
pc += val;
WRITE_ONCE(current_thread_info()->preempt.count, pc);
}
其他的:
请注意,PASS(上游内核 5.15)日志中没有这一行。
[ 242.257296] BUG: scheduling while atomic: einj_mem_uc/9237/0x00110000
答案1
基于下面列出的几个事实,我的工作理论是发生了未纠正的硬件内存错误 (UHME),导致了 NMI。在处理NMI期间,发生页面错误。增加抢占计数可能会出现操作顺序问题,或者可能会出现允许 nmi_handler 内部出现页面错误的错误。
- CentOS 4.18.0.348 的代码与主线 Linux 4.18.0 代码库有很大不同。 5.x 版本的许多功能已向后移植到 CentOS 的 4.18.0.x 中。此代码仅经过 RedHat 审查,因此出现错误的可能性可能较高。
我的研究意见是该图展示了事件的流程。
- 用户态 einj_mem_uc。
- 启动nmi_enter(),in_nmi()为假,直到preempt_count_add()设置为真。
- nmi 处理程序内部开始处理 NMI 中断。
- 发生页面错误,我们跳转到页面错误处理程序。
- 页面错误处理程序将 in_nmi() 保留为 true 并以 iret 退出。
- Intel iret 缺陷强制将 in_nmi() 值清除为 false。
- 返回 hmi 处理程序,处理程序内的 in_nmi() 为 false。
- nmi 处理程序返回 nmi_exit,触发 BUG_ON(!in_nmi()) 检查。
- 这会导致恐慌,然后停止或重新启动。
我有预感主线 4.18.1 也会像 5.15 内核一样工作。
最初我完成了另一个的源代码工作问题。
答案2
正如我在评论和回答时所怀疑的那样你的第一个相关问题你通常会面临双重错误。我在这里添加:可能还有三重。 (4.18下)
仅针对 4.18(因为此内核选项仅适用于 5.7),我建议您检查内核 .config 文件中的设置CONFIG_双重故障这应该启用双错误异常处理程序。
(请注意评论:禁用此选项...可能会导致您白发增多。;-))如果未设置,则内核将无法处理这种情况,并且会默默地重新启动。
如果你确实设置了它,那么你的 4.18 实际上面临着三重故障。 (我认为这不太可能,因为我预计至少会开始第二次跟踪转储)=>我怀疑您的 4.18 配置中未设置 CONFIG_DOUBLEFAULT。
为什么5.15下不会出现这种情况:
从 5.8 开始,如果 x32 架构保留以前处理双故障的方法,则 x86_64 架构将受益于一项功能(i386 上不可用):中断堆栈表。这使得能够针对指定事件(例如双故障或 NMI)自动切换到新堆栈。
由于初始内存故障涉及堆栈(在原子上下文中调度),因此在跟踪转储时会发生双重故障,在回溯转储时会发生三重故障。
而从 x86_64 上的 5.8 开始,切换到某些新堆栈(无内存错误)的可能性有助于优雅地处理双重错误。
答案3
认为它与内核无关,而只是一个硬件内存错误,即您使用较新的内核命中该内存地址,而不是使用旧内核命中该内存地址。您进行过内存测试吗?
答案4
似乎BUG_ON(true)
会触发一个内核BUG,即invalid opcode 0000
如果在这种情况下是,那么
BUG_ON(!in_nmi());
触发此转储。