标签 内核 下的文章

Linux 内核正在盯着你,当它检测到系统上运行的某些东西违反了正常内核行为时,它会关闭系统并发出一个“oops”!

如果你检查你的 Linux 系统上运行的进程,你可能会对一个叫做 “kerneloops” 的进程感到好奇。提示一下,它是 “kernel oops”,而不是 “kerne loops”。

坦率地说,“oops” 是 Linux 内核的一部分出现了偏差行为。你有做错了什么吗?可能没有。但有一些不对劲。而那个做了错事的进程可能已经被 CPU 结束。最糟糕的是,内核可能会报错并突然关闭系统。

请注意,“oops” 不是首字母缩略词。它不代表像“ 面向对象的编程和系统 object-oriented programming and systems ” 或“ 超出程序规范 out of procedural specs ” 之类的东西。它实际上就是“哎呀” (oops),就像你刚掉下一杯酒或踩在你的猫身上。哎呀! “oops” 的复数是 “oopses”。

oops 意味着系统上运行的某些东西违反了内核有关正确行为的规则。也许代码尝试采取不允许的代码路径或使用无效指针。不管它是什么,内核 —— 总是在监测进程的错误行为 —— 很可能会阻止特定进程,并将它做了什么的消息写入控制台、 /var/log/dmesg/var/log/kern.log 中。

oops 可能是由内核本身引起的,也可能是某些进程试图让内核违反在系统上能做的事以及它们被允许做的事。

oops 将生成一个 崩溃签名 crash signature ,这可以帮助内核开发人员找出错误并提高代码质量。

系统上运行的 kerneloops 进程可能如下所示:

kernoops 881 1 0 Feb11 ? 00:00:01 /usr/sbin/kerneloops

你可能会注意到该进程不是由 root 运行的,而是由名为 “kernoops” 的用户运行的,并且它的运行时间极少。实际上,分配给这个特定用户的唯一任务是运行 kerneloops。

$ sudo grep kernoops /etc/passwd
kernoops:x:113:65534:Kernel Oops Tracking Daemon,,,:/:/bin/false

如果你的 Linux 系统不带有 kerneloops(比如 Debian),你可以考虑添加它。查看这个 Debian 页面了解更多信息。

什么时候应该关注 oops?

一般 oops 没什么大不了的。它在一定程度上取决于特定进程所扮演的角色。它也取决于 oops 的类别。

有些 oops 很严重,会导致 系统恐慌 system panic 。从技术上讲,系统恐慌是 oops 的一个子集(即更严重的 oops)。当内核检测到的问题足够严重以至于内核认为它(内核)必须立即停止运行以防止数据丢失或对系统造成其他损害时会出现。因此,系统需要暂停并重新启动,以防止任何不一致导致不可用或不可靠。所以系统恐慌实际上是为了保护自己免受不可挽回的损害。

总之,所有的内核恐慌都是 oops,但并不是所有的 oops 都是内核恐慌。

/var/log/kern.log 和相关的轮转日志(/var/log/kern.log.1/var/log/kern.log.2 等)包含由内核生成并由 syslog 处理的日志。

kerneloops 程序收集并默认将错误信息提交到 http://oops.kernel.org/,在那里它会被分析并呈现给内核开发者。此进程的配置详细信息在 /etc/kerneloops.conf 文件中指定。你可以使用下面的命令轻松查看设置:

$ sudo cat /etc/kerneloops.conf | grep -v ^# | grep -v ^$
[sudo] password for shs:
allow-submit = ask
allow-pass-on = yes
submit-url = http://oops.kernel.org/submitoops.php
log-file = /var/log/kern.log
submit-pipe = /usr/share/apport/kernel_oops

在上面的(默认)设置中,内核问题可以被提交,但要求用户获得许可。如果设置为 allow-submit = always,则不会询问用户。

调试内核问题是使用 Linux 系统的更高级技巧之一。幸运的是,大多数 Linux 用户很少或从没有经历过 oops 或内核恐慌。不过,知道 kerneloops 这样的进程在系统中执行什么操作,了解可能会报告什么以及系统何时遇到严重的内核冲突也是很好的。


via: https://www.networkworld.com/article/3254778/linux/what-is-a-linux-oops.html

作者:Sandra Henry-Stocker 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

LKRG logo

开源社区的人们正在致力于一个 Linux 内核的新项目,它可以让内核更安全。命名为 Linux 内核运行时防护 Linux Kernel Runtime Guard (LKRG),它是一个在 Linux 内核执行运行时完整性检查的可加载内核模块(LKM)。

它的用途是检测对 Linux 内核的已知的或未知的安全漏洞利用企图,以及去阻止这种攻击企图。

LKRG 也可以检测正在运行的进程的提权行为,在漏洞利用代码运行之前杀掉这个运行进程。

这个项目开发始于 2011 年,首个版本已经发布

因为这个项目开发的较早,LKRG 的当前版本仅仅是通过内核消息去报告违反内核完整性的行为,但是随着这个项目的成熟,将会部署一个完整的漏洞利用缓减系统。

LKRG 的成员 Alexander Peslyak 解释说,这个项目从 2011 年启动,并且 LKRG 已经经历了一个“重新开发"阶段。

LKRG 的首个公开版本是 LKRG v0.0,它现在可以从 这个页面 下载使用。这里 是这个项目的维基,为支持这个项目,它也有一个 Patreon 页面

