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中所给出的步骤(略有改动):

  1. 进入到下载好的 Linux 内核文件中,将配置文件中的选项清空
make allnoconfig
  1. 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
  1. 编译内核,只要不报错就可以。但时间可能有点长。
sudo make -j8
  1. 进入busybox文件夹,使用默认的配置文件
make defconfig
  1. make menuconfig 编辑配置文件,一定开启静态编译
Settings ---> Build BusyBox as a static binary (no shared libs) ---> yes
  1. 编译busybox,老样子,无视警告,只要不报错就可以。
time make -j 8
  1. 安装 busybox, install 之后出现 _install 文件夹
make install
  1. 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
  1. 使用 cpio 生成根文件系统
find . -print0 | cpio --null -ov --format=newc   | gzip -9 > ../initramfs.cpio.gz

​ 到 busybox 文件夹中,解压刚才生成的initramfs.cpio.gzinitramfs.cpio

  1. 使用 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

内核编译相关文件

  1. 在内核源码的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
  1. 然后修改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
  1. 在内核源码目录下执行以下命令
make defconfig
make menuconfig

​ 选择自己的 LSM 作为安全模块

Security options ---> Demo support --> yes
Security options ---> Default security module ---> Demo ---> yes
  1. 编译内核
# 安装依赖库安装库
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 保姆级教程相关推荐

  1. SpringBoot 配置 generator代码生成+knife4j接口文档(2种模板设置、逻辑删除、字段填充 含代码粘贴可用)保姆级教程(注意事项+建表SQL+代码生成类封装+测试类)

    保姆级教程,逻辑删除及字段自动填充设置,特别要说明的是本次用的是MySQL数据库,如果使用Oracle数据库是,数据库配置需要改变,数据库表一定要大写,否则无法生成代码. 数据库表 CREATE TA ...

  2. ACME网站证书自动化保姆级教程

    更好的阅读体验和更多文章请移步Blog: https://blog.zhou.icu/archives/acme网站证书自动化保姆级教程 本文参考(复制)自:使用 GitHub Actions 自动申 ...

  3. 50000字,数仓建设保姆级教程,离线和实时一网打尽(理论+实战) 下

    文档大纲: 本文上半部分之前已经发过了,传送门:50000字,数仓建设保姆级教程,离线和实时一网打尽(理论+实战) 上 此篇文章是整个文档的下半部分,将接着上半部分从第五章开始. 五.实时数仓建设核心 ...

  4. 【图解SHA1杂凑算法】SHA1杂凑算法的Python实现保姆级教程 | 物联网安全 | 信息安全

    系列索引:[图解安全加密算法]加密算法系列索引 Python保姆级实现教程 | 物联网安全 | 信息安全 起初写实验时找到的代码大多基于c/c++,python可参考的资料很少,所以借着这次实验的机会 ...

  5. 保姆级教程!基于声网 Web SDK实现音视频通话及屏幕共享

    前言 大家好,我是 @小曾同学,小伙伴们也可以叫我小曾- 如果你想实现一对一音视频通话和屏幕共享功能,不妨来看看这篇文章,保姆级教程,不需要从零实现,直接集成声网 SDK 即可轻松上手. 本文也分享了 ...

  6. 爬虫保姆级教程3:利用python-Flask框架搭建本地数据可视化网站

    成果展示: (1)网站首页: (2)电影表单页 (3) 电影评分页 (4) 词频统计页 (5)团队页面 接下来让我们看看上述网站是如何完成的: 首先简单介绍一下Flask框架: Flask主要功能有两 ...

  7. Flutter开发百度地图之定位,保姆级教程(2)

    未经本人同意,禁止转载! 前几天开发flutter百度地图,总算是把第一步走通了,这几天把定位功能开发了一下.记录一下,所谓取之于CSDN用之于CSDN. 下面描述的工程是配置Android的,ios ...

  8. 【模型+代码/保姆级教程】使用Pytorch实现手写汉字识别

    前言 参考文章: 最初参考的两篇: [Pytorch]基于CNN手写汉字的识别 「Pytorch」CNN实现手写汉字识别(数据集制作,网络搭建,训练验证测试全部代码) 模型: EfficientNet ...

  9. JavaScript保姆级教程 ——— 重难点详细解析(万字长文,建议收藏)

    JavaScript保姆级教程 --- 重难点详细解析(建议收藏) 1. JS函数 2. JS事件 3. JavaScript 对象 4. JavaScript prototype(原型对象) 5. ...

最新文章

  1. 最新!2020中国高校毕业生薪资报告出炉
  2. 官宣!清华大学要搬迁!
  3. execve函数的介绍与使用
  4. dos模式下切换电脑用户
  5. python本地镜像源搭建_【Python】pip配置国内镜像源,让Python模块安装飞起来。
  6. 解决 Intellij IDEA 文件图标一直闪烁
  7. 一维抛物线的matlab求解,一维抛物线偏微分方程数值解法(附图及matlab程序)
  8. js中的cookie的读写操作
  9. python stdin和stdout_无法使用Python写入和读取stdin / stdout
  10. centos 7 163 yum 源 python 2.7.5
  11. FAT文件系统“格式化”的恢复方法
  12. IT自学网有视频教程
  13. jpeg图像质量参数及icc信息提取
  14. PWM脉冲宽度调制——它是什么?
  15. Mac的日历事件如何同步更新到iphone手机中?
  16. C语言中比较两数的大小——三种方法
  17. 隔离放大器工作原理及其应用
  18. I - Simpsons’ Hidden Talents
  19. python连接oracle报错DPI-1047
  20. CSS简单的交互动效

热门文章

  1. jsp中request.getAttribute()和 request.getParameter()有何区别
  2. matlab贝叶斯判别后验概率,统计学习方法——朴素贝叶斯法、先验概率、后验概率(示例代码)...
  3. 如何用Nginx访问图片服务器的图片
  4. 先验概率及后验概率等解释
  5. 2018腾讯游戏安全技术竞赛Android 组决赛第一轮
  6. Redis高性能原理:Redis为什么这么快?
  7. Yarn上资源隔离技术的剖析-内存资源隔离源码解析
  8. Android:屏幕的锁定和取消锁定
  9. 那些坚持写博客的程序员,后来都怎么样了?
  10. 既节能又省钱的数据中心布线解决方案