这里不对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. kafka消费组创建和删除原理

    0.10.0.0版本的kafka的消费者和消费组已经不在zk上注册节点了,那么消费组是以什么形式存在的呢? 1 入口 看下kafka自带的脚本kafka-consumer-groups.sh,可见脚本 ...

  2. vulnhub靶机Tr0ll:1渗透笔记

    Tr0ll:1渗透笔记 靶场下载地址:https://www.vulnhub.com/entry/tr0ll-1,100/ kali ip:192.168.20.128 靶机和kali位于同一网段 信 ...

  3. C++ | 栈的应用(逆波兰算法) | 计算器

    #include <iostream> using std::cin; using std::cout; using std::endl; template<typename T&g ...

  4. 前端面试题整理——关于EventLoop(1)

    下面代码输出打印值顺序: async function async1(){ console.log('async1 start'); await async2(); console.log('asyn ...

  5. 【Weex笔记】-- Animate.css的使用

    animate.css是一个使用CSS3的animation制作的动画效果的CSS集合,里面预设了很多种常用的动画,且使用非常简单.本文将详细介绍animate.css的使用. 一,安装辅助依赖 np ...

  6. Mybatis实现简单增删改查

    Mybatis的简单应用 学习内容: 需求 环境准备 代码 总结: 学习内容: 需求 使用Mybatis实现简单增删改查(以下是在IDEA中实现的,其他开发工具中,代码一样) jar 包下载:http ...

  7. vue获取验证码倒计时

    <template> <div> <el-button :disabled="disabled" @click="sendcode" ...

  8. ubuntu修复找不到sudo命令

    1.首先,您需要安装该sudo命令.你可以使用 apt 包管理器来做到这一点.您需要以有权安装软件包的用户身份运行此命令,例如root: apt-get install sudo 2.下一步是为您自己 ...

  9. Jenkins 脚本命令行应用总结

    Jenkins脚本命令行应用总结 测试环境 Jenkins 2.304 脚本命令行入口 Jenkins主页→系统管理→脚本命令行 遍历项目 例子:获取所有自由风格项目及相关项目信息 def proje ...

  10. Arrays工具类与Collections工具类

    Arrays工具类 : Arrays.sort():对指定数组进行排序,从小到大 Arrays.toString():返回数组的内容的字符串表示形式 Arrays.asList():数组转List,但 ...