虽然 LKRG 仍然是一个开源项目,LKRG 的维护者也计划做一个 LKRG Pro 版本,这个版本将包含一个专用的 LKRG 发行版,它将支持对特定漏洞利用的检测,比如,容器泄漏。开发团队计划从 LKRG Pro 基金中提取部分资金用于保证项目的剩余工作。

LKRG 是一个内核模块而不是一个补丁。

一个类似的项目是 附加内核监视器 Additional Kernel Observer (AKO),但是 LKRG 与 AKO 是不一样的,因为 LKRG 是一个内核加载模块而不是一个补丁。LKRG 开发团队决定将它设计为一个内核模块是因为,在内核上打补丁对安全性、系统稳定性以及性能都有很直接的影响。

而以内核模块的方式提供,可以在每个系统上更容易部署 LKRG,而不必去修改核心的内核代码,修改核心的内核代码非常复杂并且很容易出错。

LKRG 内核模块在目前主流的 Linux 发行版上都可以使用,比如,RHEL7、OpenVZ 7、Virtuozzo 7、以及 Ubuntu 16.04 到最新的主线版本。

它并非是一个完美的解决方案

LKRG 的创建者警告用户,他们并不认为 LKRG 是一个完美的解决方案,它提供不了坚不可摧和 100% 的安全。他们说,LKRG 是 “设计为可旁通的”,并且仅仅提供了“多元化安全” 的一个方面。

虽然 LKRG 可以防御许多已有的 Linux 内核漏洞利用,而且也有可能会防御将来许多的(包括未知的)未特意设计去绕过 LKRG 的安全漏洞利用。它是设计为可旁通的(尽管有时候是以更复杂和/或低可利用为代价的)。因此,他们说 LKRG 通过多元化提供安全,就像运行一个不常见的操作系统内核一样,也就不会有真实运行一个不常见的操作系统的可用性弊端。

LKRG 有点像基于 Windows 的防病毒软件,它也是工作于内核级别去检测漏洞利用和恶意软件。但是,LKRG 团队说,他们的产品比防病毒软件以及其它终端安全软件更加安全,因为它的基础代码量比较小,所以在内核级别引入新 bug 和漏洞的可能性就更小。

运行当前版本的 LKRG 大约会带来 6.5% 的性能损失

Peslyak 说 LKRG 是非常适用于 Linux 机器的,它在修补内核的安全漏洞后不需要重启动机器。LKRG 允许用户持续运行带有安全措施的机器,直到在一个计划的维护窗口中测试和部署关键的安全补丁为止。

经测试显示,安装 LKRG v0.0 后大约会产生 6.5% 性能影响,但是,Peslyak 说将在后续的开发中持续降低这种影响。

测试也显示,LKRG 检测到了 CVE-2014-9322 (BadIRET)、CVE-2017-5123 (waitid(2) missing access\_ok)、以及 CVE-2017-6074 (use-after-free in DCCP protocol) 的漏洞利用企图,但是没有检测到 CVE-2016-5195 (Dirty COW) 的漏洞利用企图。开发团队说,由于前面提到的“可旁通”的设计策略,LKRG 没有检测到 Dirty COW 提权攻击。

在 Dirty COW 的测试案例中,由于 bug 机制的原因,使得 LKRG 发生了 “旁通”,并且这也是一种利用方法,它也是将来类似的以用户空间为目标的绕过 LKRG 的一种方法。这样的漏洞利用是否会是普通情况(不太可能!除非 LKRG 或者类似机制的软件流行起来),以及对它的可用性的(负面的)影响是什么?(对于那些直接目标是用户空间的内核漏洞来说,这不太重要,也并不简单)。

via: https://www.bleepingcomputer.com/news/linux/lkrg-linux-to-get-a-loadable-kernel-module-for-runtime-integrity-checking/

作者:Catalin Cimpanu 译者:qhwdw 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

理解运转良好的系统对于处理不可避免的故障是最好的准备。

关于开源软件最古老的笑话是:“代码是 自具文档化的 self-documenting ”。经验表明,阅读源代码就像听天气预报一样:明智的人依然出门会看看室外的天气。本文讲述了如何运用调试工具来观察和分析 Linux 系统的启动。分析一个功能正常的系统启动过程,有助于用户和开发人员应对不可避免的故障。

从某些方面看,启动过程非常简单。内核在单核上以单线程和同步状态启动,似乎可以理解。但内核本身是如何启动的呢?initrd(initial ramdisk) 引导程序 bootloader 具有哪些功能?还有,为什么以太网端口上的 LED 灯是常亮的呢?

请继续阅读寻找答案。在 GitHub 上也提供了 介绍演示和练习的代码

启动的开始:OFF 状态

局域网唤醒 Wake-on-LAN

OFF 状态表示系统没有上电,没错吧?表面简单,其实不然。例如,如果系统启用了局域网唤醒机制(WOL),以太网指示灯将亮起。通过以下命令来检查是否是这种情况:

# sudo ethtool <interface name>

其中 <interface name> 是网络接口的名字,比如 eth0。(ethtool 可以在同名的 Linux 软件包中找到。)如果输出中的 Wake-on 显示 g,则远程主机可以通过发送 魔法数据包 MagicPacket 来启动系统。如果您无意远程唤醒系统,也不希望其他人这样做,请在系统 BIOS 菜单中将 WOL 关闭,或者用以下方式:

# sudo ethtool -s <interface name> wol d

