第 11 章 Yama

11.1 简介

Yama 是一个源自古印度语的英文单词,翻译成汉语就是“阎罗”,阎罗是印度神话中掌管地狱的神。

Yama 可以称为半个安全模块,说它是“半个”,原因是:

(1)它是目前(3.14) Linux 主线中最简单的安全模块,只用到了 4 个 LSM 钩子函数,这4 个钩子函数都和 ptrace 相关。

(2)它没有一个完整的安全概念在背后支撑,多级安全、基于角色的访问控制、类型增强等都和它无关,它是针对具体问题——ptrace——的安全加固。

(3)它可以和其他安全模块同时起作用,系统里可以既有 SELinux 的访问控制,又有 Yama对 ptrace 的控制,而 SELinux、 SMACK、 Tomoyo、 AppArmor 这四者之间是互斥的,不能同时存在。

11.2 机制

先谈一下 ptrace 有什么潜在的安全问题。 ptrace 是一个系统调用,调用它可以让两个进程形成“跟踪”关系。跟踪进程可以查看和修改被跟踪进程内存、寄存器、信号等,可以了解被跟踪进程系统调用情况。也就是说,在跟踪进程面前,被跟踪进程毫无秘密可言。

Linux 原有的、自主访问控制下的对 ptrace 的操作控制是满足下列两个条件之一即可:

(1)跟踪进程的 uid 同时等于被跟踪进程的 uid、 euid、 suid,并且跟踪者进程的 gid 同时等于被跟踪者进程的 gid、 egid、 sgid。

(2)跟踪者进程具备能力 CAP_SYS_PTRACE。

看一下代码:

kernel/ptrace.c
static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
{
…
const struct cred *cred = current_cred(), *tcred;
tcred = __task_cred(task);
if (uid_eq(cred->uid, tcred->euid) &&
uid_eq(cred->uid, tcred->suid) &&
uid_eq(cred->uid, tcred->uid) &&
gid_eq(cred->gid, tcred->egid) &&
gid_eq(cred->gid, tcred->sgid) &&
gid_eq(cred->gid, tcred->gid))
goto ok;
if (ptrace_has_cap(tcred->user_ns, mode))
goto ok;
…
}
static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode)
{
if (mode & PTRACE_MODE_NOAUDIT)
return has_ns_capability_noaudit(current, ns, CAP_SYS_PTRACE);
else
return has_ns_capability(current, ns, CAP_SYS_PTRACE);
}

这里的问题是, uid/gid 相同的进程可以互相跟踪,如果一个进程被攻破,与之同 uid/gid的进程都沦陷。而如果特权进程被攻破,全系统的进程都不能幸免。

Yama 提供了四种模式: disabled、 relational、 capability、 no_attach。 disabled 就是 Yama 不起作用,和没有它一样。 capability 就是只有在跟踪者进程具备 CAP_SYS_PTRACE 能力时允许跟踪进程和被跟踪进程之间形成跟踪关系。 no_attach 就是根本不允许任何进程之间形成跟踪关系。 relational 是在以下三种情况之一出现时允许形成跟踪关系:

(1)跟踪者进程和被跟踪者进程之间存在纵向亲缘关系,跟踪者进程是被跟踪者进程的父进程、祖父进程……

(2) 被跟踪者进程曾经通过系统调用 prctl 的选项 PR_SET_PTRACER, 声明愿意被某个(跟踪者)进程跟踪。

(3)跟踪者进程具备 CAP_SYS_PTRACE 能力。

security/yama/yama_lsm.c
int yama_ptrace_access_check(struct task_struct *child, unsigned int mode)
{
…
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) &&
!ns_capable(__task_cred(child)->user_ns, CAP_SYS_PTRACE))
rc = -EPERM;
rcu_read_unlock();
break;
case YAMA_SCOPE_CAPABILITY:
rcu_read_lock();
if (!ns_capable(__task_cred(child)->user_ns, CAP_SYS_PTRACE))
rc = -EPERM;
rcu_read_unlock();
break;
case YAMA_SCOPE_NO_ATTACH:
default:
rc = -EPERM;
break;
}
}
…
}

Yama 在系统调用 prctl 中增加了一个选项:PR_SET_PTRACER,通过它,进程可以明确向内核注册自己可以被哪个进程跟踪。举个例子:

prctl(PR_SET_PTRACER, 1972, 0, 0, 0)

这个例子意思是:进程可以被系统中 pid 为 1972 的进程跟踪。如果传入的进程号是 0,表示进程不愿被任何进程跟踪(有纵向亲缘关系的除外),如果传入的进程号是-1,表示愿意被任何进程跟踪。

11.3 伪文件系统

Yama 的设计者希望 Yama 能够和别的安全模块同时起作用,所以 Yama 不能使用/proc/[pid]/attr 目录下的文件。 Yama 也没有使用 securityfs 文件系统,虽然使用 securityfs 不会引起和别的安全模块的冲突。 Yama 的做法是在/proc/sys/kernel/目录下创建子目录 yama,在子目录 yama 下创建文件 ptrace_scope。这个伪文件的内容是一个 0 到 3 的数字,对应 Yama 的四种工作模式,见表 11-1。

