ubuntu20.04内核重新编译(5.15.x)

一、源码获取

方法1:

git clone git://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/focal

方法2:

# apt-cache search linux-source
linux-source - Linux kernel source with Ubuntu patches
linux-source-5.4.0 - Linux kernel source for version 5.4.0 with Ubuntu patches
linux-gkeop-source-5.4.0 - Linux kernel source for version 5.4.0 with Ubuntu patches
linux-hwe-5.11-source-5.11.0 - Linux kernel source for version 5.11.0 with Ubuntu patches
linux-hwe-5.13-source-5.13.0 - Linux kernel source for version 5.13.0 with Ubuntu patches
linux-hwe-5.15-source-5.15.0 - Linux kernel source for version 5.15.0 with Ubuntu patches
linux-hwe-5.8-source-5.8.0 - Linux kernel source for version 5.8.0 with Ubuntu patches
linux-intel-5.13-source-5.13.0 - Linux kernel source for version 5.13.0 with Ubuntu patches

选择linux-hwe-5.15-source-5.15.0下载:

apt-get source linux-hwe-5.15-source-5.15.0

如果执行上述命令报错的话,需要编辑 /etc/apt/sources.list ,去掉所有关于deb-src的注释,然后执行 apt-get update 更新下载源的列表,然后再执行 apt-get source linux-hwe-5.15-source-5.15.0 下载kernel源码。

二、源码编译

我们这里按照方法1获取源码,进入到源码目录,执行 git tag 查看各个历史发行版本, git checkout 到某个你想编译的版本,例如: git checkout Ubuntu-hwe-5.15-5.15.0-119.129_20.04.1 。

1.修改Makefile文件

根据 uname -r 的结果,比如我的内核版本是5.15.0-119-generic,那就按照如下方式修改Makefile,保证编译的内核和模块的vermagic版本和当前内核版本一致。

# SPDX-License-Identifier: GPL-2.0
VERSION = 5
PATCHLEVEL = 15
SUBLEVEL = 0
EXTRAVERSION = -119-generic
NAME = Trick or Treat

2. 准备config文件

内核源码编译所用的config文件可以从装有ubuntu系统的机器内部拷贝一份,我们这里从/boot/config-5.15.0-119-generic或者/usr/src/linux-headers-5.15.0-119-generic/.config拷贝。

cp /boot/config-5.15.0-119-generic .config

注意:需要把内核CONFIG_DEBUG_INFO配置关掉,不然会因为编译完安装内核时生成的initrd.img-5.15.0-119-generic太大而导致系统启动时报“out of memory”的错误导致系统起不来。加上debug信息生成的init ramfs大概有1GB左右,太TM大了。

 make menuconfig - - ->  Kernel hacking - - ->   Compile-time checks and compiler options  - - ->  [ ] Compile the kernel with debug info  

去掉 [ ] Compile the kernel with debug info  的同时会顺带去掉内核BTF信息的生成,BTF这个信息太坑了,即使在我编译出的模块的vermagic和module_layout值都和当前内核已加载模块的值相同时(查看模块module_layout值得方法:modprobe --dump-modversions xxx.ko | grep module_layout),仍然不能成功加载编译的模块,就是会报BTF(-22)相关的错误,除非我安装了我重新编译的内核,然后才能正常安装编译出的模块。

3. 编译前到底要不要执行make mrproper?

执行mrproper会删除源码目录下的debian目录、以及.config等文件,根据上一步骤中.config文件的签名相关配置:

#
# Certificates for signature checking
#
CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
CONFIG_MODULE_SIG_KEY_TYPE_RSA=y
# CONFIG_MODULE_SIG_KEY_TYPE_ECDSA is not set
CONFIG_SYSTEM_TRUSTED_KEYRING=y
CONFIG_SYSTEM_TRUSTED_KEYS="debian/canonical-certs.pem"
CONFIG_SYSTEM_EXTRA_CERTIFICATE=y
CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE=4096
CONFIG_SECONDARY_TRUSTED_KEYRING=y
CONFIG_SYSTEM_BLACKLIST_KEYRING=y
CONFIG_SYSTEM_BLACKLIST_HASH_LIST=""
CONFIG_SYSTEM_REVOCATION_LIST=y
CONFIG_SYSTEM_REVOCATION_KEYS="debian/canonical-revoked-certs.pem"
# end of Certificates for signature checking

是需要debian目录下的canonical-certs.pem和canonical-revoked-certs.pem key的。

还有就是生成模块签名的时候,通过执行debian/scripts/sign-module来生成各个模块的签名,所以说需要生成模块签名的话,不能执行 make mrproper 。

不需要生成模块签名的话,就把上述.config里的CONFIG_MODULE_SIG_KEY、CONFIG_SYSTEM_TRUSTED_KEYS和CONFIG_SYSTEM_REVOCATION_KEYS全改为=””即可。

