LSM内核模块 Demo 保姆级教程
LSM 内核模块实现 Demo
前言
最近为了完成作业,被折磨的不轻。版本的不兼容,各种的报错经历了太多。在此记录,希望对大家有所帮助。
本人在写这篇文章的时候,重新安装虚拟机,从头开始的,所以,如果能坚持到最后,大概率会成功的。祝你们好运。(当然,如果这篇文章还没有过太久的话)
准备工作
经过了大量测试,红帽公司的系统好像并不是很好编译 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的安装稍后再说,现在只要先升级即可。
安装 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
当然,我们不可能直接在系统中运行编译好的内核,还是需要在虚拟机中运行的。所以,我们安装 Qemu 轻量级虚拟机。
命令为sudo apt install qemu-system-x86
。
内核下载
下载 linux 内核,从中选择相应的版本。笔者使用的是:linux-4.20.17。
使用 busybox 制作根文件系统
在系统启动的时候,需要先加载一段内存镜像,以便于找到系统真正的入口。在我们调试内核的时候,更多的使用 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。
Qemu 运行内核
为了保险起见,我们先编译一下内核试一试,能不能运行。下面借用1中所给出的步骤(略有改动):
- 进入到下载好的 Linux 内核文件中,将配置文件中的选项清空
make allnoconfig
- make menuconfig 进入配置文件菜单选项,将以下选择勾选。注意,要吧窗口调大一点,要不然他会提示窗口太小无法运行的报错。
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
- 进入busybox文件夹,使用默认的配置文件
make defconfig
make menuconfig
编辑配置文件,一定开启静态编译
Settings ---> Build BusyBox as a static binary (no shared libs) ---> yes
- 编译
busybox
,老样子,无视警告,只要不报错就可以。
time make -j 8
- 安装 busybox, install 之后出现 _install 文件夹
make install
cd _install
创建一些文件夹以及文件
mkdir -p proc sys dev etc etc/init.d lib tmp
ln -sf linuxrc initcat > etc/init.d/rcS <<EOF
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
/sbin/mdev -s
ifconfig lo up
EOFchmod +x etc/init.d/rcScat > etc/inittab <<EOF
# /etc/inittab
::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
EOF
- 使用 cpio 生成根文件系统
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz
到 busybox 文件夹中,解压刚才生成的initramfs.cpio.gz
为initramfs.cpio
。
- 使用 qemu 启动编译好的内核
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 内核模块实现
模块编写
不知道 LSM 原理的可以先补充一下前置知识(虽然我也不知道,狗头)。但总体来说,思想就是利用系统的 hook。我们编写钩子程序,然后添加到一个钩子列表中并加入系统钩子。注册刚刚已经加入的钩子函数,重新编译内核程序就可以使用了。
下面我沿用了2中的demo代码,但可能由于版本的不兼容,原文中有一些函数无法使用,就进行了小型的修改。在此感谢大佬无私提供的代码。
// demo_lsm.c
#include <linux/lsm_hooks.h>
#include <linux/sysctl.h>
#include <linux/sched.h>
#include <linux/module.h>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_listLSM_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_DEMObool "Demo support"depends on SECURITYdefault nhelpintroduction 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/Kconfigdefault DEFAULT_SECURITY_DEMO if SECURITY_DEMOconfig DEFAULT_SECURITY_DEMObool "Demo" if SECURITY_DEMO=ydefault "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
LSM内核模块 Demo 保姆级教程相关推荐
- SpringBoot 配置 generator代码生成+knife4j接口文档(2种模板设置、逻辑删除、字段填充 含代码粘贴可用)保姆级教程(注意事项+建表SQL+代码生成类封装+测试类)
保姆级教程,逻辑删除及字段自动填充设置,特别要说明的是本次用的是MySQL数据库,如果使用Oracle数据库是,数据库配置需要改变,数据库表一定要大写,否则无法生成代码. 数据库表 CREATE TA ...
- ACME网站证书自动化保姆级教程
更好的阅读体验和更多文章请移步Blog: https://blog.zhou.icu/archives/acme网站证书自动化保姆级教程 本文参考(复制)自:使用 GitHub Actions 自动申 ...
- 50000字,数仓建设保姆级教程,离线和实时一网打尽(理论+实战) 下
文档大纲: 本文上半部分之前已经发过了,传送门:50000字,数仓建设保姆级教程,离线和实时一网打尽(理论+实战) 上 此篇文章是整个文档的下半部分,将接着上半部分从第五章开始. 五.实时数仓建设核心 ...
- 【图解SHA1杂凑算法】SHA1杂凑算法的Python实现保姆级教程 | 物联网安全 | 信息安全
系列索引:[图解安全加密算法]加密算法系列索引 Python保姆级实现教程 | 物联网安全 | 信息安全 起初写实验时找到的代码大多基于c/c++,python可参考的资料很少,所以借着这次实验的机会 ...
- 保姆级教程!基于声网 Web SDK实现音视频通话及屏幕共享
前言 大家好,我是 @小曾同学,小伙伴们也可以叫我小曾- 如果你想实现一对一音视频通话和屏幕共享功能,不妨来看看这篇文章,保姆级教程,不需要从零实现,直接集成声网 SDK 即可轻松上手. 本文也分享了 ...
- 爬虫保姆级教程3:利用python-Flask框架搭建本地数据可视化网站
成果展示: (1)网站首页: (2)电影表单页 (3) 电影评分页 (4) 词频统计页 (5)团队页面 接下来让我们看看上述网站是如何完成的: 首先简单介绍一下Flask框架: Flask主要功能有两 ...
- Flutter开发百度地图之定位,保姆级教程(2)
未经本人同意,禁止转载! 前几天开发flutter百度地图,总算是把第一步走通了,这几天把定位功能开发了一下.记录一下,所谓取之于CSDN用之于CSDN. 下面描述的工程是配置Android的,ios ...
- 【模型+代码/保姆级教程】使用Pytorch实现手写汉字识别
前言 参考文章: 最初参考的两篇: [Pytorch]基于CNN手写汉字的识别 「Pytorch」CNN实现手写汉字识别(数据集制作,网络搭建,训练验证测试全部代码) 模型: EfficientNet ...
- JavaScript保姆级教程 ——— 重难点详细解析(万字长文,建议收藏)
JavaScript保姆级教程 --- 重难点详细解析(建议收藏) 1. JS函数 2. JS事件 3. JavaScript 对象 4. JavaScript prototype(原型对象) 5. ...
最新文章
- 最新!2020中国高校毕业生薪资报告出炉
- 官宣!清华大学要搬迁!
- execve函数的介绍与使用
- dos模式下切换电脑用户
- python本地镜像源搭建_【Python】pip配置国内镜像源,让Python模块安装飞起来。
- 解决 Intellij IDEA 文件图标一直闪烁
- 一维抛物线的matlab求解,一维抛物线偏微分方程数值解法(附图及matlab程序)
- js中的cookie的读写操作
- python stdin和stdout_无法使用Python写入和读取stdin / stdout
- centos 7 163 yum 源 python 2.7.5
- FAT文件系统“格式化”的恢复方法
- IT自学网有视频教程
- jpeg图像质量参数及icc信息提取
- PWM脉冲宽度调制——它是什么?
- Mac的日历事件如何同步更新到iphone手机中?
- C语言中比较两数的大小——三种方法
- 隔离放大器工作原理及其应用
- I - Simpsons’ Hidden Talents
- python连接oracle报错DPI-1047
- CSS简单的交互动效
热门文章
- jsp中request.getAttribute()和 request.getParameter()有何区别
- matlab贝叶斯判别后验概率,统计学习方法——朴素贝叶斯法、先验概率、后验概率(示例代码)...
- 如何用Nginx访问图片服务器的图片
- 先验概率及后验概率等解释
- 2018腾讯游戏安全技术竞赛Android 组决赛第一轮
- Redis高性能原理:Redis为什么这么快?
- Yarn上资源隔离技术的剖析-内存资源隔离源码解析
- Android:屏幕的锁定和取消锁定
- 那些坚持写博客的程序员,后来都怎么样了?
- 既节能又省钱的数据中心布线解决方案