[笔记] CentOS7 手动修补内核过程简记
由于工作需要,需要进行一次对CentOS7系统内核的修补。因为之前没有进行过相关操作,所以把尝试记录下来。
系统信息
CentOS Linux 7 (Core) - Linux 3.10.0-1127.el7.x86_64 - x86_64
下载源码
- 确定内核版本
[root@localhost ~]# uname -r
3.10.0-1127.el7.x86_64
- 根据官方说明下载内核完整镜像并构建
* [https://wiki.centos.org/HowTos/I\_need\_the\_Kernel\_Source](https://wiki.centos.org/HowTos/I_need_the_Kernel_Source#:~:text=2.%20If%20you%20really%20need%20the%20full%20kernel%20source)
* 创建用户并创建目录
* ```
[root@localhost kernels]# useradd kernelmaker
[root@localhost kernels]# passwd kernelmaker
Changing password for user kernelmaker.
New password:
BAD PASSWORD: The password is shorter than 8 characters
Retype new password:
passwd: all authentication tokens updated successfully.
[root@localhost kernels]# su kernelmaker
Attempting to create directory /home/kernelmaker/perl5
[kernelmaker@localhost kernels]$ cd
[kernelmaker@localhost ~]$ echo ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
/home/kernelmaker/rpmbuild/BUILD /home/kernelmaker/rpmbuild/BUILDROOT /home/kernelmaker/rpmbuild/RPMS /home/kernelmaker/rpmbuild/SOURCES /home/kernelmaker/rpmbuild/SPECS /home/kernelmaker/rpmbuild/SRPMS
[kernelmaker@localhost ~]$ mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
[kernelmaker@localhost ~]$ echo echo '%_topdir %(echo $HOME)/rpmbuild'
echo %_topdir %(echo $HOME)/rpmbuild
[kernelmaker@localhost ~]$ echo '%_topdir %(echo $HOME)/rpmbuild'
%_topdir %(echo $HOME)/rpmbuild
[kernelmaker@localhost ~]$ echo '%_topdir %(echo $HOME)/rpmbuild' > ~/.rpmmacros
```
* 安装必备包
* ```
[root@host]# yum install asciidoc audit-libs-devel bash bc binutils binutils-devel bison diffutils elfutils
[root@host]# yum install elfutils-devel elfutils-libelf-devel findutils flex gawk gcc gettext gzip hmaccalc hostname java-devel
[root@host]# yum install m4 make module-init-tools ncurses-devel net-tools newt-devel numactl-devel openssl
[root@host]# yum install patch pciutils-devel perl perl-ExtUtils-Embed pesign python-devel python-docutils redhat-rpm-config
[root@host]# yum install rpm-build sh-utils tar xmlto xz zlib-devel
```
* 下载安装源码包,注意这一步版本号可能需要自己根据情况修改,检查是否在这一Vault路径
* ```
[kernelmaker@localhost ~]$ rpm -i https://vault.centos.org/7.8.2003/os/Source/SPackages/kernel-3.10.0-1127.el7.src.rpm 2>&1 | grep -v 'exist'
[kernelmaker@localhost ~]$ cd ~/rpmbuild/SPECS
```
* 源码将会在`/home/kernelmaker/rpmbuild/BUILD/kernel-3.10.0-1127.el7/linux-3.10.0-1127.el7.x86_64`目录
## 修补内核
### 创建补丁
将补丁创建在 `/home/kernelmaker/rpmbuild/BUILD/kernel-3.10.0-1127.el7/patches/{CNVD_NAME}.patch`方便后续操作。
#### CNVD-2023-05410
- Linux kernel拒绝服务漏洞(CNVD-2023-05410)
- net: sched: disallow noqueue for qdisc classes - Linux Kernel Git
- CVE-2022-47929 Detail - NATIONAL VULNERABILITY DATABASE
由于源文件改动较大,手动修复
if (cl){
err = cops->graft(parent, cl, new, &old);
if (new && new->ops == &noqueue_qdisc_ops) {
NL_SET_ERR_MSG(extack, "Cannot assign noqueue to a class");
return -EINVAL;
}
} else
CNVD-2023-06532
文件可以合并,因此创建Patch来合并修改
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 2c7ff28d5ef5..20759124fa39 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -5956,6 +5956,10 @@ int usb_reset_device(struct usb_device *udev)
return -EISDIR;
}
* if (udev\-\>reset\_in\_progress)
* return \-EINPROGRESS;
* udev\-\>reset\_in\_progress \= 1;
\+
port\_dev \= hub\-\>ports\[udev\-\>portnum \- 1];
/\*
@@ \-6020,6 \+6024,7 @@ int usb\_reset\_device(struct usb\_device \*udev)
usb\_autosuspend\_device(udev);
memalloc\_noio\_restore(noio\_flag);
* udev\-\>reset\_in\_progress \= 0;
return ret;
}
EXPORT\_SYMBOL\_GPL(usb\_reset\_device);
diff \-\-git a/include/linux/usb.h b/include/linux/usb.h
index 539825269474\..f2e8f4e4e3bc 100644
\-\-\- a/include/linux/usb.h
\+\+\+ b/include/linux/usb.h
@@ \-665,6 \+665,7 @@ struct usb\_device {
unsigned can\_submit:1;
unsigned persist\_enabled:1;
* unsigned reset\_in\_progress:1;
unsigned have\_langid:1;
unsigned authorized:1;
unsigned authenticated:1;
CNVD-2023-06474
由于此文件部分差异,所以部分手动替换
diff \-\-git a/net/sched/sch\_cbq.c b/net/sched/sch\_cbq.c
index 6568e17c4c634\..36db5f6782f2c 100644
\-\-\- a/net/sched/sch\_cbq.c
\+\+\+ b/net/sched/sch\_cbq.c
@@ \-230,6 \+230,8 @@ cbq\_classify(struct sk\_buff *skb, struct Qdisc* sch, int \*qerr)
* if (result \=\= TC\_ACT\_SHOT)
* return NULL;
cl \= (void \*)res.class;
if (!cl) {
应用补丁
- 在
linux-*
目录中执行:- 测试补丁但不实际修改,用于验证补丁:
patch -p1 --dry-run < path/to/your.patch
- 应用补丁:
patch -p1 < path/to/your.patch
依次将所有补丁应用。
- 测试补丁但不实际修改,用于验证补丁:
- 推荐先进行patch修补,然后再执行手动修改的部分,避免可能导致patch失效的情况。实际修补前,务必先测试补丁是否可以执行(全部success)
创建内核
要创建内核文件,需要执行以下步骤:
进入
/home/kernelmaker/rpmbuild/SPECS
目录,使用ls
命令查看其中是否有kernel.spec
文件。如果存在
kernel.spec
文件,则使用以下命令构建内核:(需要~22GB空间和较大耗时)
$ rpmbuild \-bb \-\-target\=x86\_64 \-\-without debug kernel.spec
--target
参数指定了构建的目标平台,--without debug
参数表示不需要生成调试信息。
等待构建完成后,生成的RPM包将放置在
/home/kernelmaker/rpmbuild/RPMS/x86_64
目录中。安装内核:(可能需要提前卸载版本不同而导致冲突的包,通过
rpm -qa | grep kernel
查看。)
$ sudo rpm \-ivh \-\-force kernel\-\*.rpm
注意,安装内核时应以root用户身份执行。安装后,重启系统以应用新内核。
$ sudo reboot
完成以上步骤后,新的内核文件就创建成功并安装完成了。重启后可以通过uname -a
查看使用中内核的编译时间来确定修改是否生效。
可能遇到的问题
若补丁修补的版本与当前内核差距较大,如何修补?
版本差距较小时可以直接应用diff或升级版本,而差距较大的时候则需要前往Git下载Diff,然后手动寻找文件未知来应用修改,这一步需要阅读代码来确定如何修改。
直接安装kernel的devel包来进行修补?
[不确定] 根据搜索和GPT问答,devel包中没有全部源代码,不能用于修补内核,需要下载完整源码才能修补。
patch -p1的-p1是什么意思
[GPT] -p1是patch命令的参数之一,其含义是去掉补丁文件中的第一个路径分量。在应用补丁时,补丁文件中通常包含相对于源码根目录的路径信息,例如:
\-\-\- a/kernel/fs/Makefile
\+\+\+ b/kernel/fs/Makefile
其中的a/
和b/
就是第一个路径分量。在使用patch命令应用补丁时,如果补丁文件中包含前缀路径,则需要使用-p参数去掉。例如,如果补丁文件中包含a/
前缀,则需使用-p1
参数去掉,表示删除第一个路径分量。如果补丁文件中包含a/b/
前缀,则需使用-p2
参数去掉,依此类推。
在上述打补丁的操作中,我们在应用补丁时使用了-p1
参数,因为针对CentOS 7的内核源码通常会有一层根目录的路径前缀需要去掉,因此使用-p1参数去除。
~/.rpmmacros 文件的用途是什么?为什么获取内核源码需要这个文件?
[GPT] ~/.rpmmacros
文件是用来设置RPM包构建环境的配置文件,它可以定义一些常用的宏定义,通过这些宏定义来指定RPM构建过程中所需要的一些文件目录、版本号、包名等信息,以便于自动化打包。其中它定义的 %_topdir
宏标识RPM组件的顶层目录。
在获取CentOS内核源代码时,需要创建一个基于 ~/rpmbuild/
目录的构建树来构建内核。由于 ~/.rpmmacros
文件定义了在构建过程中使用的顶层目录(%_topdir
),所以需要在创建 ~/rpmbuild/
目录前,将这个宏定义写入到 ~/.rpmmacros
文件中。
这么做的原因是,RPM包管理的构建树是有编译者自己管理和维护的,不依赖于开发机和安装系统的环境和目录结构,以及由可能包含特殊字符、空格、换行符等情况。因此,通过在 ~/.rpmmacros
文件中定义宏变量,可以保证构建环境的一致性和可控性,从而提高构建的稳定性和效率。