这里不对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. Gradle依赖声明类型

    compileOnly -用于编译生产代码所必需的依赖关系,但不应作为运行时类路径的一部分 implementation(取代compile)-用于编译和运行时 runtimeOnly(取代runti ...

  2. 详细描述一下 Elasticsearch 索引文档的过程?

    协调节点默认使用文档 ID 参与计算(也支持通过 routing),以便为路由提供合适的分片. shard = hash(document_id) % (num_of_primary_shards) ...

  3. @Controller 注解?

    该注解表明该类扮演控制器的角色,Spring 不需要你继承任何其他控制器基类或 引用 Servlet API.

  4. 学习zabbix(六)

    实验环境 实验用2到2台机器,实验所用机器系统环境如下,可以看到2台机器的主机名和IP地址 ? 1 2 3 4 5 6 7 8 9 10 [root@linux-node1 ~]# cat /etc/ ...

  5. PCB各层的含义

    阻焊层:solder mask,是指板子上要上绿油的部分:因为它是负片输出,所以实际上有solder mask的部分实际效果并不上绿油,而是镀锡,呈银白色! 助焊层:paste mask,是机器贴片时 ...

  6. 国际化相对时间格式化API:Intl.RelativeTimeFormat

    原文:The Intl.RelativeTimeFormat API 作者:Mathias Bynens(@mathias) 现代 Web 应用程序通常使用"昨天","4 ...

  7. video标签学习使用

    video标签学习使用 学习前的理解 video是HTML5中的新标签,可以用来播放视频.对于不同的浏览器支持的视频格式不一样,但是具体浏览器支持的类型并不清楚. 支持的类型 视频的格式分为编码格式和 ...

  8. c++实现职责链模式--财务审批

    内容: 某物资管理系统中物资采购需要分级审批,主任可以审批1万元及以下的采购单,部门经理可以审批5万元及以下的采购单,副总经理可以审批10万元及以下的采购单,总经理可以审批20万元及以下的采购单,20 ...

  9. 前端如何通过js判断浏览器的类型(忽略版本)web html css javascript

    每个页面浏览器会实例出一个window对象,在window对象下有一个属性navigator,navigator本身是一个对象,navigator对象上有一个属性userAgent里面包含了当前浏览器 ...

  10. 设计模式学习笔记(十四)责任链模式实现以及在Filter中的应用

    责任链模式(Chain Of Responsibility Design Pattern),也叫做职责链,是将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求.当有请求发生时,可将请求沿着这条 ...