4. 编译前准备:执行make oldconfig

 make oldconfig 会根据源码结构和内容来验证源码目录下的.config是否需要修改,如果.config不需要修改的话,会显示No change。如果需要修改.config配置的话,根据提示进行相应的操作即可,这里我一般全都是输入‘N’然后回车,即不增加新的配置。

5. 编译内核和模块

编译之前先执行一下 chmod +x scripts/* 确保相关脚本都有可执行权限。

make -j8 LOCALVERSION='' all

编译的时候可能会异常结束,往上翻看编译的过程会发现提示没找到canonical-certs.pem和canonical-revoked-certs.pem。

在Linux内核配置中,CONFIG_SYSTEM_TRUSTED_KEYS和CONFIG_SYSTEM_REVOCATION_KEYS是与内核中的签名验证机制相关的配置选项。这些配置通常与Secure Boot和模块签名验证相关。下面详细解释这两个配置选项的作用:

CONFIG_SYSTEM_TRUSTED_KEYS

CONFIG_SYSTEM_TRUSTED_KEYS指定了一个包含受信任公钥的文件,这些公钥用于验证内核模块的签名。当启用模块签名功能(CONFIG_MODULE_SIG)时,内核将使用这些公钥来检查每个加载模块的签名,以确保它们未被篡改且来自可信来源。

例如,CONFIG_SYSTEM_TRUSTED_KEYS="debian/canonical-certs.pem"表示使用`debian/canonical-certs.pem`文件中的公钥作为信任的根证书来验证模块的签名。

CONFIG_SYSTEM_REVOCATION_KEYS

CONFIG_SYSTEM_REVOCATION_KEYS指定了一个包含已撤销公钥的文件。这些撤销的公钥不再被视为有效,任何使用这些公钥签名的模块都将被拒绝加载。这是一种安全机制,用来应对密钥泄露或者其他安全问题,确保不再信任使用这些密钥签名的模块。

例如,CONFIG_SYSTEM_REVOCATION_KEYS="debian/canonical-revoked-certs.pem" 表示内核将拒绝加载任何使用`debian/canonical-revoked-certs.pem`文件中列出的公钥签名的模块。

是否可以移除这些配置?

在编译内核时,如果你不需要使用Secure Boot或者模块签名验证功能,你可以选择不配置这些选项。这可以通过设置:

CONFIG_SYSTEM_TRUSTED_KEYS=""
CONFIG_SYSTEM_REVOCATION_KEYS=""

这样做将禁用这些功能,可能会简化系统配置,减少对特定密钥文件的依赖,特别是在不使用官方预构建内核,或者在一个完全信任的环境中不需要额外的安全验证时。

然而,如果安全性是一个重要考虑因素,特别是在多用户环境或者需要保护系统不被未授权的修改所影响的环境中,建议保留并正确配置这些选项。

如果我们想要保留CONFIG_SYSTEM_TRUSTED_KEYS和CONFIG_SYSTEM_REVOCATION_KEYS这俩配置,但是内核源码目录里并没有canonical-certs.pem和canonical-revoked-certs.pem的话,参考“源码获取-方法2”,把使用方法2下载的源码目录里的debian/canonical-certs.pem和debian/canonical-revoked-certs.pem拷贝到当前源码debian目录下即可。

6. 安装内核和模块

安装模块之前执行一遍 chmod +x debian/scripts/* 给debian/scripts/sign-module加上可执行权限,确保模块的签名能正常生成。

先安装模块:

make module_install

默认安装在/lib/modules/5.15.0-119-generic/目录下,如果想把编译好的模块安装到指定目录的话,执行 make INSTALL_MOD_PATH=/path/to/install modules_install 安装编译好的模块到/path/to/install目录下。

只有在执行 make module_install 的时候才会生成模块的签名信息,模块的签名信息和vermagic可以通过modinfo xxx.ko查看。

也可以手动生成单个模块的签名信息:

scripts/sign-file sha512 ./certs/signing_key.pem ./certs/signing_key.x509 module.ko

 

再安装内核:

make install

然后重启机器, uname -a 查看当前内核的版本和生成时间是否正确。

如果编译安装的内核版本和之前的版本不一致的话,重启机器使用的可能不是最新编译的内核,需要修改/etc/default/grub中的 GRUB_DEFAULT= 为你想加载的内核版本,我们这里 grep menuentry /boot/grub/grub.cfg 查看第一条menuentry是否是我们想要加载的内核,不是的话修改 'GRUB_DEFAULT=Ubuntu, with Linux 5.15.0-119-generic', 并执行update-grub然后重启即可。

7. 结尾

!!!保存好 'certs/signing_key.pem','certs/signing_key.x509','debian/canonical-certs.pem' 和 'debian/canonical-revoked-certs.pem'这四个密钥,别人如果想编译这个版本的内核模块的时候需要用到,不然的话,由于签名验证不通过,别人编译好的模块加载时会报“module verification failed: signature and/or required key missing - tainting kernel”的warning。

posted @ 2024-08-28 16:07  闹闹爸爸  阅读(342)  评论(0编辑  收藏  举报