最近为了完成作业,被折磨的不轻。版本的不兼容,各种的报错经历了太多。在此记录,希望对大家有所帮助。
本人在写这篇文章的时候,重新安装虚拟机,从头开始的,所以,如果能坚持到最后,大概率会成功的。祝你们好运。(当然,如果这篇文章还没有过太久的话)
经过了大量测试,红帽公司的系统好像并不是很好编译 busybox,本人使用 Fedora 系统进行编译时,总是显示缺少依赖,而网上也找不到相应的库。转而使用教程较多的 Ubuntu 系统。为了本身系统的安全,当然使用虚拟机。
系统参数:Ubuntu 20.04,处理器 2 CPU * 1 内核/CPU,内存 4G,其他使用默认设置,然后直接创建就可以了。
linux 内核源码版本:linux-4.20.17。内核版本不能选用太低版本,因为当前 binutils 工具不是前向兼容的,之前有些类型现在版本的工具是无法识别的。比如 linux-4.14.0 版本,部分数据类型就已经不受支持了。
busybox:一般用最新版本即可,本人使用 busybox-1.35.0,是当前最新。
上面简单介绍一下各种工具或系统的版本,下面开始具体的实施工作。
虚拟机安装完成后,首先进行换源(Software & Updates软件),然后执行apt update && apt upgrade
升级各种软件包(或者他会自动弹出一个Software Updater的窗口,直接 install),避免之后在安装工具时出现缺少依赖包或者依赖包安装困难的问题。但是,现在不要着急安装gcc,gcc的安装稍后再说,现在只要先升级即可。
因为 Ubuntu 默认安装的是 gcc-9,所以我们需要指定版本进行安装,否则在内核编译过程中会出现版本不兼容的问题。
首先apt remove gcc-9
卸载高版本。
使用安装命令apt install gcc-8
进行安装4。但是安装之后执行 gcc 命令可能还会提示你安装 gcc,这是因为我们安装了 gcc-8,在 /usr/bin 目录下只有 gcc-8 而没有 gcc,所以 shell 找不到命令。
为此,执行命令ln /usr/bin/gcc-8 /usr/bin/gcc
。我们就直接将 gcc-8 链接为 gcc 就可以了。
当然,我们不可能直接在系统中运行编译好的内核,还是需要在虚拟机中运行的。所以,我们安装 Qemu 轻量级虚拟机。
命令为sudo apt install qemu-system-x86
。
下载 linux 内核,从中选择相应的版本。笔者使用的是:linux-4.20.17。
在系统启动的时候,需要先加载一段内存镜像,以便于找到系统真正的入口。在我们调试内核的时候,更多的使用 busybox。他可以帮助我们生成一个根文件系统,我们将其打包到一个 cpio 镜像文件之后就可以重复使用了。
首先,我们安装所需要的依赖4。
sudo apt-get install bison
sudo apt-get install flex
sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc
在安装的过程中,可以先下载 busybox5,从中选择最新版本,或者使用笔者使用的版本:busybox-1.35.0。但是在依赖安装完成后才能进行编译工作。
将下载好的 busybox 解压然后放到解压好的 linux 目录下并改名为 busybox。
为了保险起见,我们先编译一下内核试一试,能不能运行。下面借用1中所给出的步骤(略有改动):
make allnoconfig
64-bit kernel ---> yes
General setup ---> Initial RAM filesystem and RAM disk (initramfs/initrd) support ---> yes
General setup ---> Configure standard kernel features ---> Enable support for printk ---> yes
Executable file formats / Emulations ---> Kernel support for ELF binaries ---> yes
Executable file formats / Emulations ---> Kernel support for scripts starting with #! ---> yes
Device Drivers ---> Generic Driver Options ---> Maintain a devtmpfs filesystem to mount at /dev ---> yes
Device Drivers ---> Generic Driver Options ---> Automount devtmpfs at /dev, after the kernel mounted the rootfs ---> yes
Device Drivers ---> Character devices ---> Enable TTY ---> yes
Device Drivers ---> Character devices ---> Serial drivers ---> 8250/16550 and compatible serial support ---> yes
Device Drivers ---> Character devices ---> Serial drivers ---> Console on 8250/16550 and compatible serial port ---> yes
File systems ---> Pseudo filesystems ---> /proc file system support ---> yes
File systems ---> Pseudo filesystems ---> sysfs file system support ---> yes
sudo make -j8
make defconfig
make menuconfig
编辑配置文件,一定开启静态编译Settings ---> Build BusyBox as a static binary (no shared libs) ---> yes
busybox
,老样子,无视警告,只要不报错就可以。time make -j 8
make install
cd _install
创建一些文件夹以及文件mkdir -p proc sys dev etc etc/init.d lib tmp
ln -sf linuxrc init
cat > etc/init.d/rcS <<EOF
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
/sbin/mdev -s
ifconfig lo up
EOF
chmod +x etc/init.d/rcS
cat > etc/inittab <<EOF
# /etc/inittab
::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
EOF
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz
到 busybox 文件夹中,解压刚才生成的initramfs.cpio.gz
为initramfs.cpio
。
qemu-system-x86_64 -kernel ~/Downloads/linux-4.20.17/arch/x86/boot/bzImage -initrd ~/Downloads/linux-4.20.17/busybox/initramfs.cpio
这里的路径要视个人的文件路径而定,不要直接复制,先看清楚。确定路径后执行命令,就可以看到一个不带图形界面的 shell 了。
如果到这里还没有问题的话,说明你的准备工作已经完成了,恭喜!
不知道 LSM 原理的可以先补充一下前置知识(虽然我也不知道,狗头)。但总体来说,思想就是利用系统的 hook。我们编写钩子程序,然后添加到一个钩子列表中并加入系统钩子。注册刚刚已经加入的钩子函数,重新编译内核程序就可以使用了。
下面我沿用了2中的demo代码,但可能由于版本的不兼容,原文中有一些函数无法使用,就进行了小型的修改。在此感谢大佬无私提供的代码。
// demo_lsm.c
#include
#include
#include
#include
static unsigned long long count = 0;
int demo_task_alloc(struct task_struct *task,unsigned long clone_flags) // 2. implement relevant function
{
printk("[+demo] call task_create(). count=%llu\n", ++count);
return 0;
}
int demo_inode_create (struct inode *dir, struct dentry *dentry, umode_t mode)
{
printk ("[+demo] call [inode_create] by pid: %d\n", get_current()->pid) ;
return 0 ;
}
int demo_file_permission(struct file *file, int mask){
int max_use = 10;
if(file->f_inode->__i_nlink > max_use){
printk("[+demo] permisson deny!\n");
return 1;
}
return 0;
}
static struct security_hook_list demo_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(task_alloc,demo_task_alloc),
LSM_HOOK_INIT(inode_create,demo_inode_create), //3. add to security_hook_list
LSM_HOOK_INIT(file_permission,demo_file_permission),
};
void __init demo_add_hooks(void)
{
pr_info("Demo: becoming mindful.\n"); //print relevant mesg, cat by dmesg | grep demo
security_add_hooks(demo_hooks, ARRAY_SIZE(demo_hooks),"demo"); //add security model function
}
static int __init demo_init(void){
demo_add_hooks();
return 0;
}
__initcall(demo_init); //4. register this hook function
security
文件夹下面建立demo
文件夹,该文件夹内有demo_lsm.c 、Makefile 、 Kconfig
三个文件 Makefile
如下
obj-$(CONFIG_SECURITY_DEMO) := demo.o
demo-y := demo_lsm.o
Kconfig
如下
config SECURITY_DEMO
bool "Demo support"
depends on SECURITY
default n
help
introduction of demo LSM
security
文件夹下面的Makefile 、 Kconfig
文件 按照 selinux 添加自己的 LSM 配置即可。
Makefile
如下
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the kernel security code
#
obj-$(CONFIG_KEYS) += keys/
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
subdir-$(CONFIG_SECURITY_SMACK) += smack
subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo
subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor
subdir-$(CONFIG_SECURITY_YAMA) += yama
# -------- demo LSM -------- #
# -------- 在这里添加 -------- #
subdir-$(CONFIG_SECURITY_DEMO) += demo
subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin
# always enable default capabilities
obj-y += commoncap.o
obj-$(CONFIG_MMU) += min_addr.o
# Object file lists
obj-$(CONFIG_SECURITY) += security.o
obj-$(CONFIG_SECURITYFS) += inode.o
obj-$(CONFIG_SECURITY_SELINUX) += selinux/
obj-$(CONFIG_SECURITY_SMACK) += smack/
obj-$(CONFIG_AUDIT) += lsm_audit.o
obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/
obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/
obj-$(CONFIG_SECURITY_YAMA) += yama/
# -------- demo LSM ------- #
# -------- 在这里添加 -------- #
obj-$(CONFIG_SECURITY_DEMO) += demo/
obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
# Object integrity file lists
subdir-$(CONFIG_INTEGRITY) += integrity
obj-$(CONFIG_INTEGRITY) += integrity/
Kconfig
文件拉到最下面,找到对应位置添加:
source security/demo/Kconfig
default DEFAULT_SECURITY_DEMO if SECURITY_DEMO
config DEFAULT_SECURITY_DEMO
bool "Demo" if SECURITY_DEMO=y
default "Demo" if DEFAULT_SECURITY_DEMO
make defconfig
make menuconfig
选择自己的 LSM 作为安全模块
Security options ---> Demo support --> yes
Security options ---> Default security module ---> Demo ---> yes
# 安装依赖库安装库
sudo apt install libelf-dev
sudo make -j8
如果这里报错了,首先查看是否 gcc 版本正确。可以通过以下命令检查:
apt list | grep gcc
ls /usr/bin/ | grep gcc
如果有 gcc-9,直接apt remove gcc-9
卸载,然后ln /usr/bin/gcc-8 /usr/bin/gcc
重新建立硬链接。
整个内核编译的过程十分缓慢,需要耐心等候。可能是因为,在之前编译内核时使用了系统默认的安全模块,而这次需要重新对自定义安全模块编译并加载,所以导致了编译效率的降低。
如果编译成功了会显示:Kernel: arch/x86/boot/bzImage is ready
,否则就说明你的某一个环节出错了。
最后如果你已经到这里,说明你已经成功了,恭喜你!赶紧来运行一下编译好的内核看看吧。上面已经有了 qemu 启动内核的命令,这里再次给出方便使用。
qemu-system-x86_64 -kernel ~/Downloads/linux-4.20.17/arch/x86/boot/bzImage -initrd ~/Downloads/linux-4.20.17/busybox/initramfs.cpio
加载了我们的 demo LSM 后,qemu 在启动系统时,你就可以看到屏幕上显示除了很多的:[+demo] call ...
,这就说明我们的安全模块已经成功的编译,挂载到内核程序中了。
我们回车进入终端,然后输入ls
。发现输出了permission deny
的字样,也就是我们的 LSM 阻挡了我们此次的文件访问。
如果你单纯调试这个版本的内核,那么 busybox 生成的内存镜像是不需要再修改的了,直接使用就可以,你甚至可以为了方便将生成的 cpio 文件放置到其他路径。只有修改模块的时候编译内核即可。但如果更换内核版本的话,还是需要将 busybox 放入新的 linux 内核目录中进行编译安装的。
祝大家学业、工作顺利,永不报错。
[1]. huzai9527. “裁剪Linux内核,用qemu进行调试”. https://blog.csdn.net/huzai9527/article/details/116769974
[2]. huzai9527. “LSM内核模块实现demo”. https://blog.csdn.net/huzai9527/article/details/119870485
[3]. 0xJDchen. “学习LSM(Linux security module)之二:编写并运行一个简单的demo”. https://www.cnblogs.com/0xJDchen/p/6040446.html
[4]. yqf. “ubuntu 20 下搭建linux 内核+BusyBox+Qemu开发环境”. https://zhuanlan.zhihu.com/p/383583821#:~:text=%E5%AE%89%E8%A3%85%E7%BC%96%E8%AF%91busybox%20%E7%9A%84%E4%BE%9D%E8%B5%96%20sudo%20apt-get%20install%20libncurses5-dev%20libncursesw5-dev%20%E8%BF%9B%E5%85%A5,make%20install%20-j4%20%E5%9C%A8%E6%A0%B9%E7%9B%AE%E5%BD%95%E4%B8%8B%E7%94%9F%E6%88%90_install%20%E6%96%87%E4%BB%B6%E5%A4%B9%20%E9%87%8C%E9%9D%A2%E5%8C%85%E5%90%AB%E5%90%AF%E5%8A%A8linu%20%E5%86%85%E6%A0%B8%E6%96%87%E4%BB%B6%20%E5%85%B6%E4%B8%ADqemu_rootfs.img%E6%98%AF%E6%96%87%E4%BB%B6%E5%90%8D%EF%BC%8C500m%E6%98%AF%E7%A3%81%E7%9B%98%E5%A4%A7%E5%B0%8F%EF%BC%8C%E6%A0%B9%E6%8D%AE%E9%9C%80%E8%A6%81%E4%BF%AE%E6%94%B9%E3%80%82
[5]. TrueDei. “使用Busybox制作根文件系统”. https://cloud.tencent.com/developer/article/1882513
[6]. 孤星入命孑然一身. “编译错误 error New address family defined, please update secclass_map.解决”. https://blog.csdn.net/zhangpengfei991023/article/details/109672491