对此文件的读操作不需要特殊能力,写操作需要能力 CAP_SYS_PTRACE。

还有一点需要注意,一旦向此文件写入了 3,就不可以再写入其他值了。背后的含义就是一旦切入了最安全模式 no_attach,就不可以再变为不安全模式了。

11.4 嵌套使用

Yama 提供了一个内核编译选项: CONFIG_SECURITY_YAMA_STACKED,选择了它,可以让 Yama 和其他安全模块同时起作用。

11.5 总结

很多人都曾经利用 LSM 机制开发过自己的安全模块,功能或多或少,但是这类工作大都未能进入主线。 Yama 是一个特例。

从某种角度看, Yama 堪称完美。首先, Yama 解决的是一类实际的安全问题,而不是某种虚无缥缈的假想的安全威胁。其次, Yama 可以和别的安全模块共存。 Yama 承认自己只做了很小一部分工作,如果用户想要更全面的安全,可以启用另一个安全模块来和 Yama 合作。其实,内核各个安全模块所做的工作重复之处甚多。

Yama 的开发者 Kees Cook 在 Yama 被 Linux 主线接收后还曾经提交过新的安全模块,不过没有被接收, 在 Ubuntu 发行版中, 那些未进主线的新模块的功能至少有一部分被合并入 Ubuntu修改过的 Yama 之中。

11.6 参考资料

读者可参考 Documentation/security/Yama.txt。

习题

Yama 可以和别的 LSM 模块共存。阅读代码,看看 Yama 是如何做到和别的 LSM 模块共存的。思考一下 Yama 的这种作法可否推广到其他 LSM 模块。

第三部分 完整性保护

完整性保护的目的可以概括为一句话:防止数据被篡改。完整性保护的手段就是保存一个从原始数据推导出的度量值,在访问数据之前,先针对数据推导出当前的度量值,如果这个度量值和原始的度量值不一致,那么就说明数据已经有了变化。这样就产生了两个深层的问题,一个是这个度量值保存在哪里,另一个是如何保证这个度量值本身不被篡改。

第 12 章 IMA/EVM

12.1 简介

本章介绍 Linux 内核的完整性子系统,代码位于 security/integrity 目录下。完整性子系统又可分为两个部分:IMA(Integrity Measurement Architecture)和 EVM(Extended Verification Module)。在解释它们的具体含义之前,读者首先要明白 IMA/EVM 是 TCG(Trusted Computing Group)开放标准的一部分。在 TCG 开放标准的架构中,可信平台模块(Trusted Platform Module, TPM)是一个芯片,其上层是可信启动(Trusted Boot,TBoot)。在实践中,可信启动的一种实现方式是修改 GRUB,在其中加入完整性度量功能,形成 GRUB-IMA。在启动层之上是内核,内核中含有 TPM 的驱动以及本章要讲述的 IMA 和 EVM。内核之上是用户态的库和应用,这部分包含可信软件栈(Trusted Software Stack)和平台信任服务(Platform Trust Services)。TCG 开放标准规定的可信计算架构如图 12-1 所示。

所以,首先要了解一下什么是可信计算(Trusted Computing)。

12.1.1 可信计算

可信计算的首要问题是什么是可信,而关于可信,目前还没有统一的定义,不同的专家和不同的组织有不同的解释。1990 年,国际标准化组织与国际电子技术委员会(ISO/IEC)在其发布的目录服务系列标准中基于行为预期性定义了可信性:如果第二个实体完全按照第一个实体的预期行动,则第一个实体认为第二个实体是可信的。2002 年,TCG 用实体行为的预期性来定义可信:如果一个实体的行为总是以预期的方式,达到预期的目标,则这个实体是可信的。在人类社会中,“信任”是一个模糊的概念,可以是百分之百信任,百分之五十信任,不信任;可以今天信任,明天就不信任。在计算机的世界里很难做到模糊化,TCG 在可信 PC 规范中采用了一种简单的信任度量模型:

(1)二值化:只考虑信任和不信任两种极端情况。

(2)无损化:不考虑信任传递中的损失,即认为信任在传递过程中没有损失。所谓信任传递,就是甲信任乙,乙信任丙,于是甲也信任丙。

(3)用数据完整性度量值充当信任值:受目前信任度量理论和技术的限制,还不能直接度量(measure)计算机系统的可信性,于是采用数据完整性的度量值来作为可信性的度量值。

在可信 PC 规范中,信任链起始于 BIOS 启动块(Boot Block),BIOS 启动块度量 BIOS, BIOS 度量启动加载模块(boot loader),启动加载模块度量 OS,OS 度量应用。一级度量一级,一级信任一级,把信任扩展到整个计算机系统。而存储和保护度量值的地方就在 TPM(Trusted Platform Module)。        

TCG 所定义的 TPM 是一种 SoC(System on Chip)芯片,如图 12-2 所示。

TPM 主要用来管理密钥、执行加解密运算、数字签名、安全存储数据。本章要介绍的 IMA和 EVM 会使用 TPM 管理的密钥,会利用 TPM 提供的 PCR(Platform Configuration Register)来存储完整性度量值。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