Ubuntu 22.04 通过编译降级内核版本
虚拟化平台与虚拟机安装
虚拟化平台使用 Windows 自带的 Hyper-V 虚拟机,安装 Ubuntu Server 22.04.1 LTS 系统。在创建虚拟机时选择第二代虚拟机,配置虚拟机的安全设置中安全启动的模板选择“Microsoft UEFI 证书颁发机构”,或直接禁用安全启动,否则会因为 UEFI 安全启动的原因无法进行 Ubuntu 系统的安装与启动。
安装时未启用 LVM。
安装完成之后可以配置 SSH server 后在 host 直接通过 SSH 连接上虚拟机,以避免在虚拟机窗口中输入命令的麻烦。
内核编译准备
安装必要的软件包
1 | sudo apt install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison |
复制配置信息
从当前系统的启动目录复制配置信息到源代码目录,使编译内核的配置与用当前环境一致。
1 | cp /boot/config-$(uname -r) .config |
配置内核的编译参数
使用 make oldconfig
比对当前系统配置信息和新内核选项的差别,并对新增项与修改项做配置。这里也可以直接使用 make olddefconfig
配置所有差异项为默认推荐设置。
使用 make menuconfig
启动 TUI 界面的内核配置工具,可以对编译选项做更详细的设置。
或者可以直接编辑源码目录下 .config
文件进行配置。
配置 Hyper-V 第二代虚拟机驱动
对于 Hyper-V 第二代虚拟机,需要按照此顺序启用(以 built-in 方式)内核中的某些选项,在启用前面的选项之后才可以启用后面的选项:
- CONFIG_HYPERVISOR_GUEST: Processor type and featueres > Linux Guest Support
- CONFIG_PARAVIRT: Processor type and features > Linux Guest Support > Enable paravirtualization code
- CONFIG_PARAVIRT_SPINLOCKS: Processor type and features > Linux Guest Support > Paravirtualization layer for spinlocks
- CONFIG_CONNECTOR: Device Drivers > Connector - unified userspace <-> kernelspase linker
- CONFIG_SCSI_FC_ATTRS: Device Drivers > SCSI device support > SCSI Transports > FiberChannel Transport Attributes
- CONFIG_HYPERV: Device Drivers > Microsoft Hyper-V guest support > Microsoft Hyper-V client drivers
- CONFIG_HYPERV_UTILS: Device Drivers > Microsoft Hyper-V guest support > Microsoft Hyper-V Utilities driver
- CONFIG_HYPERV_BALLOON: Device Drivers > Microsoft Hyper-V guest support > Microsoft Hyper-V Balloon driver
- CONFIG_HYPERV_STORAGE: Device Drivers > SCSI device support > SCSI low-level drivers > Microsoft Hyper-V virtual storage driver
- CONFIG_HYPERV_NET: Device Drivers > Network device support > Microsoft Hyper-V virtual network driver
- CONFIG_HYPERV_KEYBOARD: Device Drivers > Input device support > Hardware I/O ports > Microsoft Synthetic Keyboard driver
- CONFIG_FB_HYPERV: Device Drivers > Graphics support > Frame buffer Devices > Microsoft Hyper-V Synthetic Video support
- CONFIG_HID: Device Drivers > HID support > HID bus support
- CONFIG_HID_HYPERV_MOUSE: Device Drivers > HID support > Special HID drivers > Microsoft Hyper-V mouse driver
- CONFIG_PCI_HYPERV: Bus options (PCI etc.) > Hyper-V PCI Frontend
- CONFIG_VSOCKETS: Networking support > Networking options > Virtual Socket protocol
- CONFIG_HYPERV_VSOCKETS: Networking support > Networking options > Hyper-V transport for Virtual Sockets
system trusted key 文件配置
使用编辑器打开源码目录下 .config
文件,找到如下行:
1 | CONFIG_SYSTEM_TRUSTED_KEYS="debian/canonical-certs.pem" |
将引号中内容删去。
内核编译安装
为提升编译速度,可以临时提升虚拟机的 vCPU 核心数。为防止 SSH 连接掉线导致编译过程中断,可以使用 screen
创建虚拟终端会话。
使用 make -j$(nproc)
开始编译。
编译完成后使用 sudo make modules_install
安装模块。
随后使用 sudo make install
安装内核。
内核签名
若在开启了安全启动的情况下不对自行编译的内核进行签名,在 GRUB 加载内核后会出现 error: bad shim signature
错误。可以对内核进行签名解决。
内核的签名证书需要使用 openssl 生成。
创建配置文件 openssl.cnf
保存密钥信息:
1 | # This definition stops the following lines choking if HOME isn't |
在 home 目录使用 openssl rand -writerand .rnd
创建随机数文件。
使用如下命令创建密钥对:
1 | openssl req -config ./openssl.cnf \ |
将创建的证书转换为 PEM:
1 | openssl x509 -in MOK.der -inform DER -outform PEM -out MOK.pem |
用 PEM 文件签署内核文件:
1 | sudo sbsign --key MOK.priv --cert MOK.pem /boot/vmlinuz-4.19.260 --output /boot/vmlinuz-4.19.260 |
随后使用 mokutil
命令注册密钥:
1 | sudo mokutil --import MOK.der |
按照提示输入密码。随后重新启动系统。在加载 GRUB 之前 shim 的蓝屏界面选择“注册 MOK”,然后跟随菜单完成注册过程。
选择 Enroll MOK
。
可以选择 View key 0
查看密钥属性,也可以直接选择 Continue
继续。
选择 Yes
导入,随后输入使用 mokutil
命令注册密钥时设置的密码。
选择 Reboot
重新启动。
修改 GRUB 默认配置
因为是降级安装,在更新引导项时编译的新内核并不会被设为默认启动项,这里可以编辑 /etc/default/grub
,将 GRUB_TIMEOUT_STYLE=hidden
注释以显示 GRUB 引导菜单,并修改 GRUB_TIMEOUT=0
的数值大于 0 以延长选择时间。在新内核测试成功后还可以修改 GRUB_DEFAULT=0
以默认直接启动至新内核。
若新内核无法通过 UUID 启动,可以取消文件中 GRUB_DISABLE_LINUX_UUID=true
的注释。
修改完成后使用 sudo update-grub2
更新引导配置。
安装完成
配置完成后重新启动选择新内核即可。
重启前:
1 | neko@ubuntu:~$ uname -a |
重启后:
1 | neko@ubuntu:~$ uname -a |
可能出现的问题
缺少 system trusted key 文件
Ubuntu 系统中直接使用 /boot/config-$(uname -r)
配置编译内核可能会出现如下问题:
1 | make[1]: *** 没有规则可制作目标“debian/canonical-certs.pem”,由“certs/x509_certificate_list” 需求。 停止。 |
Ubuntu 的默认配置会使用其自身的证书来签名内核模块,这个证书在从 kernel.org
中下载的内核源代码包中不存在。
可选方案:
- 不使用指定的签名证书。编辑
.config
文件,找到CONFIG_SYSTEM_TRUSTED_KEYS="debian/canonical-certs.pem"
,将双引号中内容删除,这样内核编译时会生成一次性的证书来签名内核模块。 - 自己生成签名证书。
- 使用 Ubuntu 仓库/源中的内核源码包(或提取其中的证书文件)。
- 关闭模块签名机制。
这里选择第一种方式,具体操作请参考配置内核签名文件。
Hyper-V 虚拟机驱动缺失
在不设置 Hyper-V 相关选项直接编译安装时可能会发生如下错误:
1 | VFS: Cannot open root device "mapper/ubuntu--vg-ubuntu--lv" or unknown-block(0,0): errpr -6 |
一开始以为是因为开始 LVM 的原因,经过多次尝试后,尝试在无 LVM 虚拟机上以同样步骤构建内核,发现有同样的问题,仔细分析之后发现内核没有找到硬盘分区,猜想是磁盘驱动问题,解决方案请参考配置 Hyper-V 第二代虚拟机驱动。
PS:加上驱动后还是有这个问题,但是变化是 here are the available partitions:
后面有几行详细的分区信息了。LVM 分区还是有问题,始终无法解决,只好放弃带 LVM 系统的内核编译。
编译安装完成后重启直接进入原内核
因为是降级内核,GRUB 生成引导菜单时会将更新的内核作为默认启动项,可以通过修改 GRUB 默认启动项解决,也可以修改 GRUB 配置后在启动菜单手动选择旧版内核启动。解决方案请参考修改 GRUB 默认配置。
内核签名错误
GRUB 加载内核后会出现 error: bad shim signature
错误,是因为开了 UEFI 安全启动但没有对内核进行签名,解决方案请参考内核签名。