学习LSM(Linux security module)之一:解读yama
最近打算写一个基于LSM的安全模块,发现国内现有的资料极少。因此打算自己琢磨一下。大致的学习路线如下:
由易至难使用并阅读两到三个安全模块->参照阅读模块自己实现一个安全模块->在自己实现的同时阅读LSM实现的基本源码,由于Yama代码量小,结构十分清晰,可以作为入门的demo进行参照。
由于网上关于LSM的相关介绍已经烂大街了,就按自己的初步理解简单介绍一下LSM,详情可以自己阅读文后的相关链接,本文源码基于Linux4.8.0。
一:什么是LSM
一种轻量级的安全访问控制框架,主要利用Hook函数对权限进行访问控制,并在部分对象中内置了透明的安全属性。
二:Yama的简单介绍和基本使用
Yama主要是对Ptrace函数调用进行访问控制。
Ptrace是一个系统调用,它提供了一种方法来让‘父’进程可以观察和控制其它进程的执行,检查和改变其核心映像以及寄存器。 主要用来实现断点调试和系统调用跟踪。利用ptrace函数,不仅可以劫持另一个进程的调用,修改系统函数调用和改变返回值,而且可以向另一个函数注入代码,修改eip,进入自己的逻辑。这个函数广泛用于调试和信号跟踪工具。所以说,对ptrace函数进行访问控制还是很有必要的。
Yama一共分为四个等级:
#define YAMA_SCOPE_DISABLED 0 #define YAMA_SCOPE_RELATIONAL 1 #define YAMA_SCOPE_CAPABILITY 2 #define YAMA_SCOPE_NO_ATTACH 3
其中YAMA_SCOPE_DISABLED代表yama并不起任何作用,YAMA_SCOPE_RELATIONAL代表只能ptarce子进程才能进行调试,YAMA_SCOPE_CAPABILITY,拥有CAP_SYS_PTRACE能力的进程才可以使用ptrace。而YAMA_SCOPE_NO_ATTACH代表没有任何进程可以attach,而且只要设置成了3就无法降级了。
现在,先来测试使用一下,先将等级设为0。在root权限下进行:
此时,任何ptrace都能够直接运行。
被ptrace的demo程序如下:
//test.c #include<stdio.h>int main(){while(1){sleep(20);static int i = 0; }return 0;}
得到结果如下:
将等级设为一:
等级设为二:
可以通过setcap CAP_SYS_PTRACE=ep /usr/bin/strace给strace设置CAP_SYS_PTRACE权限,
等级设为三:
三:源码解析
从开头看起
void __init yama_add_hooks(void) {pr_info("Yama: becoming mindful.\n"); //打印相关信息,可以通过dmesg | grep Yama:查看security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks)); //添加安全模块函数yama_init_sysctl(); //在中sysctl进行注册 }
先简单解释一下yama_init_sysctl()函数,这个函数的作用是在sysctl中进行注册,使其能通过/proc/sys/kernel/yama/ptrace_scope进行设置参数,看具体源码:
static void __init yama_init_sysctl(void)
{if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table))panic("Yama: sysctl registration failed.\n");
}
其中,yama_sysctl_path用于注明在/proc/sys目录下的具体位置,yama的定义如下:
struct ctl_path yama_sysctl_path[] = {{ .procname = "kernel", },{ .procname = "yama", },{ }
};
即在/proc/sys/kernel/yama目录下。
yama_sysctl_table表示参数的相关信息,源码如下:
static int zero;//自动初始化为0 static int max_scope = YAMA_SCOPE_NO_ATTACH;
static struct ctl_table yama_sysctl_table[] = {{.procname = "ptrace_scope", //文件名.data = &ptrace_scope, //实际参数在内核中的数据结构.maxlen = sizeof(int), //对超过该最大长度的字符串截掉后面超长的部分..mode = 0644, //条目在proc文件系统下的权限.proc_handler = yama_dointvec_minmax, //如上,对.proc_handler进行hook.extra1 = &zero, //proc_handler的参数,即范围为0~3.extra2 = &max_scope,},{ }
};
proc_handler代表读写操作函数,对/proc/sys/kernel/yama/ptrace_scope进行读写时调用的函数。其中
proc_dointvec 读写一个包含一个或多个整数的数组
proc_dostring 读写一个字符串
proc_dointvec_minmax 写的数组必须在min~max范围内。
在这个数据结构中,自己构造了一个函数,来在操作之前进行了一些操作,如下
static int yama_dointvec_minmax(struct ctl_table *table, int write,void __user *buffer, size_t *lenp, loff_t *ppos) {struct ctl_table table_copy;/*capable来对权限做出检查,检查是否有权对指定的资源进行操作,该函数返回0则代表无权操作这里对ptrace_scope进行读写需要write置1而且需要用户有CAP_SYS_PTRACE权限*/if (write && !capable(CAP_SYS_PTRACE)) return -EPERM;//当设置为最大值时,不再允许修改该参数table_copy = *table;if (*(int *)table_copy.data == *(int *)table_copy.extra2)table_copy.extra1 = table_copy.extra2;return proc_dointvec_minmax(&table_copy, write, buffer, lenp, ppos); }
核心函数是security_add_hooks函数,这个函数负责对ptrace进行访问控制,如下:
先来看一下yama_hooks:
static struct security_hook_list yama_hooks[] = {//上面两个hook就是对ptrace的两种方式进行分别check LSM_HOOK_INIT(ptrace_access_check, yama_ptrace_access_check),LSM_HOOK_INIT(ptrace_traceme, yama_ptrace_traceme),LSM_HOOK_INIT(task_prctl, yama_task_prctl),LSM_HOOK_INIT(task_free, yama_task_free), };
先看一下在内核中关于LSM_HOOK_INIT的相关定义,
#define LSM_HOOK_INIT(HEAD, HOOK) { .head = &security_hook_heads.HEAD, .hook = { .HEAD = HOOK } }
可见该宏的作用就是来是填充security_hook_list,security_hook_list的,相关函数定义如下:
struct security_hook_list { struct list_head list; struct list_head *head; union security_list_options hook; };
在介绍ptrace_access_check和ptrace_trace前需要补充一些相关知识:
PTRACE_TRACEME和PTRACE_ATTACH是ptrace()函数TRACE的两种类型。这两种方式的主要区别可以概括为:
PTRACE_TRACEME是子进程主动申请被TRACE。
而PTRACE_ATTACH是父进程自己要attach到子进程,
相当于子进程是被动的trace。
继续,ptrace_may_access主要发生在发生在ptrace_attach,而ptrace_attch函数发生在ptrace()中。,ptrace_may_access函数的功能正如源码注释
This check is used both for attaching with ptrace and for allowing access to sensitive information in /proc.
ptrace_traceme函数发生在ptrace()调用前,主要的功能是做检查和设置PTRACE_TRACEME位,其中PTRACE_TRACEME表示程序已被跟踪。通过对这两个函数进行hook,就廊括了ptrace的所有情况了。
先来看的yama_ptrace_access_check函数,代码如下:
static int yama_ptrace_access_check(struct task_struct *child,unsigned int mode)
{int rc = 0;/* require ptrace target be a child of ptracer on attach */if (mode & PTRACE_MODE_ATTACH) {switch (ptrace_scope) {case YAMA_SCOPE_DISABLED:/* No additional restrictions. */break;case YAMA_SCOPE_RELATIONAL: //进程可以跟踪有血缘关系(后代)的进程rcu_read_lock(); if (!task_is_descendant(current, child) && //简单的遍历,查看进程是否是后代!ptracer_exception_found(current, child) && //检测是否已有祖先attach了!ns_capable(__task_cred(child)->user_ns, CAP_SYS_PTRACE))rc = -EPERM;rcu_read_unlock();break;case YAMA_SCOPE_CAPABILITY: //拥有CAP_SYS_PTRACE能力的进程才可以使用ptracercu_read_lock();if (!ns_capable(__task_cred(child)->user_ns, CAP_SYS_PTRACE))rc = -EPERM;rcu_read_unlock();break;case YAMA_SCOPE_NO_ATTACH: //无法进行ptracedefault:rc = -EPERM;break;}}if (rc && (mode & PTRACE_MODE_NOAUDIT) == 0) {printk_ratelimited(KERN_NOTICE"ptrace of pid %d was attempted by: %s (pid %d)\n",child->pid, current->comm, current->pid);}return rc;
}
注释讲的很清楚了,通过switch ptrace_scope的值,对每种情况分别讨论。yama_ptrace_traceme 基本如下:
int yama_ptrace_traceme(struct task_struct *parent) {int rc = 0;/* Only disallow PTRACE_TRACEME on more aggressive settings. */switch (ptrace_scope) {case YAMA_SCOPE_CAPABILITY:/*当用户父进程有CAP_SYS_PTRACE没有CAP_SYS_PTRACE时,返回失败*/if (!has_ns_capability(parent, current_user_ns(), CAP_SYS_PTRACE))rc = -EPERM;break;/*如果YAMA_SCOPE_NO_ATTACH,直接返回失败*/case YAMA_SCOPE_NO_ATTACH:rc = -EPERM;break;}
对于
LSM_HOOK_INIT(task_prctl, yama_task_prctl),LSM_HOOK_INIT(task_free, yama_task_free),
这两个hook,主要是为了构建调试函数和被调试函数的关系,不多阐述,有兴趣可以自由阅读源码。
转载于:https://www.cnblogs.com/0xJDchen/p/6033167.html
学习LSM(Linux security module)之一:解读yama相关推荐
- 学习LSM(Linux security module)之二:编写并运行一个简单的demo
转自:cnblog 各种折腾,经过了一个蛋疼的周末,终于在Ubuntu14.04上运行了一个基于LSM的简单demo程序. 一:程序编写 先简单的看一下这个demo: //demo_lsm.c #in ...
- 学习LSM(Linux security module)之四:一个基于LSM的简单沙箱的设计与实现
转自:cnblog 嗯!如题,一个简单的基于LSM的沙箱设计.环境是Linux v4.4.28.一个比较新的版本,所以在实现过程中很难找到资料,而且还有各种坑逼,所以大部分的时间都是在看源码,虽然写的 ...
- Linux Security Module逆向分析实战
Linux Security Module逆向分析实战 本文记录了对某发行版Linux中一个安全模块(LSM)的逆向过程,该LSM对系统中待运行的程序进行安全校验,数据流穿越内核态与用户态,涉及系统内 ...
- LSM(Linux Security Modules)框架原理解析
1. 基本原理 LSM是内核安全模块的一套框架,本质是插桩法.它的主要有两个特点: 1.在内核安全相关的关键路径上插入了Hook点: 内核安全相关的关键对象有:task_struct(任务和进程).l ...
- 34.Oracle深度学习笔记——12C的AWR初步解读
34.Oracle深度学习笔记--12C的AWR初步解读 关于AWR,蛤蟆也经常看.因为经常看别人给出的建议,很难有深刻体会.对此,计划花费几个晚上时间好好体会一把并记录下来.此处以单实例为例.列出目 ...
- 【深度学习】基于深度学习的linux服务器,需要搭建哪些服务,一步步搭建深度学习的环境,cuda,pytorch,opencv,ftp服务, nfs服务 docker等等
来来回回的安装服务器,是时间写个pipline了,在这里主要记录下生产环境下的一台基于深度学习的linux服务器,需要搭建那些服务 文章目录 前言 一.开工 1.1 切换yum源 1.2 minico ...
- 简单实例讲解linux的module模块编译步骤
简单实例讲解linux的module模块编译步骤 (2014-10-24 10:19:17) 标签: module linux 分类:Linux/Unix 本文将直接了当的带你进入linux的模块编译 ...
- Android 驱动(8)---简单实例讲解linux的module模块编译步骤
简单实例讲解linux的module模块编译步骤 原博文地址http://blog.sina.com.cn/s/blog_4ba5b45e0102v25h.html ----------------- ...
- PowerShell 学习笔记 - 2 PS Module
PowerShell 学习笔记 - 2 PS Module 本章主要探讨 PowerShell 的模块化,由于 PowerShell Core 现版本下已经移植的模块较少以及存在大量强依赖于平台的功能 ...
最新文章
- 关于JVM,你需要掌握这些!!
- IntelliJ IDEA 常用设置
- Elasticsearch环境准备(一)
- Mac更新VSCode写权限被拒绝 Cannot update while running on a read-only volume
- 大众点评网2016校招试题选录
- LeetCode 16 3Sum Closest(最接近的3个数的和)
- Java Web-网页基础-HTML-CSS
- [Python] L1-035. 情人节 团体程序设计天梯赛GPLT
- 20155332 缓冲区溢出漏洞实验
- Android CircleMenu:旋转转盘选择Menu
- word 公式编辑器 键入技巧 | 写数学作业必备速查表
- 模拟信号采样与AD转换
- 遗传算法及其应用_遗传算法及其广泛应用
- ActivityManagerService解读之Activity启动三探--Activity中Task与Stack
- RTCP 协议的 NACK 报文
- 云服务器初始化失败怎么办,提示交互式登录进程初始化失败是什么原因?解决方法步骤教程...
- jQuery全选、反选与获取选中值
- 《在路上 …》 金山卫士开源 , 人生很多感慨
- scum官方服务器维护时间,在等公测的这段时间里聊聊最近很火的scum吧
- 关于程序员的问题,我是看大佬说的不是我说的。
热门文章
- 智华计算机终端无法卸载,智华天成V1.0计算机终端保密检查系统软件 国密装备目录**...
- python求绝对值得方法
- 触摸屏坏了有哪些现象_触摸屏常见的故障及解决方法(实用)
- finereport激活码
- 中国科学院院士徐宗本:大数据与智能制造融合应用
- STC8H开发(十五): GPIO驱动Ci24R1无线模块
- Aizu1367 Rearranging a Sequence 模拟|签到
- 最近项目用到Dubbo框架,临时抱佛脚分享一下共探讨。
- 并发编程之深入理解十三:CompletionService CompletableFuture
- Spring之ApplicationContext介绍