响应魔法数据包的处理器可能是网络接口的一部分,也可能是 底板管理控制器 Baseboard Management Controller (BMC)。

英特尔管理引擎、平台控制器单元和 Minix

BMC 不是唯一的在系统关闭时仍在监听的微控制器(MCU)。x86\_64 系统还包含了用于远程管理系统的英特尔管理引擎(IME)软件套件。从服务器到笔记本电脑,各种各样的设备都包含了这项技术,它开启了如 KVM 远程控制和英特尔功能许可服务等 功能。根据 Intel 自己的检测工具IME 存在尚未修补的漏洞。坏消息是,要禁用 IME 很难。Trammell Hudson 发起了一个 me\_cleaner 项目,它可以清除一些相对恶劣的 IME 组件,比如嵌入式 Web 服务器,但也可能会影响运行它的系统。

IME 固件和 系统管理模式 System Management Mode (SMM)软件是 基于 Minix 操作系统 的,并运行在单独的 平台控制器单元 Platform Controller Hub 上(LCTT 译注:即南桥芯片),而不是主 CPU 上。然后,SMM 启动位于主处理器上的 通用可扩展固件接口 Universal Extensible Firmware Interface (UEFI)软件,相关内容 已被提及多次。Google 的 Coreboot 小组已经启动了一个雄心勃勃的 非扩展性缩减版固件 Non-Extensible Reduced Firmware (NERF)项目,其目的不仅是要取代 UEFI,还要取代早期的 Linux 用户空间组件,如 systemd。在我们等待这些新成果的同时,Linux 用户现在就可以从 Purism、System76 或 Dell 等处购买 禁用了 IME 的笔记本电脑,另外 带有 ARM 64 位处理器笔记本电脑 还是值得期待的。

引导程序

除了启动那些问题不断的间谍软件外,早期引导固件还有什么功能呢?引导程序的作用是为新上电的处理器提供通用操作系统(如 Linux)所需的资源。在开机时,不但没有虚拟内存,在控制器启动之前连 DRAM 也没有。然后,引导程序打开电源,并扫描总线和接口,以定位内核镜像和根文件系统的位置。U-Boot 和 GRUB 等常见的引导程序支持 USB、PCI 和 NFS 等接口,以及更多的嵌入式专用设备,如 NOR 闪存和 NAND 闪存。引导程序还与 可信平台模块 Trusted Platform Module (TPM)等硬件安全设备进行交互,在启动最开始建立信任链。

 title=

在构建主机上的沙盒中运行 U-boot 引导程序。

包括树莓派、任天堂设备、汽车主板和 Chromebook 在内的系统都支持广泛使用的开源引导程序 U-Boot。它没有系统日志,当发生问题时,甚至没有任何控制台输出。为了便于调试,U-Boot 团队提供了一个沙盒,可以在构建主机甚至是夜间的持续集成(CI)系统上测试补丁程序。如果系统上安装了 Git 和 GNU Compiler Collection(GCC)等通用的开发工具,使用 U-Boot 沙盒会相对简单:

# git clone git://git.denx.de/u-boot; cd u-boot
# make ARCH=sandbox defconfig
# make; ./u-boot
=> printenv
=> help

在 x86\_64 上运行 U-Boot,可以测试一些棘手的功能,如 模拟存储设备 的重新分区、基于 TPM 的密钥操作以及 USB 设备热插拔等。U-Boot 沙盒甚至可以在 GDB 调试器下单步执行。使用沙盒进行开发的速度比将引导程序刷新到电路板上的测试快 10 倍,并且可以使用 Ctrl + C 恢复一个“变砖”的沙盒。

启动内核

配置引导内核

引导程序完成任务后将跳转到已加载到主内存中的内核代码,并开始执行,传递用户指定的任何命令行选项。内核是什么样的程序呢?用命令 file /boot/vmlinuz 可以看到它是一个 “bzImage”,意思是一个大的压缩的镜像。Linux 源代码树包含了一个可以解压缩这个文件的工具—— extract-vmlinux

# scripts/extract-vmlinux /boot/vmlinuz-$(uname -r) > vmlinux
# file vmlinux
vmlinux: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically
linked, stripped

内核是一个 可执行与可链接格式 Executable and Linking Format (ELF)的二进制文件,就像 Linux 的用户空间程序一样。这意味着我们可以使用 binutils 包中的命令,如 readelf 来检查它。比较一下输出,例如:

# readelf -S /bin/date
# readelf -S vmlinux

这两个二进制文件中的段内容大致相同。

所以内核必须像其他的 Linux ELF 文件一样启动,但用户空间程序是如何启动的呢?在 main() 函数中?并不确切。

main() 函数运行之前,程序需要一个执行上下文,包括堆栈内存以及 stdiostdoutstderr 的文件描述符。用户空间程序从标准库(多数 Linux 系统在用 “glibc”)中获取这些资源。参照以下输出:

# file /bin/date
/bin/date: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically
linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32,
BuildID[sha1]=14e8563676febeb06d701dbee35d225c5a8e565a,
stripped

ELF 二进制文件有一个解释器,就像 Bash 和 Python 脚本一样,但是解释器不需要像脚本那样用 #! 指定,因为 ELF 是 Linux 的原生格式。ELF 解释器通过调用 _start() 函数来用所需资源 配置一个二进制文件,这个函数可以从 glibc 源代码包中找到,可以 用 GDB 查看。内核显然没有解释器,必须自我配置,这是怎么做到的呢?

