目 录
1 Linux引导过程
2 BIOS功能描述
3 BootLoader流程分析
4 vmlinuz文件分析
5 initrd (initramfs)文件分析
6 Linux systemd启动流程
7 Cgroups与systemd关系
8 systemd启动目标单元分析
BIOS(基本输入输出系统)是烧录计算机在主板芯片上的程序,它保存着计算机基本的输入输出的程序,开机后的硬件自检程序和系统自启动程序,它从COMS中读写系统的设置的具体信息,为计算机提供最底层的硬件控制。
BIOS设置硬件参数,设置显示类型核显显示、独立显示和自动,设置串口协议和波特率,常见协议有RS-232,RS-422,RS-485,设置启动硬盘(安装双系统建议使用两块硬盘),控制风扇转速和模式,设置TPM模式,是否上电自启,设置CPU功耗,设置网络的POE供电功能,设置BOOT启动模式传统模式(Legacy Boot Type)、UEFI模式和双模式,设置PXE网络协议启动,设置是否开启门口看门狗-WDT(当检测到系统程序非正常运行后,会强制CPU发送复位信号使整个系统复位)
BIOS也是一些病毒木马攻击的目标
例:
谍影木马支持的BIOS版本非常多,是目前已知的唯一能够感染UEFI主板的木马,恶意
代码可能是有非法份子烧录的主板中的,现阶段只能重新烧录BIOS,才可以彻底清理谍影 木马。
类似的病毒木马还有TrickBot,暗云III,双枪,隐魂,等幽灵木马。日常使用建议保持主 机固件的更新,启用BIOS写保护。
与传统BIOS(汇编语言)具有相同功能的还有UEFI(c语言)。
常见的引导方式:
传统模式由于是MBR分区无法引导2TB以上的硬盘。
UEFI模式采用GPT分区可以引导大于2TB以上的硬盘并且向下兼容MBR。
boot loader一般分为两个阶段,第一个阶段使用用汇编来实现,它完成了一些依赖于CPU体系结构的初始化,并调用第二阶段的代码,第二阶段通常使用C语言来实现,这样可以实 现更复杂的功能,而且代码会有更好的可读性和移植性。
第一阶段功能
第二阶段功能
在Linux系统中,vmlinux (vmlinuz) 是一个包含Linux Kernel的静态链接的可执行文件,文件类型可能是Linux接受的可执行文件格式之一(ELF和COFF),vmlinux若要用于调试是则必须要在引导前增加symbol table。
应用场景:
相关内容:
实践:
本质上,vmlinuz-$(uname -r)是一个gzip压缩文件,但是不能直接用gzip指令解压,因为在这个文件的开头嵌入了gzip的代码。所以首先用指令C找到真正的压缩文件的头部,这个指令的输出如下:
0018864 ac fe ff ff 1f 8b 08 00 00 00 00 00 02 03 ec fd
然后执行下面的指令,其中的18868就是18864+4,这里4是指1f 8b 08前面有4个字节。
dd if=vmlinuz-$(uname -r) bs=1 skip=18868 | zcat > vmlinuz-gakki
objdump -D vmlinuz-gakki >> result
result是一个汇编文件,而vmlinuz-gakki文件本质上是一个可执行程序,可以尝试执行它
chmod +x vmlinuz-gakki && ./vmlinuz-gakki
显示 Segmentation fault(存储器段错误或访问权限冲突)
Linux允许将一部分内存作为块设备(RAM block device support)。这通常见于完全运行在内存上的Linux的live发行版。Linux的live发行版会卸载光盘并接着加载到内存中,所以在尝试一个新的操作系统或者修复另一个系统时不会伤害到已安装的系统。
initrd是一个内存中的磁盘结构(ramdisk),它把(initrd)文件系统当做可启动文件系统。用于在内核把控制权交给根文件系统上的init应用程序之前挂载所需的文件系统initrd。Linux内核在此根文件系统上执行脚本(通常称为linuxrc),此脚本的工作是准备系统,切换到真正的根文件系统,然后调用init。
initramfs即initram file system,翻译成中文的意思就是初始化ram文件系统,基于tmpfs,是一种大小灵活,直接作用在内存中的文件系统。initramfs包含的工具和脚本,在正式的根文件系统初始化启动之前,就被挂载了。initramfs是可选的,内核编译选项默认开启initramfs。
应用场景:
initramfs在内核启动的早期提供一个用户态环境,用于完成在内核启动阶段不易完成的工作。
initramfs包含的工具可以解密抽象层(用于加密的文件系统),逻辑卷管理器,软RAID,
蓝牙驱动程序等。
一个initramfs至少包含一个文件,即systemd,内核将这个文件执行起来的进程设
为main init进程,pid=1。内核挂载initramfs时,文件系统的根分区并没有挂载,所以无法访问 文件系统中的文件。多数的嵌入式设备需要一个shell,那么也会在initramfs打包进一个shell。如 果还需要其他工具或脚本,也可以打包到initramfs。
注意:打包时,必须包含依赖,因为initramfs是一个能够独立运行的ram文件系统。
Tips:dracut是用来制作更轻量化initramfs的工具,它的使用方式跟mkinitrd非常接近,迁移成本较低。
实践:
首先将/boot/initramfs-$(uname -r).img文件复制到/tmp文件夹下
执行file initramfs-5.10.x86_64.img,得到如下结果:
initramfs-5.10.x86_64.img: gzip compressed data, max compression, from Unix, original size 75768832
可以看到它本质上是一个gzip格式的压缩文件
mv initramfs-5.10.x86_64.img initramfs-5.10.x86_64.img.gz
gzip -d initramfs-5.10.x86_64.img.gz
file initramfs-5.10.x86_64.img
显示 initramfs-5.10.x86_64.img: ASCII cpio archive (SVR4 with no CRC)
这是一个cpio文件
执行cpio -idmv < initramfs-5.10.x86_64.img
生成了一个小型的根文件系统(rootfs)。
在用户真正使用的根文件系统sysroot启动之前,内核用先启动initramfs(虚根)文件系统systemd,systemd完成启动后会挂载sysroot(逻辑根目录),然后切换到根文件系统,再次执行systemd。
Tips:使用命令man bootup 可以查看系统内systemd启动流程的手册原文。
两次执行的systemd流程类似,如下图:
描述:
系统引导涉及许多不同的组件。在上电之后,系统BIOS将立即进行最小的硬件初始化,并将控制权移交给MBR(持久存储中的引导加载程序存储设备)。
然后,这个引导加载程序将从磁盘(或网络)调用操作系统内核。在Linux情况下,该内核(可选)提取并执行初始RAM磁盘映像(initrd)。
例如由Dracut(8),它查找根文件系统(可能为此使用systemd(1))。找到并挂载根文件系统后,initrd将控制权移交给主机的系统管理器(例如systemd(1))。
存储在操作系统映像中,然后该映像负责检测所有剩余的硬件,挂载所有必要的文件系统并生成所有配置的服务。
在关闭时,系统管理器停止所有服务,卸载所有文件系统(卸载支持它们的存储技术),然后(可选地)跳转回卸载/卸载根目录的initrd代码文件系统及其所在的存储。最后一步是关闭系统的电源。
系统管理器(systemd)启动:
在引导时,操作系统映像上的系统管理器负责初始化操作系统所需的文件系统、服务和驱动程序。在systemd(1)系统上,这个进程被拆分。
这个过程被分散到以systemd.target为单元的多个步骤中。有关目标单元的详细信息,参见system .target(5)。启动过程是高度并行的,以便特定目标的启动顺序的单元是不确定的,但仍然坚持有限数量的排序结构。
当systemd启动系统时,它将激活所有依赖于default的单元。目标(以及递归地使用这些依赖的所有依赖项)。Target只是一个别名。
graphical.target(图形界面)或multi-user.target(多用户模式或文本模式),这取决于系统是配置为图形UI还是仅配置为文本控制台,graphical.target和multi-user.target对应systemV中的运行级别init5 和init3。
目录/etc/systemd/system/multi-user.target.wants/,这里的服务是用户自定义的systemd的开机启动项。
目录/usr/lib/systemd/system/multi-user.target.wants/,是系统开机启用的systemd。
该目录结构:
下图是这些众所周知的单元及其在启动逻辑中的位置的结构概述。箭头描述了哪些单元被启动,并在其他单元之前排序。
在接近图表底部的单元之前开始。
重点强调通常用作引导目标的目标单元。这些单元是作为目标目标的很好的选择,例如将它们传递给systemd.unit = kernel命令行选项(参见systemd(1))或将创建default.target。
timers.target被基本拉入。异步的目标。这允许计时器单元依赖于只有在引导之后才可用的服务。
在初始ram磁盘(initrd)中启动:
初始RAM磁盘实现(initrd)也可以使用systemd设置。在这种情况下,initrd内部的引导遵循以下结构。
initrd中的默认目标器为initrd.target。启动过程的开始与系统管理器的启动过程相同(参见上面),直到它到达basic.target。从那里,systemd接近特殊目标。
initrd.target。在挂载任何文件系统之前,必须确定系统是将从休眠状态恢复还是继续正常引导。这是通过[email protected]必须完成的。
在local-fs-pre.target之前完成。因此在检查完成之前不能挂载任何文件系统。如果根设备可以挂载,当根设备可用时,启动initd-root-device.target。
/sysroot sysroot.mount单元开始活动到initrd-root-fs.target。initrd-parse-etc.service扫描/sysroot/etc/fstab,查找/usr挂载点和可以用的挂载点。
x-initrd.mount选项。找到的所有条目都挂载在到/sysroot和initrd-fs.target。initrd-cleanup.service隔离到initrd-switch-root.target,可以在其中运行清理服务。
随着最后一步,initrd-switch-root.service被激活,将导致系统将根目录切换到/sysroot。
系统管理器关闭:
使用systemd的系统关闭也包含各种目标单元,并应用了一些最小顺序结构。
强调了常用的系统关闭目标。
system-halt.service(8),system-reboot.service,systemd-poweroff.service,systemd-kexec.service将把系统和服务器管理器(PID 1)转换到系统关闭的第二阶段(已实现)。
在system -shutdown二进制文件中,它将卸载所有剩余的文件系统,杀死所有剩余的进程并释放所有剩余的资源,简单而稳健,不接受任何服务或单元。
再把概念考虑进去。在这一点上,常规的应用程序和资源通常已经终止和释放,因此,第二阶段只能作为无法停止的一切的安全网。
或者在上面描述的基于单元的主要停机阶段由于某种原因释放。
当Linux的init系统发展到systemd之后,systemd与cgrops发生了融合(或者说systemd提供了cgroups的使用和管理接口),systemd管理的东西非常多。
描述:
Cgroups是Linux内核提供的一种机制。
systemd依赖Cgroups:
Cgroups分为两个方面,层级机构(A)和资源控制(B)。首先cgroups是以层级结构组织并标识进程的一种方式,同时它也是在该层级结构上执行资源限制的一种方式。我们简单的包cgroups的层级结构称为A,把cgroups的资源控制能力称为B。
对于systemd来说,A是必须的,如果没有A,systemd将不能很好的工作。而B则是可选的,如果你不需要对资源进行控制那么在编译Linux内核时完全去掉B相关的编译选项。
在系统开机阶段,systemd会把支持的controllers(控制器子系统)挂载到默认的/sys/fs/cgrop/目录下面。
Cgroups的默认层级:
通过将cgroup层级系统与systemd unit树绑定,systemd可以把资源管理的设置从进程级别移动至应用程序级别。
默认情况下,systemd会自动创建slice、scope、和service unit的层级(slice、scope和service都是systemd和unit类型),来为cgroup树提供统一的层级结构。
系统中运行的所有进程,都是systemd init进程的子进程。
在资源管控方面,systemd提供了三种unit类型:
我们可以通过systemd-cgls命令查看cgroups的层级结构:
service、scope和slice unit被直接映射到cgroup树中的对象。当这些unit被激活时,它们或直接一一映射到有unit名建立的cgroup路径中。例如,crond.service属于system.slice,会直接映射到cgroup system.slice/crond.service/中。
下图显示为操作系统瀑布状的启动流程: