这里不对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. 解释内存中的栈(stack)、堆(heap)和方法区(method area) 的用法?

    通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的 现场保存都使用 JVM 中的栈空间:而通过 new 关键字和构造器创建的对象则放在 堆空间,堆是垃圾收集器管理的主要区域,由于现 ...

  2. 在虚拟机里面运行java程序

    首先输入vi在里面写一个java程序 然后再查找jdk 复制jdk名字 然后安装jdk 安装完之后输入Javac加你创建的文件名 然后再输入Java 和文件名(这个不要加后缀)然后就打印出来了

  3. @Required 注解有什么用?

    @Required 应用于 bean 属性 setter 方法.此注解仅指示必须在配置时使用 bean 定义中的显式属性值或使用自动装配填充受影响的 bean 属性.如果尚未 填充受影响的 bean ...

  4. mapper.xml文件中标签没有提示的解决

    1.首先我们来看看mapper.xml的头文件 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTY ...

  5. 学习Puppet(一)

    puppet的入门 1.简介 puppet是一种采用C/S星状结构的linux.Unix平台的集中配置管理系统. puppet拥有自己的语言,可管理配置文件.用户.cron任务.软件包.系统服务等. ...

  6. 学习saltstack (二)

    saltstack使用教程: 1.安装: 需要epel的yum源,没有的话把下面的复制并新建个文件 /etc/yum.repos.d/epel.repo 粘贴即可: [epel] name=Extra ...

  7. Windows常用快捷操作

    Windows操作系统作为目前最广泛使用的PC端OS,掌握一些快捷键,方便快速在Windows系统下进行操作. 下面收集整理了一些常用的快捷操作: Ctrl + A   全选 Ctrl + C   复 ...

  8. C++中sort()函数使用介绍

    sort()简介 为什么选择使用sort()  在刷题的时候我们经常会碰到排序的问题,如果我们不使用一些排序的方法那我们只能手撕排序,这样就会浪费一些时间.而且我们还需要根据需要去选择相关的排序方法: ...

  9. Semantic UI 语义化设计的前端框架

    UI是Web的灵魂!Semantic UI是一款语义化设计的前端框架,为攻城师而制作的可复用的开源前端框架. 特性 弃用有歧义的表述 Semantic是围绕自然交流语言而架构的,这使得开发更加直观(易 ...

  10. 基于HTML5的网络拓扑图(1)

    什么是网络拓扑 网络拓扑,指构成网络的成员间特定的排列方式.分为物理的,即真实的.或者逻辑的,即虚拟的两种.如果两个网络的连接结构相同,我们就説它们的网络拓扑相同,尽管它们各自内部的物理接线.节点间距 ...