这里不对apparmor做介绍,记录一下源码分析过程。

初始化

static int __init apparmor_init(void)
-> security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks), "apparmor");
-> 该函数主要通过一个结构数组 apparmor_hooks 初始化 HOOK 函数

apparmor_hooks 结构数组分析

具体定义在这

摘取一段分析

static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(file_permission, apparmor_file_permission),
}

这里每一个 LSM_HOOK_INIT 都定义了一个 security_hook_list 结构。

security_hook_list 结构定义为:

struct security_hook_list {
struct hlist_node list;
struct hlist_head *head;
union security_list_options hook;
char *lsm;} __randomize_layout;

结合 LSM_HOOK_INIT 宏看:

#define LSM_HOOK_INIT(HEAD, HOOK) \
{ .head = &security_hook_heads.HEAD, .hook = { .HEAD = HOOK } }

可知,LSM_HOOK_INIT 把一个 security_hook_list 结构体中 head 指针指向 security_hook_heads 的一个成员链表,hook 成员初始化为 HOOK函数。

security_hook_heads 我们后面再看,我们这里推测它是一个全局变量。

security_add_hooks

我们回头继续看 security_add_hooks 函数

void __init security_add_hooks(struct security_hook_list *hooks, int count, char *lsm){
int i; for (i = 0; i < count; i++) {
hooks[i].lsm = lsm;
hlist_add_tail_rcu(&hooks[i].list, hooks[i].head);
}
...

遍历 apparmor_hooks 结构数组,对每一个数组将该数组添加到 head 指向的列表中。

以上实现即是:将每一个 security_hook_list 挂到全局 security_hook_heads 结构体的某一个成员列表中。而 security_hook_list hook 指向具体函数

security_hook_heads

接下来看看全局 security_hook_heads 是啥

struct security_hook_heads security_hook_heads __lsm_ro_after_init;

定义就一行,是个结构体, __lsm_ro_after_init 是指定的读写权限,这里不管。

security_hook_heads 结构定义为:

struct security_hook_heads {
#define LSM_HOOK(RET, DEFAULT, NAME, ...) struct hlist_head NAME;
#include "lsm_hook_defs.h"
#undef LSM_HOOK} __randomize_layout;

简短,但令人迷惑。include 会将对应文件内容放到结构体里。

lsm_hook_defs.h 内容片段如下:(剩余内容类似)

LSM_HOOK(int, 0, inode_permission, struct inode *inode, int mask)
...
LSM_HOOK(int, 0, file_permission, struct file *file, int mask)

把定义展开,结构体就变成了:

struct security_hook_heads {
struct hlist_head inode_permission;
...
struct hlist_head file_permission;
...
}

展开后,就找到了前面初始化时对应的 file_permission 成员。

调用

apparmor如何调用具体的权限检查函数呢,以 security_file_permission 为例:

int security_file_permission(struct file *file, int mask){
int ret;
ret = call_int_hook(file_permission, 0, file, mask);
...

call_int_hook 定义在这,不贴出来了,展开后结果:

({
int RC = 0;
do {
struct security_hook_list *P;
hlist_for_each_entry(P, &security_hook_heads.file_permission, list) {
RC = P->hook.file_permission(file, mask);
if (RC != 0)
break;
}
} while(0);
})

其会根据全局变量 security_hook_heads 找到 file_permission 成员列表上所有的security_hook_list 结构,并调用 hook 指向的 file_permission 函数。

这个 hook 成员前面略过去了,这里看一下,其定义为 union 类型,具体为:

union security_list_options {
#define LSM_HOOK(RET, DEFAULT, NAME, ...) RET (*NAME)(__VA_ARGS__);
#include "lsm_hook_defs.h"
#undef LSM_HOOK};

定义与 security_hook_heads 有点类似,区别在于 LSM_HOOK 宏展开方式不一样,并且是一个union 类型,对于 file_permission 展开后变成了:

union security_list_options {
int (*file_permission)( struct file *file, int mask);
}

所以,其就是一个函数指针。这就说得通了。

apparmor 源码分析的更多相关文章

  1. Docker源码分析(八):Docker Container网络(下)

    1.Docker Client配置容器网络模式 Docker目前支持4种网络模式,分别是bridge.host.container.none,Docker开发者可以根据自己的需求来确定最适合自己应用场 ...

  2. Docker源码分析(四):Docker Daemon之NewDaemon实现

    1. 前言 Docker的生态系统日趋完善,开发者群体也在日趋庞大,这让业界对Docker持续抱有极其乐观的态度.如今,对于广大开发者而言,使用Docker这项技术已然不是门槛,享受Docker带来的 ...

  3. Docker源码分析(一):Docker架构

    1 背景 1.1 Docker简介 Docker是Docker公司开源的一个基于轻量级虚拟化技术的容器引擎项目,整个项目基于Go语言开发,并遵从Apache 2.0协议.目前,Docker可以在容器内 ...

  4. 转载:Docker源码分析(一):Docker架构

    原文地址: http://www.infoq.com/cn/articles/docker-source-code-analysis-part1  作者:孙宏亮 1 背景 1.1 Docker简介 D ...

  5. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  6. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  7. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  8. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  9. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

随机推荐

  1. Java并发机制(2)--synchronized与Lock

    本内容整理自:博客园-海 子-java并发编程系列-http://www.cnblogs.com/dolphin0520/category/602384.html 1.基础: 1.什么时候出现线程安全 ...

  2. 为什么说 Mybatis 是半自动 ORM 映射工具?它与全自动 的区别在哪里?

    Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联 集合对象时,可以根据对象关系模型直接获取,所以它是全自动的.而 Mybatis 在查询关联对象或关联集 ...

  3. MariaDB数据库设置用户密码

    SET PASSWORD [FOR user] = { PASSWORD('some password') | OLD_PASSWORD('some password') | 'encrypted p ...

  4. prometheus-存储

    采集到的样本以时间序列的方式保存在内存(TSDB 时序数据库)中,并定时保存到硬盘中 prometheus一般会保留15天 prometheus按照block块的方式来存储数据,每2小时为一个时间单位 ...

  5. Idea中使用Lombok 编译报找不到符号

    1.问题描述 项目中使用了lombok,但是在idea编译过程是出现找不到符号.报错如下图所示:   file @Data @ApiModel(value = "HeadTeacherVO& ...

  6. Redis 回收进程如何工作的?

    一个客户端运行了新的命令,添加了新的数据.Redi 检查内存使用情况,如 果大于 maxmemory 的限制, 则根据设定好的策略进行回收.一个新的命令被执 行,等等.所以我们不断地穿越内存限制的边界 ...

  7. final、finalize 和 finally 的不同之处?

    final 是一个修饰符,可以修饰变量.方法和类.如果 final 修饰变量,意味着该 变量的值在初始化后不能被改变.finalize 方法是在对象被回收之前调用的方法, 给对象自己最后一个复活的机会 ...

  8. django基础环境配置

    Django环境搭建 1.下载安装 命令行 pip install django==1.11.21 pip install django==1.11.21 -i 源 pycharm setting - ...

  9. .NET Core Ecosystem

    .NET .NET Blog Application Models Web Mobile Desktop Microservices Gaming Machine Learning Cloud Int ...

  10. Vue-router实现单页面应用在没有登录情况下,自动跳转到登录页面

    这是我做前端一来的第一篇文章,都不知道该怎么开始了.那就直接奔主题吧.先讲讲这个功能的实现场景吧,我们小组使用vue全家桶实现了一个单页面应用,最初就考虑对登录状态做限制.比如登录后不能后退到登录页面 ...