用 GDB 检查内核的启动给出了答案。首先安装内核的调试软件包,内核中包含一个 未剥离的 unstripped vmlinux,例如 apt-get install linux-image-amd64-dbg,或者从源代码编译和安装你自己的内核,可以参照 Debian Kernel Handbook 中的指令。gdb vmlinux 后加 info files 可显示 ELF 段 init.text。在 init.text 中用 l *(address) 列出程序执行的开头,其中 addressinit.text 的十六进制开头。用 GDB 可以看到 x86\_64 内核从内核文件 arch/x86/kernel/head\_64.S 开始启动,在这个文件中我们找到了汇编函数 start_cpu0(),以及一段明确的代码显示在调用 x86_64 start_kernel() 函数之前创建了堆栈并解压了 zImage。ARM 32 位内核也有类似的文件 arch/arm/kernel/head.Sstart_kernel() 不针对特定的体系结构,所以这个函数驻留在内核的 init/main.c 中。start_kernel() 可以说是 Linux 真正的 main() 函数。

从 start\_kernel() 到 PID 1

内核的硬件清单:设备树和 ACPI 表

在引导时,内核需要硬件信息,不仅仅是已编译过的处理器类型。代码中的指令通过单独存储的配置数据进行扩充。有两种主要的数据存储方法: 设备树 device-tree 高级配置和电源接口(ACPI)表。内核通过读取这些文件了解每次启动时需要运行的硬件。

