自從 Linux 4.3 開始,在 Linode 上使用 PaX/grsecurity 時,內核會在被 pv-grub 執行后不久立即崩潰。由于崩潰是在啟動后極早期立刻發生的,沒有任何可以用來調試的日志,同時公司也不是蓋子開的,也沒有辦法得到母機上有意義的調試信息。這導致了蓋子的 VPS 內核從去年 12 月開始被鎖定在 4.2.7。由于不知什么時候產生了 Linode 東京機房會在 2016 年 6 月從 Xen 遷移到 KVM 的錯覺,也沒有花精力去嘗試調試這個問題。
然而今年 Linode 周年慶時硬件全部翻倍,惟獨東京機房除外。而根據官方最新的說法,新機房樂觀估計要第四季度上線。解決內核問題就不得不提上了蓋子的日程,首先是手工修復了不少 CVE 高危漏洞,隨后又祭出 diff 折騰半天,內核始終會在啟動后立刻死亡。而由于 grsecurity 并不提供 git 源,所以 git bisect 也是不可能的,唯一可用的工具只有 Linux 4.2.7 / 補丁文件,與 Linux 4.3.3 / 補丁文件。
在閱讀代碼差異時,一個很大的挑戰是如何區分上游內核的修改與下游 PaX/grsecurity 補丁的修改。直接比較補丁文件會導致代碼上下文丟失,讓代碼的意圖不可理解。最后蓋子打算編寫一個名為 metadiff 的工具,自動比較并去除在上游中出現的代碼段,以便僅僅對 PaX/grsecurity 的代碼進行比較,就連名字都想好了就叫 metadiff ,但一直沒有動手。
直到上個月和 Shawn 聊天時,提到了自己裝個 Xen 也不是不可行;于是周六終于動手在 VirutalBox 虛擬機里撞了個 Debian + Xen,又在 Xen 里啟動了一個虛擬機,果然很快就得到了內核崩潰的 traceback。
rip: ffffffff8100b2b0 pmu_msr_read+0x10flags: 00000282 i s nzrsp: ffffffff81aeff30rax: 8000000000000000 rcx: 0000000000000001 rdx: ffffffff81aeffccrbx: 00000000c0000080 rsi: ffffffff81aeffa0 rdi: 00000000c0000080rbp: ffffffff81aeffa0 r8: 0000000000000001 r9: 00000000ffffffffr10: ffffffff81cf9000 r11: 0000000000000000 r12: ffffffff81aeffccr13: ffffffff81aeffc4 r14: ffffffff81aeffc0 r15: 6f73b764afec1c9d cs: e033 ss: e02b ds: 0000 es: 0000 fs: 0000 @ 0000000000000000 gs: 0000 @ 0000000000000000/0000000000000000Code (instr addr ffffffff8100b2b0)00 00 00 00 00 41 54 49 89 d4 55 48 89 f5 53 89 fb 48 83 ec 10 <65> 48 8b 04 25 28 00 00 00 48 89 Stack: 0000000000000001 0000000000000000 0000000000000000 ffffffff8100b2b0 000000010000e030 0000000000010082 ffffffff81aeff70 000000000000e02b 0000000000000000 0000000000000000 00000000c0000080 ffffffff81aeffcc ffffffff81aeffc8 ffffffff810041c8 ffffffff81aeffc8 ffffffff81aeffccCall Trace: [<ffffffff8100b2b0>] pmu_msr_read+0x10 <-- [<ffffffff8100b2b0>] pmu_msr_read+0x10 [<ffffffff810041c8>] xen_read_msr_safe+0x18 [<ffffffff81be93eb>] xen_start_kernel+0x1b9
哦?可見內核在 xen_start_kernel 不久就崩潰了,這是 /* First C function to be called on Xen boot */,在如此早期就崩潰,什么錯誤日志到看不到也就不奇怪了。來看看 xen_read_msr 和 pmu_msr_read 在 4.2 和 4.3 之間有什么改變:
--- ../../4.2.7/linux-4.2.7/arch/x86/xen/enlighten.c 2016-09-11 00:44:12.010022936 +0800+++ arch/x86/xen/enlighten.c 2015-12-15 13:41:43.000000000 +0800@@ -1030,6 +1034,9 @@ static u64 xen_read_msr_safe(unsigned in { u64 val;+ if (pmu_msr_read(msr, &val, err))+ return val;+ val = native_read_msr_safe(msr, err); switch (msr) { case MSR_IA32_APICBASE:@@ -1074,9 +1081,11 @@ static int xen_write_msr_safe(unsigned i /* Fast syscall setup is all done in hypercalls, so these are all ignored. Stub them out here to stop Xen console noise. */+ break; default:- ret = native_write_msr_safe(msr, low, high);+ if (!pmu_msr_write(msr, low, high, &ret))+ ret = native_write_msr_safe(msr, low, high); } return ret;
新聞熱點
疑難解答