对于嵌入式设备,设备树是已安装硬件的清单。设备树只是一个与内核源代码同时编译的文件,通常与 vmlinux 一样位于 /boot 目录中。要查看 ARM 设备上的设备树的内容,只需对名称与 /boot/*.dtb 匹配的文件执行 binutils 包中的 strings 命令即可,这里 dtb 是指 设备树二进制文件 device-tree binary 。显然,只需编辑构成它的类 JSON 的文件并重新运行随内核源代码提供的特殊 dtc 编译器即可修改设备树。虽然设备树是一个静态文件,其文件路径通常由命令行引导程序传递给内核,但近年来增加了一个 设备树覆盖 的功能,内核在启动后可以动态加载热插拔的附加设备。

x86 系列和许多企业级的 ARM64 设备使用 ACPI 机制。与设备树不同的是,ACPI 信息存储在内核在启动时通过访问板载 ROM 而创建的 /sys/firmware/acpi/tables 虚拟文件系统中。读取 ACPI 表的简单方法是使用 acpica-tools 包中的 acpidump 命令。例如:

 title=

联想笔记本电脑的 ACPI 表都是为 Windows 2001 设置的。

是的,你的 Linux 系统已经准备好用于 Windows 2001 了,你要考虑安装吗?与设备树不同,ACPI 具有方法和数据,而设备树更多地是一种硬件描述语言。ACPI 方法在启动后仍处于活动状态。例如,运行 acpi_listen 命令(在 apcid 包中),然后打开和关闭笔记本机盖会发现 ACPI 功能一直在运行。暂时地和动态地 覆盖 ACPI 表 是可能的,而永久地改变它需要在引导时与 BIOS 菜单交互或刷新 ROM。如果你遇到那么多麻烦,也许你应该 安装 coreboot,这是开源固件的替代品。

从 start\_kernel() 到用户空间

init/main.c 中的代码竟然是可读的,而且有趣的是,它仍然在使用 1991 - 1992 年的 Linus Torvalds 的原始版权。在一个刚启动的系统上运行 dmesg | head,其输出主要来源于此文件。第一个 CPU 注册到系统中,全局数据结构被初始化,并且调度程序、中断处理程序(IRQ)、定时器和控制台按照严格的顺序逐一启动。在 timekeeping_init() 函数运行之前,所有的时间戳都是零。内核初始化的这部分是同步的,也就是说执行只发生在一个线程中,在最后一个完成并返回之前,没有任何函数会被执行。因此,即使在两个系统之间,dmesg 的输出也是完全可重复的,只要它们具有相同的设备树或 ACPI 表。Linux 的行为就像在 MCU 上运行的 RTOS(实时操作系统)一样,如 QNX 或 VxWorks。这种情况持续存在于函数 rest_init() 中,该函数在终止时由 start_kernel() 调用。

 title=

早期的内核启动流程。

函数 rest_init() 产生了一个新进程以运行 kernel_init(),并调用了 do_initcalls()。用户可以通过将 initcall_debug 附加到内核命令行来监控 initcalls,这样每运行一次 initcall 函数就会产生 一个 dmesg 条目。initcalls 会历经七个连续的级别:early、core、postcore、arch、subsys、fs、device 和 late。initcalls 最为用户可见的部分是所有处理器外围设备的探测和设置:总线、网络、存储和显示器等等,同时加载其内核模块。rest_init() 也会在引导处理器上产生第二个线程,它首先运行 cpu_idle(),然后等待调度器分配工作。

kernel_init() 也可以 设置对称多处理(SMP)结构。在较新的内核中,如果 dmesg 的输出中出现 “Bringing up secondary CPUs...” 等字样,系统便使用了 SMP。SMP 通过“热插拔” CPU 来进行,这意味着它用状态机来管理其生命周期,这种状态机在概念上类似于热插拔的 U 盘一样。内核的电源管理系统经常会使某个 core 离线,然后根据需要将其唤醒,以便在不忙的机器上反复调用同一段的 CPU 热插拔代码。观察电源管理系统调用 CPU 热插拔代码的 BCC 工具 称为 offcputime.py

请注意,init/main.c 中的代码在 smp_init() 运行时几乎已执行完毕:引导处理器已经完成了大部分一次性初始化操作,其它核无需重复。尽管如此,跨 CPU 的线程仍然要在每个核上生成,以管理每个核的中断(IRQ)、工作队列、定时器和电源事件。例如,通过 ps -o psr 命令可以查看服务每个 CPU 上的线程的 softirqs 和 workqueues。

# ps -o pid,psr,comm $(pgrep ksoftirqd)  
 PID PSR COMMAND 
   7   0 ksoftirqd/0 
  16   1 ksoftirqd/1 
  22   2 ksoftirqd/2 
  28   3 ksoftirqd/3 

# ps -o pid,psr,comm $(pgrep kworker)
PID  PSR COMMAND 
   4   0 kworker/0:0H 
  18   1 kworker/1:0H 
  24   2 kworker/2:0H 
  30   3 kworker/3:0H
[ . . . ]

其中,PSR 字段代表“ 处理器 processor ”。每个核还必须拥有自己的定时器和 cpuhp 热插拔处理程序。

那么用户空间是如何启动的呢?在最后,kernel_init() 寻找可以代表它执行 init 进程的 initrd。如果没有找到,内核直接执行 init 本身。那么为什么需要 initrd 呢?

早期的用户空间:谁规定要用 initrd?

除了设备树之外,在启动时可以提供给内核的另一个文件路径是 initrd 的路径。initrd 通常位于 /boot 目录中,与 x86 系统中的 bzImage 文件 vmlinuz 一样,或是与 ARM 系统中的 uImage 和设备树相同。用 initramfs-tools-core 软件包中的 lsinitramfs 工具可以列出 initrd 的内容。发行版的 initrd 方案包含了最小化的 /bin/sbin/etc 目录以及内核模块,还有 /scripts 中的一些文件。所有这些看起来都很熟悉,因为 initrd 大致上是一个简单的最小化 Linux 根文件系统。看似相似,其实不然,因为位于虚拟内存盘中的 /bin/sbin 目录下的所有可执行文件几乎都是指向 BusyBox 二进制文件 的符号链接,由此导致 /bin/sbin 目录比 glibc 的小 10 倍。

如果要做的只是加载一些模块,然后在普通的根文件系统上启动 init,为什么还要创建一个 initrd 呢?想想一个加密的根文件系统,解密可能依赖于加载一个位于根文件系统 /lib/modules 的内核模块,当然还有 initrd 中的。加密模块可能被静态地编译到内核中,而不是从文件加载,但有多种原因不希望这样做。例如,用模块静态编译内核可能会使其太大而不能适应存储空间,或者静态编译可能会违反软件许可条款。不出所料,存储、网络和人类输入设备(HID)驱动程序也可能存在于 initrd 中。initrd 基本上包含了任何挂载根文件系统所必需的非内核代码。initrd 也是用户存放 自定义ACPI 表代码的地方。

 title=initrd."" title=" title="Rescue shell and a custom initrd."">

救援模式的 shell 和自定义的 initrd 还是很有意思的。

initrd 对测试文件系统和数据存储设备也很有用。将这些测试工具存放在 initrd 中,并从内存中运行测试,而不是从被测对象中运行。

最后,当 init 开始运行时,系统就启动啦!由于第二个处理器现在在运行,机器已经成为我们所熟知和喜爱的异步、可抢占、不可预测和高性能的生物。的确,ps -o pid,psr,comm -p 1 很容易显示用户空间的 init 进程已不在引导处理器上运行了。

总结

Linux 引导过程听起来或许令人生畏,即使是简单嵌入式设备上的软件数量也是如此。但换个角度来看,启动过程相当简单,因为启动中没有抢占、RCU 和竞争条件等扑朔迷离的复杂功能。只关注内核和 PID 1 会忽略了引导程序和辅助处理器为运行内核执行的大量准备工作。虽然内核在 Linux 程序中是独一无二的,但通过一些检查 ELF 文件的工具也可以了解其结构。学习一个正常的启动过程,可以帮助运维人员处理启动的故障。

要了解更多信息,请参阅 Alison Chaiken 的演讲——Linux: The first second,已于 1 月 22 日至 26 日在悉尼举行。参见 linux.conf.au

感谢 Akkana Peck 的提议和指正。


via: https://opensource.com/article/18/1/analyzing-linux-boot-process

作者:Alison Chaiken 译者:jessie-pang 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

 title=

Konstantin Ryabitsev 为你讲解哪个 Linux 内核版本可以被视作“稳定版”,以及你应该如何选择一个适用你的内核版本。

每次 Linus Torvalds 发布 一个新 Linux 内核的主线版本,几乎都会引起这种困惑,那就是到底哪个内核版本才是最新的“稳定版”?是新的那个 X.Y,还是前面的那个 X.Y-1.Z ?最新的内核版本是不是太“新”了?你是不是应该坚持使用以前的版本?

kernel.org 网页上的信息并不会帮你解开这个困惑。目前,在该页面的最顶部,我们看到是最新稳定版内核是 4.15 — 但是在这个表格的下面,4.14.16 也被列为“ 稳定版 stable ”,而 4.15 被列为“ 主线版本 mainline ”,很困惑,是吧?

不幸的是,这个问题并不好回答。我们在这里使用“稳定”这个词有两个不同的意思:一是,作为最初发布的 Git 树的名字,二是,表示这个内核可以被视作“稳定版”,用在“生产系统”。

由于 Git 的分布式特性,Linux 的开发工作在许多 不同的分叉仓库中 进行。所有的 bug 修复和新特性也是首先由各个子系统维护者收集和准备的,然后提交给 Linus Torvalds,由 Linus Torvalds 包含进 他自己的 Linux 树 中,他的 Git 树被认为是 Git 仓库的 “master”。我们称这个树为 “主线” Linux 树。

候选发布版(RC)

在每个新的内核版本发布之前,它都要经过几轮的“候选发布”,它由开发者进行测试并“打磨”所有的这些很酷的新特性。基于他们这几轮测试的反馈,Linus 决定最终版本是否已经准备就绪。通常有 7 个每周预发布版本,但是,这个数字经常走到 -rc8,并且有时候甚至达到 -rc9 及以上。当 Linus 确信那个新内核已经没有问题了,他就制作最终发行版,我们称这个版本为“稳定版”,表示它不再是一个“候选发布版”。

Bug 修复

就像任何一个由不是十全十美的人所写的复杂软件一样,任何一个 Linux 内核的新版本都包含 bug,并且这些 bug 必须被修复。Linux 内核的 bug 修复规则非常简单:所有修复必须首先进入到 Linus 的树。一旦主线仓库中的 bug 被修复后,它接着会被应用到内核开发社区仍在维护的已发布内核中。在它们被考虑回迁到已发布的稳定版本之前,所有的 bug 修复必须满足 一套重要的标准 — 标准的其中之一是,它们 “必须已经存在于 Linus 的树中”。这是一个 独立的 Git 仓库,维护它的用途是回迁 bug 修复,而它也被称为“稳定”树 —— 因为它用于跟踪以前发布的稳定内核。这个树由 Greg Kroah-Hartman 策划和维护。

最新的稳定内核

因此,无论在什么时候,为了查看最新的稳定内核而访问 kernel.org 网站时,你应该去使用那个在大黄色按钮所说的“最新的稳定内核”。

但是,你可能会惊奇地发现 —— 4.15 和 4.14.16 都是稳定版本,那么到底哪一个更“稳定”呢?有些人不愿意使用 “.0” 的内核发行版,因为他们认为这个版本并不足够“稳定”,直到最新的是 ".1" 的为止。很难证明或者反驳这种观点的对与错,并且这两种观点都有赞成或者反对的理由,因此,具体选择哪一个取决于你的喜好。

一方面,任何一个进入到稳定树的发行版都必须首先被接受进入主线内核版本中,并且随后会被回迁到已发行版本中。这意味着内核的主线版本相比稳定树中的发行版本来说,总包含有最新的 bug 修复,因此,如果你想使用的发行版包含的“已知 bug”最少,那么使用 “.0” 的主线发行版是最佳选择。

另一方面,主线版本增加了所有很酷的新特性 —— 而新特性也给它们带来了数量未知的“新 bug”,而这些“新 bug”在老的稳定版中是不会存在的。而新的、未知的 bug 是否比旧的、已知的但尚未修复的 bug 更加令人担心呢? —— 这取决于你的选择。不过需要说明的一点是,许多 bug 修复只对内核的主线版本进行了彻底的测试。当补丁回迁到旧内核时,它们可能会工作的很好,但是它们很少做与旧内核的集成测试工作。通常都假定,“以前的稳定版本”足够接近当前的确信可用于生产系统的主线版本。而实际上也确实是这样的,当然,这也更加说明了为什么选择“哪个内核版本更稳定”是件非常困难的事情了。

因此,从根本上说,我们并没有定量的或者定性的手段去明确的告诉你哪个内核版本更加稳定 —— 4.15 还是 4.14.16?我们能够做到的只是告诉你,它们具有“不同的稳定性”,(这个答案可能没有帮到你,但是,至少你明白了这些版本的差别是什么?)。

学习更多的 Linux 的知识,可以通过来自 Linux 基金会和 edX 的免费课程 "认识 Linux"


via: https://www.linux.com/blog/learn/2018/2/which-linux-kernel-version-stable

作者:KONSTANTIN RYABITSEV 译者:qhwdw 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

 title=

Linus Torvalds 在周日发布了 Linux 的 4.15 版内核,比原计划发布时间晚了一周。了解这次发行版的关键更新。

Linus Torvalds 在周日(1 月 28 日)发布了 Linux 内核的 4.15 版,再一次比原计划晚了一周。延迟发布的罪魁祸首是 “Meltdown” 和 “Spectre” bug,由于这两个漏洞,使开发者不得不在这最后的周期中提交重大补丁。Torvalds 不愿意“赶工”,因此,他又给了一周时间去制作这个发行版本。

不出意外的话,这第一批补丁将是去修补前面提及的 Meltdown 和 Spectre 漏洞。为防范 Meltdown —— 这个影响 Intel 芯片的问题,在 x86 架构上开发者实现了页表隔离(PTI)。不论什么理由你如果想去关闭它,你可以使用内核引导选项 pti=off 去关闭这个特性。

Spectre v2 漏洞对 Intel 和 AMD 芯片都有影响,为防范它,内核现在带来了 retpoline 机制。Retpoline 要求 GCC 的版本支持 -mindirect-branch=thunk-extern 功能。由于使用了 PTI,Spectre 抑制机制可以被关闭,如果需要去关闭它,在引导时使用 spectre_v2=off 选项。尽管开发者努力去解决 Spectre v1,但是,到目前为止还没有一个解决方案,因此,在 4.15 的内核版本中并没有这个 bug 的修补程序。

对于在 ARM 上的 Meltdown 解决方案也将在下一个开发周期中推送。但是,对于 PowerPC 上的 bug,在这个发行版中包含了一个补救措施,那就是使用 L1-D 缓存的 RFI 冲刷特性

一个有趣的事情是,上面提及的所有受影响的新内核中,都带有一个 /sys/devices/system/cpu/vulnerabilities/ 虚拟目录。这个目录显示了影响你的 CPU 的漏洞以及当前应用的补救措施。

芯片带 bug (以及保守秘密的制造商)的问题重新唤起了开发可行的开源替代品的呼声。这使得已经合并到主线版本的内核提供了对 RISC-V 芯片的部分支持。RISC-V 是一个开源的指令集架构,它允许制造商去设计他们自己的基于 RISC-V 芯片的实现。并且因此也有了几个开源的芯片。虽然 RISC-V 芯片目前主要用于嵌入式设备,它能够去做像智能硬盘或者像 Arduino 这样的开发板,RISC-V 的支持者认为这个架构也可以用于个人电脑甚至是多节点的超级计算机上。

正如在上面提到的,对 RISC-V 的支持,仍然没有全部完成,它虽然包含了架构代码,但是没有设备驱动。这意味着,虽然 Linux 内核可以在 RISC-V 芯片上运行,但是没有可行的方式与底层的硬件进行实质的交互。也就是说,RISC-V 不会受到其它闭源架构上的任何 bug 的影响,并且对它的支持的开发工作也在加速进行,因为,RISC-V 基金会已经得到了一些行业巨头的支持

4.15 版新内核中的其它新特性

Torvalds 经常说他喜欢的事情是很无聊的。对他来说,幸运的是,除了 Spectre 和 Meltdown 引发的混乱之外,在 4.15 内核中的大部分其它东西都很普通,比如,对驱动的进一步改进、对新设备的支持等等。但是,还有几点需要重点指出,它们是:

  • AMD 对虚拟化安全加密的支持。它允许内核通过加密来实现对虚拟机内存的保护。加密的内存仅能够被使用它的虚拟机所解密。就算是 hypervisor 也不能看到它内部的数据。这意味着在云中虚拟机正在处理的数据,在虚拟机外的任何进程都看不到。
  • 由于 包含了显示代码, AMD GPU 得到了极大的提升,这使得 Radeon RX Vega 和 Raven Ridge 显卡得到了内核主线版本的支持,并且也在 AMD 显卡中实现了 HDMI/DP 音频。
  • 树莓派的爱好者应该很高兴,因为在新内核中, 7" 触摸屏现在已经得到原生支持,这将产生成百上千的有趣的项目。

要发现更多的特性,你可以去查看在 Kernel NewbiesPhoronix 上的内容。


via: https://www.linux.com/blog/intro-to-linux/2018/1/linux-kernel-415-unusual-release-cycle

作者:PAUL BROWN 译者:qhwdw 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

英特尔处理器曝出了一个严重的硬件设计漏洞,迫使包括 Linux、Windows 在内的主要操作系统和各大云计算服务商都忙着打补丁。因为漏洞信息没有解密,所以目前只能通过已发布的补丁反推这个漏洞

这里是一篇对该漏洞的技术分析文章。

在十月底的时候,KAISER 补丁集被披露了;它做了一项工作,将内核空间与用户空间使用的 页表 page tables 进行了隔离,以解决 x86 处理器上向攻击者透露内核布局的安全漏洞。这些补丁是自它们被公布以来,这一星期中最值关注的事情,但是,它们似乎正在接近最终的状态。这应该是再次审视它们的合适机会。

这项工作被重命名为 “ 内核页表隔离 kernel page-table isolation ” (KPTI),但是目的是一样的:分割页表,将现在被用户空间和内核空间共享使用的这张表分成两套,内核空间和用户空间各自使用一个。这对内核的内存管理产生了根本性的变化,并且,这是本来人们期望先争论多年再做决定的,尤其是考虑到它的性能影响的时候。不过,KPTI 仍然处于快速发展的轨道上。一组预备补丁 已被被合并到 4.15 - rc4 之后的主版本线上了 — 一般情况下仅重要的修复才被允许这样做 — 并且其余的似乎被确定进入 4.16 版的合并窗口中。许多内核开发者都在这项工作上投入了大量的时间,并且 Linus Torvalds 要求 将这项工作 回迁 backport 到长期稳定内核中。

也就是说,KPTI 已经在最后期限的压力下安全补丁的所有标记都已经就绪了。对于任何基于 ARM 的读者,在这里值的注意的是,在这项工作中有一个 为 arm64 的等效补丁集

51 个补丁乃至更多

在这篇文章中,x86 补丁系列正处在 163 版本。它包含 51 个补丁,因此,我们应该感谢那些没有公开的版本。最初的补丁集,由 Dave Hansen 发布,由 Thomas Gleixner、Peter Zijlstra、Andy Lutomirski、和 Hugh Dickins 根据许多其它人的建议,做了大量的修订。任何还存在的缺陷都不是由于没有足够多的有经验的开发人员过目所导致的。

在现代系统中,页表是以一个树形结构进行组织的,这样可以高效地存储稀疏内存映射和支持巨页特性;可以查看这篇 2005 年的文章 了解更多细节以及它是怎么工作的示意图。在一个有四级页面表的系统上(目前的大多数大型系统都是这样),顶级是页面全局目录(PGD)。紧接着是页面上层目录(PUD)、页面中层目录(PMD)和页面表条目(PTE)。有五级页面表的系统是在 PGD 下面插入了一层(称为 P4D)。

页面故障解析通常遍历整个树去查找所需的 PTE,但是,巨页可以被更高层级的特定条目所表示。例如,一个 2MB 的内存 chunk 既可以由 PMD 层级的一个单个的巨页条目表示,也可以由一个单页 PTE 条目的完整页面表示。

在当前的内核中,每个处理器有一个单个的 PGD;在 KPTI 系列补丁中所采取的第一步的其中一个措施是,去创建一个第二个 PGD。当内核运行时,原来的仍然在使用;它映射所有的地址空间。当处理器运行在用户空间时,(在打完该系列补丁之后)第二个被激活。它指向属于该进程的页面的相同目录层次,但是,描述内核空间(位于虚拟地址空间的顶端)的部分通常都不在这里。

页表条目包含权限描述位,它们记录了内存该如何被访问;不用说都知道,这些位是用来设置阻止用户空间访问内核页面的,即便是通过那些被映射到该地址空间的页面访问。不幸的是,一些硬件级的错误允许用户空间的攻击者去确定一个给定的内核空间地址是否被映射,而不管那个页面上映射的地址是否被允许访问。而那个信息可以被用于击败内核地址空间布局随机化,可以使一个本地的攻击者更易于得逞。在 KPTI 背后的核心思想是,切换到一个没有内核空间映射的 PGD,将会使基于这个漏洞的攻击失效,而到现在为止,我们还没有看到这些攻击。

细节

这个想法很简单,但是,就像经常发生的那样,有各种各样麻烦的细节使得这个简单的想法变成了一个由 51 个部分构成的补丁集。其中最初的一个是,如果处理器在用户模式运行时响应一个硬件中断,处理中断需要的内核代码将在地址空间中不存在。因此,必须有足够的内核代码映射在用户模式中,以能够切换回到内核 PGD,使剩余的代码也可用。对于 traps、非屏蔽中断、和系统调用,也存在一个相似的情况。这个代码很小而且可以与其它部分隔离,但是,在处理安全且有效地切换时,涉及到一些很复杂的细节。

另一个难题来自 x86 本地描述符表(LDT)的构成,它可以被用于去改变用户空间的内存布局。它可以使用鲜为人知的 modify_ldt() 系统调用来做微调。例如,在 Linux 上早期的 POSIX 线程实现,使用了 LDT 去创建一个本地线程存储区域。在现在的 Linux 系统上,LDT 几乎不再使用了,但是,一些应用程序(比如,Wine)仍然需要它。当它被使用时,LDT 必须能够被用户空间和内核空间都可以访问到,但是,它必须一直处于内核空间中。KPTI 补丁集打乱内核附近的内存,在 PGD 级别上为 LDT 保留一个完全的条目;因此,vmalloc() 调用的可用空间收缩到仅有 12,800TB。那是一个非常巨大的 LDT 空间数,可以满足有很多 CPU 系统的需要。这种变化的其中一个结果是,LDT 的位置将是固定的,并且已知道用户空间 ——因此这将是个潜在的问题,由于覆写 LDT 的能力很容易被用来破坏整个系统。在这个系列的最终的补丁是映射为只读 LDT,以阻止此类攻击。

另一个潜在的安全缺陷是,如果内核可以一直被操纵直至返回用户空间,以至于不切换回经过过滤的 PGD。因为内核空间 PGD 也映射用户空间内存,这种疏忽可能在一段时间内不会被察觉到。对此问题的应对方法是将虚拟内存空间中用户空间的部分以非可执行的方式映射到内核的 PGD。只要用户空间(的程序)开始从一个错误的页面表开始执行,它将会立即崩溃。

最后,虽然所有已存在的 x86 处理器似乎都会受到这个信息泄露的漏洞影响,但是,以后的处理器可能不会受此影响。KPTI 有一个可测量的运行时成本,估计在 5%。有些用户也许不愿意为这些成本埋单,尤其是他们拿到了不存在这个问题的新处理器之后。为此将会有一个 nopti (内核)命令行选项来在启动的时候禁用这个机制。这个补丁系列也增加了一个新的“特性”标识(X86_BUG_CPU_INSECURE)去标识有漏洞的 CPU;它被设置在现在所有的 x86 CPU 上(LCTT 译注:AMD 表示不背这锅),但是在以后的硬件上可能没有。如果没有该特性标识,页面隔离将自动被关闭。

在 4.16 版的合并窗口打开之前剩下将近一个月。在这期间,针对一些新发现而不可避免的小毛病,KPTI 补丁集毫无疑问的将迎来一系列的小修订。一旦所有的事情都敲定了,看起来这些代码将会被合并同时以相对快的速度迁回到稳定版本的内核。显而易见的是,我们将会收到一个更慢,但是更安全的内核作为一个新年礼物。


via: https://lwn.net/SubscriberLink/741878/eb6c9d3913d7cb2b/

作者:Jonathan Corbet 译者:qhwdw 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出