第 6 章. TrustedBSD MAC 框架

本文档由 Safeport Network Services 和 Network Associates Laboratories(Network Associates, Inc. 的安全研究部门)的 Chris Costello 为 FreeBSD 项目开发,根据 DARPA/SPAWAR 合同 N66001-01-C-8035 (“CBOSS”),作为 DARPA CHATS 研究项目的一部分。

无论修改与否,以源代码 (SGML DocBook) 和“编译”形式 (SGML、HTML、PDF、PostScript、RTF 等) 的重新分发和使用都是允许的,前提是满足以下条件

  1. 源代码 (SGML DocBook) 的重新分发必须保留上述版权声明、此条件列表以及以下免责声明,作为此文件的第一行,未经修改。

  2. 以编译形式 (转换为其他 DTD、转换为 PDF、PostScript、RTF 和其他格式) 的重新分发必须在文档和/或与分发一起提供的其他材料中复制上述版权声明、此条件列表以及以下免责声明。

本文档由 NETWORKS ASSOCIATES TECHNOLOGY, INC. “按原样” 提供,任何明示或暗示的保证,包括但不限于对适销性和特定目的适用性的暗示保证,均被免除。在任何情况下,NETWORKS ASSOCIATES TECHNOLOGY, INC. 均不对任何直接、间接、偶发、特殊、示例性或后果性损害(包括但不限于采购替代商品或服务、使用、数据或利润损失、或业务中断)负责,无论其起因或责任理论如何,无论是在合同中、严格责任中、还是在侵权行为(包括疏忽或其他)中,均不因使用本文档而产生,即使已被告知可能发生此类损害。

6.2. 概要

FreeBSD 包含对多种强制访问控制策略的实验性支持,以及一个用于内核安全可扩展性的框架,即 TrustedBSD MAC 框架。MAC 框架是一个可插拔的访问控制框架,允许将新的安全策略轻松地链接到内核,在启动时加载,或在运行时动态加载。该框架提供各种功能,以简化新的安全策略的实现,包括轻松地将安全标签(例如机密性信息)标记到系统对象的能力。

本章介绍 MAC 策略框架,并提供一个示例 MAC 策略模块的文档。

6.3. 简介

TrustedBSD MAC 框架提供了一种机制,允许在编译时或运行时扩展内核访问控制模型。新的系统策略可以作为内核模块实现,并链接到内核;如果多个策略模块存在,它们的执行结果将被组合。MAC 框架提供各种访问控制基础设施服务来帮助策略编写者,包括支持瞬态和持久策略无关对象安全标签。此支持目前被视为实验性的。

本章提供了适合策略模块开发人员以及 MAC 启用环境的潜在使用者阅读的信息,让他们了解 MAC 框架如何支持内核的访问控制扩展。

6.4. 策略背景

强制访问控制 (MAC) 指的是一组由操作系统强制执行于用户的访问控制策略。MAC 策略与自由裁量式访问控制 (DAC) 保护形成对比,在自由裁量式访问控制中,非管理员用户可以(根据他们的判断)保护对象。在传统的 UNIX 系统中,DAC 保护包括文件权限和访问控制列表;MAC 保护包括阻止用户间调试和防火墙的进程控制。各种 MAC 策略已经由操作系统设计人员和安全研究人员制定,包括多级安全 (MLS) 机密性策略、Biba 完整性策略、基于角色的访问控制 (RBAC)、域和类型强制 (DTE) 以及类型强制 (TE)。每个模型都根据各种因素做出决定,包括用户身份、角色和安全许可,以及代表数据敏感性和完整性等概念的对象安全标签。

TrustedBSD MAC 框架能够支持实现所有这些策略的策略模块,以及广泛的系统强化策略,这些策略可以使用现有的安全属性,例如用户和组 ID,以及文件的扩展属性,以及其他系统属性。此外,尽管有名称,但 MAC 框架也可以用于实现纯粹的自由裁量式策略,因为策略模块在授权保护方面具有很大的灵活性。

6.5. MAC 框架内核架构

TrustedBSD MAC 框架允许内核模块扩展操作系统安全策略,以及提供许多访问控制模块所需的基础设施功能。如果多个策略同时加载,MAC 框架将以有用的方式(根据对有用的定义)组合这些策略的结果。

6.5.1. 内核元素

MAC 框架包含许多内核元素

  • 框架管理接口

  • 并发和同步原语。

  • 策略注册

  • 可扩展的内核对象的的安全标签

  • 策略入口点组合操作符

  • 标签管理原语

  • 内核服务调用的入口点 API

  • 策略模块的入口点 API

  • 入口点实现(策略生命周期、对象生命周期/标签管理、访问控制检查)。

  • 策略无关的标签管理系统调用

  • mac_syscall() 多路复用系统调用

  • 各种作为 MAC 策略模块实现的安全策略

6.5.2. 框架管理接口

TrustedBSD MAC 框架可以使用 sysctl、加载程序可调参数和系统调用直接管理。

在大多数情况下,sysctl 和加载程序可调参数使用相同名称修改相同参数,并控制诸如针对各种内核子系统执行保护的行为。此外,如果 MAC 调试支持已编译到内核中,则将维护几个计数器来跟踪标签分配。通常建议不要在生产环境中使用每个子系统的执行控制来控制策略行为,因为它们会广泛影响所有活动策略的操作。相反,应优先考虑每个策略的控制,因为它们为策略模块提供了更高的粒度和更高的操作一致性。

使用系统模块管理系统调用和其他系统接口(包括引导加载程序变量)来加载和卸载策略模块;策略模块将有机会影响加载和卸载事件,包括阻止策略的意外卸载。

6.5.3. 策略列表并发和同步

由于活动策略集可能在运行时发生变化,并且入口点的调用是非原子的,因此需要同步以防止在入口点调用正在进行时加载或卸载策略,从而在整个过程中冻结活动策略集。这是通过一个框架繁忙计数实现的:每当进入入口点时,繁忙计数就会增加;每当退出时,繁忙计数就会减少。当繁忙计数升高时,不允许更改策略列表,并且尝试修改策略列表的线程将休眠,直到列表不再繁忙。繁忙计数受互斥锁保护,并且条件变量用于唤醒等待策略列表修改的休眠线程。这种同步模型的一个副作用是,允许从策略模块内部递归进入 MAC 框架,尽管通常不使用。

使用各种优化来减少繁忙计数的开销,包括如果列表为空或仅包含静态条目(在系统启动之前加载的策略,并且不能卸载)则避免增加和减少的全部成本。还提供了一个编译时选项,它可以防止在运行时对已加载策略集进行任何更改,这消除了与支持动态加载和卸载的策略相关的互斥锁锁定成本,因为不再需要同步。

由于不允许 MAC 框架在某些入口点阻塞,因此无法使用普通的休眠锁;因此,加载或卸载尝试可能会阻塞很长时间,等待框架变为空闲。

6.5.4. 标签同步

由于感兴趣的内核对象通常可以从多个线程同时访问,并且允许多个线程同时进入 MAC 框架,因此 MAC 框架维护的安全属性存储经过精心同步。通常,使用现有的内核对象数据上的内核同步来保护对象上的 MAC 框架安全标签:例如,套接字上的 MAC 标签使用现有的套接字互斥锁来保护。同样,并发访问的语义通常与容器对象的语义相同:对于凭据,与凭据结构的其余部分一样,维护标签内容的写时复制语义。MAC 框架在使用对象引用调用时断言对象上的必要锁。策略作者必须了解这些同步语义,因为它们有时会限制对标签允许的访问类型:例如,当将对凭据的只读引用通过入口点传递给策略时,仅允许对附加到凭据的标签状态执行读操作。

6.5.5. 策略同步和并发

必须编写策略模块以假定由于 FreeBSD 内核的并行和抢占性,许多内核线程可能同时进入一个或多个策略入口点。如果策略模块使用可变状态,则可能需要在策略内使用同步原语来防止对该状态的不一致视图导致策略操作不正确。策略通常能够为此目的使用现有的 FreeBSD 同步原语,包括互斥锁、休眠锁、条件变量和计数信号量。但是,应编写策略以谨慎地使用这些原语,尊重现有的内核锁顺序,并认识到某些入口点不允许休眠,这限制了在这些入口点中对原语的使用,以限制为互斥锁和唤醒操作。

当策略模块调用其他内核子系统时,它们通常需要释放任何策略内锁,以避免违反内核锁顺序或冒锁递归的风险。这将使策略锁作为全局锁顺序中的叶锁,有助于避免死锁。

6.5.6. 策略注册

MAC 框架维护两个活动策略列表:一个静态列表和一个动态列表。这些列表仅在锁定语义方面有所不同:不需要提高引用计数来使用静态列表。当包含 MAC 框架策略的内核模块加载时,策略模块将使用 SYSINIT 来调用注册函数;当策略模块卸载时,SYSINIT 将同样调用注销函数。如果策略模块被加载多次,如果注册可用资源不足(例如,策略可能需要标记并且没有足够的标记状态可用),或者其他策略先决条件可能未满足(某些策略可能只能在启动之前加载),则注册可能会失败。同样,如果将策略标记为不可卸载,则注销可能会失败。

6.5.7. 入口点

内核服务以两种方式与 MAC 框架交互:它们调用一系列 API 来通知框架相关事件,以及在安全相关的对象中提供与策略无关的标签结构指针。标签指针由 MAC 框架通过标签管理入口点维护,并允许框架通过对维护对象的内核子系统的相对非侵入性更改为策略模块提供标签服务。例如,标签指针已添加到进程、进程凭据、套接字、管道、vnode、Mbuf、网络接口、IP 重组队列以及各种其他安全相关结构中。内核服务在执行重要的安全决策时也会调用 MAC 框架,允许策略模块根据自己的标准(可能包括存储在安全标签中的数据)来增强这些决策。这些安全关键决策中的大多数将是明确的访问控制检查;但是,有些会影响更一般的决策功能,例如套接字的包匹配和程序执行时的标签转换。

6.5.8. 策略组合

当一次将多个策略模块加载到内核中时,框架将使用组合运算符来组合策略模块的结果。此运算符当前是硬编码的,并且要求所有活动策略必须批准请求才能返回成功。由于策略可能会返回各种错误条件(成功、拒绝访问、对象不存在等),因此优先级运算符从策略返回的错误集中选择结果错误。通常,指示对象不存在的错误优先于指示拒绝访问对象的错误。虽然不能保证结果组合是有用或安全的,但我们发现它对于许多有用的策略选择是有效的。例如,传统的可信系统通常会使用两个或多个策略来使用类似的组合。

6.5.9. 标签支持

由于许多有趣的访问控制扩展依赖于对象上的安全标签,因此 MAC 框架提供了一组与策略无关的标签管理系统调用,涵盖各种用户公开的对象。常见的标签类型包括分区标识符、敏感度标签、完整性标签、隔室、域、角色和类型。与策略无关是指策略模块能够完全定义与对象相关的元数据的语义。策略模块参与由用户应用程序提供的基于字符串的标签的内部化和外部化,并且可以根据需要向应用程序公开多个标签元素。

内存中的标签存储在板分配的 struct label 中,它由固定长度的联合数组组成,每个联合都包含一个 void * 指针和一个 long。注册标签存储的策略将被分配一个“插槽”标识符,该标识符可用于取消引用标签存储。存储的语义完全由策略模块决定:模块提供与内核对象生命周期相关的各种入口点,包括初始化、关联/创建和销毁。使用这些接口,可以实现引用计数和其他存储模型。策略模块通常不需要直接访问对象结构来检索标签,因为 MAC 框架通常会将指向对象的指针和指向对象标签的直接指针传递到入口点。此规则的主要例外是进程凭据,必须手动取消引用才能访问凭据标签。这可能会在 MAC 框架的未来修订中发生变化。

初始化入口点通常包含一个休眠处置标志,指示是否允许初始化休眠;如果不允许休眠,则可能会返回失败以取消标签的分配(因此取消对象)。例如,这可能发生在网络堆栈中处理中断时,此时不允许休眠,或者调用方持有互斥锁时。由于在飞行网络数据包(Mbuf)上维护标签的性能成本,策略必须明确声明对分配 Mbuf 标签的要求。使用标签的动态加载的策略必须能够处理其 init 函数尚未在对象上调用的情况,因为当策略加载时对象可能已经存在。MAC 框架保证未初始化的标签插槽将保存 0 或 NULL 值,策略可以使用它来检测未初始化的值。但是,由于 Mbuf 标签的分配是条件性的,因此如果策略已动态加载,则策略还必须能够处理 Mbuf 的 NULL 标签指针。

在文件系统标签的情况下,为扩展属性中的安全标签的持久存储提供了特殊支持。在有扩展属性的地方,使用扩展属性事务来允许对 vnode 上的安全标签进行一致的复合更新——目前这种支持仅存在于 UFS2 文件系统中。策略作者可以选择使用一个(或多个)扩展属性来实现多标签文件系统对象标签。出于效率原因,vnode 标签 (v_label) 是任何磁盘上标签的缓存;策略能够在实例化 vnode 时将值加载到缓存中,并根据需要更新缓存。因此,扩展属性不需要在每次访问控制检查时都直接访问。

目前,如果已标记的策略允许动态卸载,则其状态槽位无法回收,这使得已标记策略的卸载-重新加载操作数量受到严格(并且相对较低)的限制。

6.5.10. 系统调用

MAC 框架实现了许多系统调用:其中大多数调用支持向用户应用程序公开的与策略无关的标签检索和操作 API。

标签管理调用接受一个标签描述结构,struct mac,其中包含一系列 MAC 标签元素。每个元素包含一个字符字符串名称和一个字符字符串值。每个策略都有机会声明特定的元素名称,允许策略根据需要公开多个独立元素。策略模块通过入口点执行内核标签和用户提供的标签之间的内部化和外部化,允许各种语义。标签管理系统调用通常由用户库函数包装以执行内存分配和错误处理,简化了必须管理标签的用户应用程序。

以下与 MAC 相关的系统调用存在于 FreeBSD 内核中。

  • mac_get_proc() 可用于检索当前进程的标签。

  • mac_set_proc() 可用于请求更改当前进程的标签。

  • mac_get_fd() 可用于检索由文件描述符引用的对象(文件、套接字、管道等)的标签。

  • mac_get_file() 可用于检索由文件系统路径引用的对象的标签。

  • mac_set_fd() 可用于请求更改由文件描述符引用的对象(文件、套接字、管道等)的标签。

  • mac_set_file() 可用于请求更改由文件系统路径引用的对象的标签。

  • mac_syscall() 允许策略模块创建新的系统调用而无需修改系统调用表;它接受目标策略名称、操作编号和不透明参数供策略使用。

  • mac_get_pid() 可用于请求另一个进程的标签,按进程 ID。

  • mac_get_link()mac_get_file() 相同,只是它不会跟踪符号链接,如果它是路径中的最后一个条目,因此可用于检索符号链接上的标签。

  • mac_set_link()mac_set_file() 相同,只是它不会跟踪符号链接,如果它是路径中的最后一个条目,因此可用于操作符号链接上的标签。

  • mac_execve()execve() 系统调用相同,只是它还接受一个请求的标签,以在开始执行新程序时将进程标签设置为该标签。执行时的此标签更改称为“转换”。

  • mac_get_peer(),实际上是通过套接字选项实现的,检索套接字上远程对端的标签(如果可用)。

除了这些系统调用外,SIOCSIGMACSIOCSIFMAC 网络接口 ioctl 允许检索和设置网络接口上的标签。

6.6. MAC 策略架构

安全策略要么直接链接到内核,要么编译到可加载内核模块中,这些模块可以在引导时加载,也可以在运行时使用模块加载系统调用动态加载。策略模块通过一组声明的入口点与系统交互,提供对系统事件流的访问,并允许策略影响访问控制决策。每个策略包含多个元素。

  • 策略的可选配置参数。

  • 策略逻辑和参数的集中式实现。

  • 策略生命周期事件的可选实现,例如初始化和销毁。

  • 对在选定内核对象上初始化、维护和销毁标签的可选支持。

  • 对用户进程检查和修改选定对象上的标签的可选支持。

  • 对策略感兴趣的选定访问控制入口点的实现。

  • 声明策略标识、模块入口点和策略属性。

6.6.1. 策略声明

可以使用 MAC_POLICY_SET() 宏声明模块,该宏命名策略、提供对 MAC 入口点向量的引用、提供加载时标志,以确定策略框架应如何处理策略,并可选地请求框架分配标签状态。

static struct mac_policy_ops mac_policy_ops =
{
        .mpo_destroy = mac_policy_destroy,
        .mpo_init = mac_policy_init,
        .mpo_init_bpfdesc_label = mac_policy_init_bpfdesc_label,
        .mpo_init_cred_label = mac_policy_init_label,
/* ... */
        .mpo_check_vnode_setutimes = mac_policy_check_vnode_setutimes,
        .mpo_check_vnode_stat = mac_policy_check_vnode_stat,
        .mpo_check_vnode_write = mac_policy_check_vnode_write,
};

在此示例中,MAC 策略入口点向量 macpolicyops 将模块中定义的函数与特定入口点关联。可在 MAC 入口点参考部分找到可用入口点的完整列表及其原型。在模块注册期间,.mpo_destroy 和 .mpo_init 入口点特别有趣。.mpo_init 将在策略成功注册到模块框架但任何其他入口点处于活动状态之前调用。这允许策略执行任何策略特定的分配和初始化,例如初始化任何数据或锁。.mpo_destroy 将在卸载策略模块时调用,以允许释放任何已分配的内存和销毁锁。目前,这两个入口点在 MAC 策略列表互斥锁处于锁定状态时调用,以防止任何其他入口点被调用:这将会改变,但在此期间,策略应该注意它们调用的内核原语,以避免锁排序或睡眠问题。

策略声明的模块名称字段存在,以便可以为模块依赖性目的唯一标识该模块。应选择适当的字符串。在加载和卸载事件期间,策略的完整字符串名称会显示给用户,并通过内核日志显示,并且在向用户空间进程提供状态信息时也会导出。

6.6.2. 策略标志

策略声明标志字段允许模块在加载模块时向框架提供有关其功能的信息。目前,定义了三个标志。

MPC_LOADTIME_FLAG_UNLOADOK

此标志表示可以卸载策略模块。如果没有提供此标志,则策略框架将拒绝卸载模块的请求。此标志可能被分配标签状态并且无法在运行时释放该状态的模块使用。

MPC_LOADTIME_FLAG_NOTLATE

此标志表示策略模块必须在引导过程的早期加载和初始化。如果指定了此标志,则在引导后尝试注册模块将被拒绝。该标志可用于需要对所有系统对象进行普遍标记的策略,并且无法处理尚未由策略正确初始化的对象。

MPC_LOADTIME_FLAG_LABELMBUFS

此标志表示策略模块需要对 Mbuf 进行标记,并且应始终为存储 Mbuf 标签分配内存。默认情况下,MAC 框架不会为 Mbuf 分配标签存储,除非至少一个已加载的策略设置了此标志。当策略不需要 Mbuf 标记时,这会显着提高网络性能。内核选项 MAC_ALWAYS_LABEL_MBUF 存在,以强制 MAC 框架分配 Mbuf 标签存储,而与此标志的设置无关,并且可能在某些环境中很有用。

使用 MPC_LOADTIME_FLAG_LABELMBUFS 但未设置 MPC_LOADTIME_FLAG_NOTLATE 标志的策略必须能够正确处理传递到入口点的 NULL Mbuf 标签指针。这是必要的,因为在启用 Mbuf 标记的策略加载后,没有标签存储的飞行中 Mbuf 可能会持续存在。如果策略在网络子系统处于活动状态之前加载(即,策略未在加载时加载),则所有 Mbuf 都保证具有标签存储。

6.6.3. 策略入口点

向注册到框架的策略提供四类入口点:与策略的注册和管理相关的入口点、表示内核对象的初始化、创建、销毁和其他生命周期事件的入口点、与策略模块可能影响的访问控制决策相关的事件以及与管理对象上的标签相关的调用。此外,还提供了一个 mac_syscall() 入口点,以便策略可以在不注册新系统调用情况下扩展内核接口。

策略模块编写者应了解内核锁定策略以及在哪些入口点可以使用哪些对象锁。编写者应尝试通过避免在入口点内获取非叶锁来避免死锁情况,并遵循对象访问和修改的锁定协议。特别是,编写者应注意,虽然通常会保留访问对象及其标签的必要锁,但可能并非所有入口点都具有修改对象或其标签的足够锁。参数的锁定信息在 MAC 框架入口点文档中有所记录。

策略入口点将传递对对象标签的引用以及对象本身。这允许标记的策略不知道对象的内部结构,但仍然可以根据标签做出决策。例外情况是进程凭证,该凭证被假定为策略在内核中的一流安全对象。

6.7. MAC 策略入口点参考

6.7.1. 通用模块入口点

6.7.1.1. mpo_init

void mpo_init(struct mac_policy_conf *conf);
参数描述锁定

conf

MAC 策略定义

策略加载事件。策略列表互斥锁处于锁定状态,因此无法执行睡眠操作,并且必须谨慎地调用其他内核子系统。如果在策略初始化期间需要潜在的睡眠内存分配,则应使用单独的模块 SYSINIT() 进行分配。

6.7.1.2. mpo_destroy

void mpo_destroy(struct mac_policy_conf *conf);
参数描述锁定

conf

MAC 策略定义

策略加载事件。策略列表互斥锁处于锁定状态,因此应谨慎操作。

6.7.1.3. mpo_syscall

int mpo_syscall(struct thread *td, int call, void *arg);
参数描述锁定

td

调用线程

call

特定于策略的系统调用编号

arg

指向系统调用参数的指针

此入口点提供了一个策略多路复用系统调用,以便策略可以向用户进程提供其他服务,而无需注册特定系统调用。在注册期间提供的策略名称用于从用户空间多路复用调用,并且参数将转发到此入口点。在实现新服务时,安全模块应确保根据需要从 MAC 框架调用适当的访问控制检查。例如,如果策略实现增强的信号功能,则应调用必要的信号访问控制检查以调用 MAC 框架和其他已注册的策略。

模块目前必须自行执行 copyin() 系统调用数据的操作。

6.7.1.4. mpo_thread_userret

void mpo_thread_userret(struct thread *td);
参数描述锁定

td

返回线程

此入口点允许策略模块在线程通过系统调用返回、陷阱返回或其他方式返回用户空间时执行与 MAC 相关的事件。对于具有浮动进程标签的策略,这是必需的,因为在系统调用处理期间,无法始终在堆栈中的任意点获取进程锁;进程标签可能代表传统的身份验证数据、进程历史信息或其他数据。为了使用此机制,可以将意图对进程凭据标签进行的更改存储在由每个策略自旋锁保护的p_label中,然后设置每个线程的TDF_ASTPENDING标志和每个进程的PS_MACPENDM标志,以调度对userret入口点的调用。从这个入口点开始,策略可以在不考虑锁定上下文的情况下创建替换凭据。策略编写者应注意,与调度 AST 和执行 AST 相关的事件排序可能很复杂,并且在多线程应用程序中会相互交织。

6.7.2. 标签操作

6.7.2.1. mpo_init_bpfdesc_label

void mpo_init_bpfdesc_label(struct label *label);
参数描述锁定

标签

要应用的新标签

在新建的 bpfdesc(BPF 描述符)上初始化标签。允许休眠。

6.7.2.2. mpo_init_cred_label

void mpo_init_cred_label(struct label *label);
参数描述锁定

标签

要初始化的新标签

为新实例化的用户凭据初始化标签。允许休眠。

6.7.2.3. mpo_init_devfsdirent_label

void mpo_init_devfsdirent_label(struct label *label);
参数描述锁定

标签

要应用的新标签

在新建的 devfs 条目上初始化标签。允许休眠。

6.7.2.4. mpo_init_ifnet_label

void mpo_init_ifnet_label(struct label *label);
参数描述锁定

标签

要应用的新标签

在新建的网络接口上初始化标签。允许休眠。

6.7.2.5. mpo_init_ipq_label

void mpo_init_ipq_label(struct label *label, int flag);
参数描述锁定

标签

要应用的新标签

标志

休眠/非休眠 malloc(9);见下文

在新建的 IP 片段重组队列上初始化标签。flag 字段可以是 M_WAITOK 和 M_NOWAIT 之一,应使用它来避免在此初始化调用期间执行休眠的 malloc(9)。IP 片段重组队列分配通常发生在性能敏感的环境中,实现应该注意避免休眠或长时间运行的操作。此入口点允许失败,导致无法分配 IP 片段重组队列。

6.7.2.6. mpo_init_mbuf_label

void mpo_init_mbuf_label(int flag, struct label *label);
参数描述锁定

标志

休眠/非休眠 malloc(9);见下文

标签

要初始化的策略标签

在新实例化的 mbuf 数据包头(mbuf)上初始化标签。flag 字段可以是 M_WAITOK 和 M_NOWAIT 之一,应使用它来避免在此初始化调用期间执行休眠的 malloc(9)。Mbuf 分配通常发生在性能敏感的环境中,实现应该注意避免休眠或长时间运行的操作。此入口点允许失败,导致无法分配 mbuf 头。

6.7.2.7. mpo_init_mount_label

void mpo_init_mount_label(struct label *mntlabel, struct label *fslabel);
参数描述锁定

mntlabel

要为挂载点本身初始化的策略标签

fslabel

要为文件系统初始化的策略标签

在新建的挂载点上初始化标签。允许休眠。

6.7.2.8. mpo_init_mount_fs_label

void mpo_init_mount_fs_label(struct label *label);
参数描述锁定

标签

要初始化的标签

在新建的挂载文件系统上初始化标签。允许休眠

6.7.2.9. mpo_init_pipe_label

void mpo_init_pipe_label(struct label *label);
参数描述锁定

标签

要填充的标签

为新实例化的管道初始化标签。允许休眠。

6.7.2.10. mpo_init_socket_label

void mpo_init_socket_label(struct label *label, int flag);
参数描述锁定

标签

要初始化的新标签

标志

malloc(9) 标志

为新实例化的套接字初始化标签。flag 字段可以是 M_WAITOK 和 M_NOWAIT 之一,应使用它来避免在此初始化调用期间执行休眠的 malloc(9)

6.7.2.11. mpo_init_socket_peer_label

void mpo_init_socket_peer_label(struct label *label, int flag);
参数描述锁定

标签

要初始化的新标签

标志

malloc(9) 标志

为新实例化的套接字初始化对等标签。flag 字段可以是 M_WAITOK 和 M_NOWAIT 之一,应使用它来避免在此初始化调用期间执行休眠的 malloc(9)

6.7.2.12. mpo_init_proc_label

void mpo_init_proc_label(struct label *label);
参数描述锁定

标签

要初始化的新标签

为新实例化的进程初始化标签。允许休眠。

6.7.2.13. mpo_init_vnode_label

void mpo_init_vnode_label(struct label *label);
参数描述锁定

标签

要初始化的新标签

在新建的 vnode 上初始化标签。允许休眠。

6.7.2.14. mpo_destroy_bpfdesc_label

void mpo_destroy_bpfdesc_label(struct label *label);
参数描述锁定

标签

bpfdesc 标签

销毁 BPF 描述符上的标签。在此入口点,策略应释放与label关联的任何内部存储,以便可以销毁它。

6.7.2.15. mpo_destroy_cred_label

void mpo_destroy_cred_label(struct label *label);
参数描述锁定

标签

要销毁的标签

销毁凭据上的标签。在此入口点,策略模块应释放与label关联的任何内部存储,以便可以销毁它。

6.7.2.16. mpo_destroy_devfsdirent_label

void mpo_destroy_devfsdirent_label(struct label *label);
参数描述锁定

标签

要销毁的标签

销毁 devfs 条目上的标签。在此入口点,策略模块应释放与label关联的任何内部存储,以便可以销毁它。

6.7.2.17. mpo_destroy_ifnet_label

void mpo_destroy_ifnet_label(struct label *label);
参数描述锁定

标签

要销毁的标签

销毁已删除接口上的标签。在此入口点,策略模块应释放与label关联的任何内部存储,以便可以销毁它。

6.7.2.18. mpo_destroy_ipq_label

void mpo_destroy_ipq_label(struct label *label);
参数描述锁定

标签

要销毁的标签

销毁 IP 片段队列上的标签。在此入口点,策略模块应释放与label关联的任何内部存储,以便可以销毁它。

6.7.2.19. mpo_destroy_mbuf_label

void mpo_destroy_mbuf_label(struct label *label);
参数描述锁定

标签

要销毁的标签

销毁 mbuf 头上的标签。在此入口点,策略模块应释放与label关联的任何内部存储,以便可以销毁它。

6.7.2.20. mpo_destroy_mount_label

void mpo_destroy_mount_label(struct label *label);
参数描述锁定

标签

要销毁的挂载点标签

销毁挂载点上的标签。在此入口点,策略模块应释放与mntlabel关联的内部存储,以便可以销毁它。

6.7.2.21. mpo_destroy_mount_label

void mpo_destroy_mount_label(struct label *mntlabel, struct label *fslabel);
参数描述锁定

mntlabel

要销毁的挂载点标签

fslabel

要销毁的文件系统标签>

销毁挂载点上的标签。在此入口点,策略模块应释放与mntlabelfslabel关联的内部存储,以便可以销毁它。

6.7.2.22. mpo_destroy_socket_label

void mpo_destroy_socket_label(struct label *label);
参数描述锁定

标签

要销毁的套接字标签

销毁套接字上的标签。在此入口点,策略模块应释放与label关联的任何内部存储,以便可以销毁它。

6.7.2.23. mpo_destroy_socket_peer_label

void mpo_destroy_socket_peer_label(struct label *peerlabel);
参数描述锁定

peerlabel

要销毁的套接字对等标签

销毁套接字上的对等标签。在此入口点,策略模块应释放与label关联的任何内部存储,以便可以销毁它。

6.7.2.24. mpo_destroy_pipe_label

void mpo_destroy_pipe_label(struct label *label);
参数描述锁定

标签

管道标签

销毁管道上的标签。在此入口点,策略模块应释放与label关联的任何内部存储,以便可以销毁它。

6.7.2.25. mpo_destroy_proc_label

void mpo_destroy_proc_label(struct label *label);
参数描述锁定

标签

进程标签

销毁进程上的标签。在此入口点,策略模块应释放与label关联的任何内部存储,以便可以销毁它。

6.7.2.26. mpo_destroy_vnode_label

void mpo_destroy_vnode_label(struct label *label);
参数描述锁定

标签

进程标签

销毁 vnode 上的标签。在此入口点,策略模块应释放与label关联的任何内部存储,以便可以销毁它。

6.7.2.27. mpo_copy_mbuf_label

void mpo_copy_mbuf_label(struct label *src, struct label *dest);
参数描述锁定

src

源标签

dest

目标标签

src中的标签信息复制到dest中。

6.7.2.28. mpo_copy_pipe_label

void mpo_copy_pipe_label(struct label *src, struct label *dest);
参数描述锁定

src

源标签

dest

目标标签

src中的标签信息复制到dest中。

6.7.2.29. mpo_copy_vnode_label

void mpo_copy_vnode_label(struct label *src, struct label *dest);
参数描述锁定

src

源标签

dest

目标标签

src中的标签信息复制到dest中。

6.7.2.30. mpo_externalize_cred_label

int mpo_externalize_cred_label(struct label *label, char *element_name,
    struct sbuf *sb, int *claimed);
参数描述锁定

标签

要外部化的标签

element_name

应外部化其标签的策略的名称

sb

要填充标签文本表示的字符串缓冲区

claimed

当可以填充element_data时应增加。

根据传入的标签结构生成外部化的标签。外部化的标签由标签内容的文本表示组成,该表示可以与用户空间应用程序一起使用并由用户读取。目前,所有策略的externalize入口点都将被调用,因此实现应该在尝试填充sb之前检查element_name的内容。如果element_name与您的策略名称不匹配,则只需返回 0。仅当在外部化标签数据时发生错误时才返回非零值。一旦策略填充element_data*claimed应该增加。

6.7.2.31. mpo_externalize_ifnet_label

int mpo_externalize_ifnet_label(struct label *label, char *element_name,
    struct sbuf *sb, int *claimed);
参数描述锁定

标签

要外部化的标签

element_name

应外部化其标签的策略的名称

sb

要填充标签文本表示的字符串缓冲区

claimed

当可以填充element_data时应增加。

根据传入的标签结构生成外部化的标签。外部化的标签由标签内容的文本表示组成,该表示可以与用户空间应用程序一起使用并由用户读取。目前,所有策略的externalize入口点都将被调用,因此实现应该在尝试填充sb之前检查element_name的内容。如果element_name与您的策略名称不匹配,则只需返回 0。仅当在外部化标签数据时发生错误时才返回非零值。一旦策略填充element_data*claimed应该增加。

6.7.2.32. mpo_externalize_pipe_label

int mpo_externalize_pipe_label(struct label *label, char *element_name,
    struct sbuf *sb, int *claimed);
参数描述锁定

标签

要外部化的标签

element_name

应外部化其标签的策略的名称

sb

要填充标签文本表示的字符串缓冲区

claimed

当可以填充element_data时应增加。

根据传入的标签结构生成外部化的标签。外部化的标签由标签内容的文本表示组成,该表示可以与用户空间应用程序一起使用并由用户读取。目前,所有策略的externalize入口点都将被调用,因此实现应该在尝试填充sb之前检查element_name的内容。如果element_name与您的策略名称不匹配,则只需返回 0。仅当在外部化标签数据时发生错误时才返回非零值。一旦策略填充element_data*claimed应该增加。

6.7.2.33. mpo_externalize_socket_label

int mpo_externalize_socket_label(struct label *label, char *element_name,
    struct sbuf *sb, int *claimed);
参数描述锁定

标签

要外部化的标签

element_name

应外部化其标签的策略的名称

sb

要填充标签文本表示的字符串缓冲区

claimed

当可以填充element_data时应增加。

根据传入的标签结构生成外部化的标签。外部化的标签由标签内容的文本表示组成,该表示可以与用户空间应用程序一起使用并由用户读取。目前,所有策略的externalize入口点都将被调用,因此实现应该在尝试填充sb之前检查element_name的内容。如果element_name与您的策略名称不匹配,则只需返回 0。仅当在外部化标签数据时发生错误时才返回非零值。一旦策略填充element_data*claimed应该增加。

6.7.2.34. mpo_externalize_socket_peer_label

int mpo_externalize_socket_peer_label(struct label *label, char *element_name,
    struct sbuf *sb, int *claimed);
参数描述锁定

标签

要外部化的标签

element_name

应外部化其标签的策略的名称

sb

要填充标签文本表示的字符串缓冲区

claimed

当可以填充element_data时应增加。

根据传入的标签结构生成外部化的标签。外部化的标签由标签内容的文本表示组成,该表示可以与用户空间应用程序一起使用并由用户读取。目前,所有策略的externalize入口点都将被调用,因此实现应该在尝试填充sb之前检查element_name的内容。如果element_name与您的策略名称不匹配,则只需返回 0。仅当在外部化标签数据时发生错误时才返回非零值。一旦策略填充element_data*claimed应该增加。

6.7.2.35. mpo_externalize_vnode_label

int mpo_externalize_vnode_label(struct label *label, char *element_name,
    struct sbuf *sb, int *claimed);
参数描述锁定

标签

要外部化的标签

element_name

应外部化其标签的策略的名称

sb

要填充标签文本表示的字符串缓冲区

claimed

当可以填充element_data时应增加。

根据传入的标签结构生成外部化的标签。外部化的标签由标签内容的文本表示组成,该表示可以与用户空间应用程序一起使用并由用户读取。目前,所有策略的externalize入口点都将被调用,因此实现应该在尝试填充sb之前检查element_name的内容。如果element_name与您的策略名称不匹配,则只需返回 0。仅当在外部化标签数据时发生错误时才返回非零值。一旦策略填充element_data*claimed应该增加。

6.7.2.36. mpo_internalize_cred_label

int mpo_internalize_cred_label(struct label *label, char *element_name,
    char *element_data, int *claimed);
参数描述锁定

标签

要填充的标签

element_name

应内部化其标签的策略的名称

element_data

要内部化的文本数据。

claimed

当数据能够成功内部化时,应增加此值。

根据文本格式的外部化标签数据生成内部标签结构。当前,当请求内部化时,所有策略的 internalize 入口点都会被调用,因此实现应该将 element_name 的内容与其自身的名称进行比较,以确保它应该内部化 element_data 中的数据。与 externalize 入口点类似,如果 element_name 与其自身名称不匹配,则入口点应返回 0,或者当数据能够成功内部化时,在这种情况下,应增加 *claimed 的值。

6.7.2.37. mpo_internalize_ifnet_label

int mpo_internalize_ifnet_label(struct label *label, char *element_name,
    char *element_data, int *claimed);
参数描述锁定

标签

要填充的标签

element_name

应内部化其标签的策略的名称

element_data

要内部化的文本数据。

claimed

当数据能够成功内部化时,应增加此值。

根据文本格式的外部化标签数据生成内部标签结构。当前,当请求内部化时,所有策略的 internalize 入口点都会被调用,因此实现应该将 element_name 的内容与其自身的名称进行比较,以确保它应该内部化 element_data 中的数据。与 externalize 入口点类似,如果 element_name 与其自身名称不匹配,则入口点应返回 0,或者当数据能够成功内部化时,在这种情况下,应增加 *claimed 的值。

6.7.2.38. mpo_internalize_pipe_label

int mpo_internalize_pipe_label(struct label *label, char *element_name,
    char *element_data, int *claimed);
参数描述锁定

标签

要填充的标签

element_name

应内部化其标签的策略的名称

element_data

要内部化的文本数据。

claimed

当数据能够成功内部化时,应增加此值。

根据文本格式的外部化标签数据生成内部标签结构。当前,当请求内部化时,所有策略的 internalize 入口点都会被调用,因此实现应该将 element_name 的内容与其自身的名称进行比较,以确保它应该内部化 element_data 中的数据。与 externalize 入口点类似,如果 element_name 与其自身名称不匹配,则入口点应返回 0,或者当数据能够成功内部化时,在这种情况下,应增加 *claimed 的值。

6.7.2.39. mpo_internalize_socket_label

int mpo_internalize_socket_label(struct label *label, char *element_name,
    char *element_data, int *claimed);
参数描述锁定

标签

要填充的标签

element_name

应内部化其标签的策略的名称

element_data

要内部化的文本数据。

claimed

当数据能够成功内部化时,应增加此值。

根据文本格式的外部化标签数据生成内部标签结构。当前,当请求内部化时,所有策略的 internalize 入口点都会被调用,因此实现应该将 element_name 的内容与其自身的名称进行比较,以确保它应该内部化 element_data 中的数据。与 externalize 入口点类似,如果 element_name 与其自身名称不匹配,则入口点应返回 0,或者当数据能够成功内部化时,在这种情况下,应增加 *claimed 的值。

6.7.2.40. mpo_internalize_vnode_label

int mpo_internalize_vnode_label(struct label *label, char *element_name,
    char *element_data, int *claimed);
参数描述锁定

标签

要填充的标签

element_name

应内部化其标签的策略的名称

element_data

要内部化的文本数据。

claimed

当数据能够成功内部化时,应增加此值。

根据文本格式的外部化标签数据生成内部标签结构。当前,当请求内部化时,所有策略的 internalize 入口点都会被调用,因此实现应该将 element_name 的内容与其自身的名称进行比较,以确保它应该内部化 element_data 中的数据。与 externalize 入口点类似,如果 element_name 与其自身名称不匹配,则入口点应返回 0,或者当数据能够成功内部化时,在这种情况下,应增加 *claimed 的值。

6.7.3. 标签事件

此类入口点由 MAC 框架使用,允许策略维护内核对象上的标签信息。对于 MAC 策略感兴趣的每个带标签的内核对象,可以为相关的生命周期事件注册入口点。所有对象都实现了初始化、创建和销毁挂钩。一些对象还会实现重新标记,允许用户进程更改对象上的标签。一些对象还会实现特定于对象自身的事件,例如与 IP 重新组装相关的标签事件。典型的带标签对象将具有以下生命周期入口点

Label initialization          o
(object-specific wait)         \
Label creation                  o
                                 \
Relabel events,                   o--<--.
Various object-specific,          |     |
Access control events             ~-->--o
                                         \
Label destruction                         o

标签初始化允许策略在没有对象使用上下文的条件下为标签分配内存并设置初始值。分配给策略的标签槽默认情况下将被清零,因此某些策略可能不需要执行初始化。

当内核结构与实际的内核对象相关联时,将发生标签创建。例如,Mbuf 可以分配并保持未使用的状态,直到它们被需要。mbuf 分配会导致对 mbuf 进行标签初始化,但 mbuf 创建发生在 mbuf 与数据报相关联时。通常,将提供创建事件的上下文,包括创建的具体情况以及创建过程中其他相关对象的标签。例如,当从套接字创建 mbuf 时,除了新的 mbuf 及其标签之外,套接字及其标签还将被提供给已注册的策略。在创建事件中不鼓励内存分配,因为它可能发生在内核的性能敏感端口中;此外,创建调用不允许失败,因此无法报告内存分配失败。

特定于对象的事件通常不会归入其他广泛的标签事件类别,但通常将提供一个机会来修改或更新对象上的标签,以基于额外的上下文。例如,IP 分片重新组装队列上的标签可以在 MAC_UPDATE_IPQ 入口点期间更新,因为将附加的 mbuf 接受到该队列中。

下一节将详细讨论访问控制事件。

标签销毁允许策略在标签与对象相关联期间释放与标签相关的存储或状态,以便支持该对象的内核数据结构可以被重新使用或释放。

除了与特定内核对象相关的标签之外,还存在另一类标签:临时标签。这些标签用于存储用户进程提交的更新信息。这些标签与其他标签类型一样被初始化和销毁,但创建事件是 MAC_INTERNALIZE,它接受要转换为内核表示的用户标签。

6.7.3.1. 文件系统对象标记事件操作

6.7.3.1.1. mpo_associate_vnode_devfs
void mpo_associate_vnode_devfs(struct mount *mp, struct label *fslabel,
    struct devfs_dirent *de, struct label *delabel, struct vnode *vp,
    struct label *vlabel);
参数描述锁定

mp

Devfs 挂载点

fslabel

Devfs 文件系统标签 (mp→mnt_fslabel)

de

Devfs 目录项

delabel

de 关联的策略标签

vp

de 关联的 vnode

vlabel

vp 关联的策略标签

根据 de 中传递的 devfs 目录项及其标签填充新创建的 devfs vnode 的标签 (vlabel)。

6.7.3.1.2. mpo_associate_vnode_extattr
int mpo_associate_vnode_extattr(struct mount *mp, struct label *fslabel,
    struct vnode *vp, struct label *vlabel);
参数描述锁定

mp

文件系统挂载点

fslabel

文件系统标签

vp

要标记的 vnode

vlabel

vp 关联的策略标签

尝试从文件系统扩展属性中检索 vp 的标签。成功后,将返回 0 值。如果扩展属性检索不受支持,则可接受的回退是将 fslabel 复制到 vlabel 中。如果发生错误,应返回 errno 的适当值。

6.7.3.1.3. mpo_associate_vnode_singlelabel
void mpo_associate_vnode_singlelabel(struct mount *mp, struct label *fslabel,
    struct vnode *vp, struct label *vlabel);
参数描述锁定

mp

文件系统挂载点

fslabel

文件系统标签

vp

要标记的 vnode

vlabel

vp 关联的策略标签

在非多标签文件系统上,调用此入口点来设置基于文件系统标签 fslabelvp 的策略标签。

6.7.3.1.4. mpo_create_devfs_device
void mpo_create_devfs_device(dev_t dev, struct devfs_dirent *devfs_dirent,
    struct label *label);
参数描述锁定

dev

devfs_dirent 相对应的设备

devfs_dirent

要标记的 Devfs 目录项。

标签

要填充的 devfs_dirent 的标签。

为为传递的设备创建的 devfs_dirent 填写标签。当设备文件系统被挂载、重新生成或新的设备变为可用时,将进行此调用。

6.7.3.1.5. mpo_create_devfs_directory
void mpo_create_devfs_directory(char *dirname, int dirnamelen,
    struct devfs_dirent *devfs_dirent, struct label *label);
参数描述锁定

dirname

正在创建的目录的名称

namelen

字符串 dirname 的长度

devfs_dirent

正在为其创建的目录的 Devfs 目录项。

为为传递的目录创建的 devfs_dirent 填写标签。当设备文件系统被挂载、重新生成或需要特定目录层次结构的新设备变为可用时,将进行此调用。

void mpo_create_devfs_symlink(struct ucred *cred, struct mount *mp,
    struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de,
    struct label *delabel);
参数描述锁定

cred

主题凭据

mp

Devfs 挂载点

dd

链接目标

ddlabel

dd 关联的标签

de

符号链接项

delabel

de 关联的标签

为新创建的 devfs(5) 符号链接项填充标签 (delabel)。

6.7.3.1.7. mpo_create_vnode_extattr
int mpo_create_vnode_extattr(struct ucred *cred, struct mount *mp,
    struct label *fslabel, struct vnode *dvp, struct label *dlabel,
    struct vnode *vp, struct label *vlabel, struct componentname *cnp);
参数描述锁定

cred

主题凭据

mount

文件系统挂载点

标签

文件系统标签

dvp

父目录 vnode

dlabel

dvp 关联的标签

vp

新创建的 vnode

vlabel

vp 关联的策略标签

cnp

vp 的组件名称

vp 的标签写入到相应的扩展属性。如果写入成功,则使用该标签填充 vlabel,并返回 0。否则,返回适当的错误。

6.7.3.1.8. mpo_create_mount
void mpo_create_mount(struct ucred *cred, struct mount *mp, struct label *mnt,
    struct label *fslabel);
参数描述锁定

cred

主题凭据

mp

对象;正在挂载的文件系统

mntlabel

要填充的 mp 的策略标签

fslabel

mp 挂载的文件系统的策略标签。

使用传递的主题凭据填写正在创建的挂载点的标签。当新的文件系统被挂载时,将进行此调用。

6.7.3.1.9. mpo_create_root_mount
void mpo_create_root_mount(struct ucred *cred, struct mount *mp,
    struct label *mntlabel, struct label *fslabel);
参数描述锁定

参见 mpo_create_mount.

使用传递的主题凭据填写正在创建的挂载点的标签。当根文件系统被挂载后,将在 mpo_create_mount; 之后进行此调用。

6.7.3.1.10. mpo_relabel_vnode
void mpo_relabel_vnode(struct ucred *cred, struct vnode *vp,
    struct label *vnodelabel, struct label *newlabel);
参数描述锁定

cred

主题凭据

vp

要重新标记的 vnode

vnodelabel

vp 的现有策略标签

newlabel

要替换 vnodelabel 的新标签(可能是部分标签)

使用传递的更新 vnode 标签和传递的主题凭据更新传递的 vnode 上的标签。

6.7.3.1.11. mpo_setlabel_vnode_extattr
int mpo_setlabel_vnode_extattr(struct ucred *cred, struct vnode *vp,
    struct label *vlabel, struct label *intlabel);
参数描述锁定

cred

主题凭据

vp

正在为其写入标签的 vnode

vlabel

vp 关联的策略标签

intlabel

要写出的标签

将来自 intlabel 的策略写入到扩展属性。这是从 vop_stdcreatevnode_ea 调用的。

6.7.3.1.12. mpo_update_devfsdirent
void mpo_update_devfsdirent(struct devfs_dirent *devfs_dirent,
    struct label *direntlabel, struct vnode *vp, struct label *vnodelabel);
参数描述锁定

devfs_dirent

对象;devfs 目录项

direntlabel

要更新的 devfs_dirent 的策略标签。

vp

父 vnode

已锁定

vnodelabel

vp 的策略标签

从传递的 devfs vnode 标签更新 devfs_dirent 标签。当 devfs vnode 成功重新标记以提交标签更改,以便即使 vnode 被回收也能持续存在时,将进行此调用。当在 devfs 中创建符号链接时,它也会在调用 mac_vnode_create_from_vnode 初始化 vnode 标签之后进行调用。

6.7.3.2. IPC 对象标记事件操作

6.7.3.2.1. mpo_create_mbuf_from_socket
void mpo_create_mbuf_from_socket(struct socket *so, struct label *socketlabel,
    struct mbuf *m, struct label *mbuflabel);
参数描述锁定

socket

套接字

套接字锁定 WIP

socketlabel

socket 关联的策略标签

m

对象;mbuf

mbuflabel

要填充的 m 的策略标签

从传递的套接字标签设置新创建的 mbuf 标头的标签。当套接字生成新的数据报或消息并将它们存储在传递的 mbuf 中时,会进行此调用。

6.7.3.2.2. mpo_create_pipe
void mpo_create_pipe(struct ucred *cred, struct pipe *pipe,
    struct label *pipelabel);
参数描述锁定

cred

主题凭据

pipe

管道

pipelabel

pipe 关联的策略标签

使用传递的主题凭据设置新创建的管道的标签。当新的管道被创建时,会进行此调用。

6.7.3.2.3. mpo_create_socket
void mpo_create_socket(struct ucred *cred, struct socket *so,
    struct label *socketlabel);
参数描述锁定

cred

主题凭据

不可变

so

对象;要标记的套接字

socketlabel

要填充的 so 的标签

使用传递的主题凭据设置新创建的套接字的标签。当套接字被创建时,会进行此调用。

6.7.3.2.4. mpo_create_socket_from_socket
void mpo_create_socket_from_socket(struct socket *oldsocket,
    struct label *oldsocketlabel, struct socket *newsocket,
    struct label *newsocketlabel);
参数描述锁定

oldsocket

监听套接字

oldsocketlabel

oldsocket 关联的策略标签

newsocket

新套接字

newsocketlabel

newsocketlabel 关联的策略标签

根据 listen(2) 套接字 oldsocket 标记新 accept(2) 的套接字 newsocket

6.7.3.2.5. mpo_relabel_pipe
void mpo_relabel_pipe(struct ucred *cred, struct pipe *pipe,
    struct label *oldlabel, struct label *newlabel);
参数描述锁定

cred

主题凭据

pipe

管道

oldlabel

pipe 关联的当前策略标签

newlabel

要应用于 pipe 的策略标签更新

将新的标签 newlabel 应用于 pipe

6.7.3.2.6. mpo_relabel_socket
void mpo_relabel_socket(struct ucred *cred, struct socket *so,
    struct label *oldlabel, struct label *newlabel);
参数描述锁定

cred

主题凭据

不可变

so

对象;套接字

oldlabel

so 的当前标签

newlabel

so 的标签更新

使用传递的套接字标签更新更新套接字上的标签。

6.7.3.2.7. mpo_set_socket_peer_from_mbuf
void mpo_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct label *mbuflabel,
    struct label *oldlabel, struct label *newlabel);
参数描述锁定

mbuf

通过套接字接收的第一个数据报

mbuflabel

mbuf 的标签

oldlabel

套接字的当前标签

newlabel

要填充的套接字的策略标签

从传递的 mbuf 标签设置流套接字上的对等标签。当流套接字接收第一个数据报时,会进行此调用,Unix 域套接字除外。

6.7.3.2.8. mpo_set_socket_peer_from_socket
void mpo_set_socket_peer_from_socket(struct socket *oldsocket,
    struct label *oldsocketlabel, struct socket *newsocket,
    struct label *newsocketpeerlabel);
参数描述锁定

oldsocket

本地套接字

oldsocketlabel

oldsocket 的策略标签

newsocket

对等套接字

newsocketpeerlabel

要填充的 newsocket 的策略标签

从传递的远程套接字端点设置流 UNIX 域套接字上的对等标签。此调用将在套接字对连接时进行,并将对两个端点都进行。

6.7.3.3. 网络对象标记事件操作

6.7.3.3.1. mpo_create_bpfdesc
void mpo_create_bpfdesc(struct ucred *cred, struct bpf_d *bpf_d,
    struct label *bpflabel);
参数描述锁定

cred

主题凭据

不可变

bpf_d

对象;bpf 描述符

bpf

要为 bpf_d 填充的策略标签

从传递的主题凭据设置新创建的 BPF 描述符上的标签。当 BPF 设备节点被具有传递的主题凭据的进程打开时,此调用将被执行。

6.7.3.3.2. mpo_create_ifnet
void mpo_create_ifnet(struct ifnet *ifnet, struct label *ifnetlabel);
参数描述锁定

ifnet

网络接口

ifnetlabel

要为 ifnet 填充的策略标签

设置新创建的接口上的标签。当新的物理接口可用时,或当伪接口在启动期间或作为用户操作的结果被实例化时,此调用可能会被执行。

6.7.3.3.3. mpo_create_ipq
void mpo_create_ipq(struct mbuf *fragment, struct label *fragmentlabel,
    struct ipq *ipq, struct label *ipqlabel);
参数描述锁定

fragment

第一个接收到的 IP 碎片

fragmentlabel

fragment 的策略标签

ipq

要标记的 IP 重组队列

ipqlabel

要为 ipq 填充的策略标签

从第一个接收到的碎片的 mbuf 标头设置新创建的 IP 碎片重组队列上的标签。

6.7.3.3.4. mpo_create_datagram_from_ipq
void mpo_create_create_datagram_from_ipq(struct ipq *ipq,
    struct label *ipqlabel, struct mbuf *datagram, struct label *datagramlabel);
参数描述锁定

ipq

IP 重组队列

ipqlabel

ipq 的策略标签

datagram

要标记的数据报

datagramlabel

要为 datagramlabel 填充的策略标签

从生成它的 IP 碎片重组队列设置新组装的 IP 数据报上的标签。

6.7.3.3.5. mpo_create_fragment
void mpo_create_fragment(struct mbuf *datagram, struct label *datagramlabel,
    struct mbuf *fragment, struct label *fragmentlabel);
参数描述锁定

datagram

数据报

datagramlabel

datagram 的策略标签

fragment

要标记的碎片

fragmentlabel

要为 datagram 填充的策略标签

从生成它的数据报的 mbuf 标头的标签设置新创建的 IP 碎片的 mbuf 标头的标签。

6.7.3.3.6. mpo_create_mbuf_from_mbuf
void mpo_create_mbuf_from_mbuf(struct mbuf *oldmbuf, struct label *oldmbuflabel,
    struct mbuf *newmbuf, struct label *newmbuflabel);
参数描述锁定

oldmbuf

现有(源)mbuf

oldmbuflabel

oldmbuf 的策略标签

newmbuf

要标记的新 mbuf

newmbuflabel

要为 newmbuf 填充的策略标签

从现有数据报的 mbuf 标头设置新创建的数据报的 mbuf 标头的标签。此调用可能在多种情况下执行,包括当 mbuf 重新分配以进行对齐时。

6.7.3.3.7. mpo_create_mbuf_linklayer
void mpo_create_mbuf_linklayer(struct ifnet *ifnet, struct label *ifnetlabel,
    struct mbuf *mbuf, struct label *mbuflabel);
参数描述锁定

ifnet

网络接口

ifnetlabel

ifnet 的策略标签

mbuf

新数据报的 mbuf 标头

mbuflabel

要为 mbuf 填充的策略标签

为传递的接口设置新创建的数据报的 mbuf 标头的标签,该数据报是为了链接层响应而生成的。此调用可能在多种情况下执行,包括在 IPv4 和 IPv6 堆栈中对 ARP 或 ND6 响应执行此调用。

6.7.3.3.8. mpo_create_mbuf_from_bpfdesc
void mpo_create_mbuf_from_bpfdesc(struct bpf_d *bpf_d, struct label *bpflabel,
    struct mbuf *mbuf, struct label *mbuflabel);
参数描述锁定

bpf_d

BPF 描述符

bpflabel

bpflabel 的策略标签

mbuf

要标记的新 mbuf

mbuflabel

要为 mbuf 填充的策略标签

设置使用传递的 BPF 描述符生成的新创建的数据报的 mbuf 标头的标签。当对与传递的 BPF 描述符关联的 BPF 设备执行写入操作时,此调用将被执行。

6.7.3.3.9. mpo_create_mbuf_from_ifnet
void mpo_create_mbuf_from_ifnet(struct ifnet *ifnet, struct label *ifnetlabel,
    struct mbuf *mbuf, struct label *mbuflabel);
参数描述锁定

ifnet

网络接口

ifnetlabel

ifnetlabel 的策略标签

mbuf

新数据报的 mbuf 标头

mbuflabel

要为 mbuf 填充的策略标签

设置从传递的网络接口生成的新创建的数据报的 mbuf 标头的标签。

6.7.3.3.10. mpo_create_mbuf_multicast_encap
void mpo_create_mbuf_multicast_encap(struct mbuf *oldmbuf,
    struct label *oldmbuflabel, struct ifnet *ifnet, struct label *ifnetlabel,
    struct mbuf *newmbuf, struct label *newmbuflabel);
参数描述锁定

oldmbuf

现有数据报的 mbuf 标头

oldmbuflabel

oldmbuf 的策略标签

ifnet

网络接口

ifnetlabel

ifnet 的策略标签

newmbuf

要为新数据报标记的 mbuf 标头

newmbuflabel

要为 newmbuf 填充的策略标签

当通过传递的多播封装接口处理现有传递的数据报时,设置新创建的数据报的 mbuf 标头的标签。当要使用虚拟接口传递 mbuf 时,此调用将被执行。

6.7.3.3.11. mpo_create_mbuf_netlayer
void mpo_create_mbuf_netlayer(struct mbuf *oldmbuf, struct label *oldmbuflabel,
    struct mbuf *newmbuf, struct label *newmbuflabel);
参数描述锁定

oldmbuf

接收到的数据报

oldmbuflabel

oldmbuf 的策略标签

newmbuf

新创建的数据报

newmbuflabel

newmbuf 的策略标签

设置作为对现有接收的数据报 (oldmbuf) 的响应由 IP 堆栈生成的新创建的数据报的 mbuf 标头的标签。此调用可能在多种情况下执行,包括响应 ICMP 请求数据报时执行此调用。

6.7.3.3.12. mpo_fragment_match
int mpo_fragment_match(struct mbuf *fragment, struct label *fragmentlabel,
    struct ipq *ipq, struct label *ipqlabel);
参数描述锁定

fragment

IP 数据报碎片

fragmentlabel

fragment 的策略标签

ipq

IP 碎片重组队列

ipqlabel

ipq 的策略标签

确定包含 IP 数据报 (fragment) 碎片的 mbuf 标头是否与传递的 IP 碎片重组队列 (ipq) 的标签匹配。对于成功匹配返回 (1),对于不匹配返回 (0)。当 IP 堆栈尝试为新接收的碎片找到现有的碎片重组队列时,此调用将被执行;如果失败,可能会为碎片实例化新的碎片重组队列。策略可以使用此入口点阻止其他匹配的 IP 碎片的重组,如果策略不允许它们根据标签或其他信息进行重组。

6.7.3.3.13. mpo_relabel_ifnet
void mpo_relabel_ifnet(struct ucred *cred, struct ifnet *ifnet,
    struct label *ifnetlabel, struct label *newlabel);
参数描述锁定

cred

主题凭据

ifnet

对象;网络接口

ifnetlabel

ifnet 的策略标签

newlabel

要应用于 ifnet 的标签更新

基于传递的更新标签 newlabel 和传递的主题凭据 cred 更新网络接口 ifnet 的标签。

6.7.3.3.14. mpo_update_ipq
void mpo_update_ipq(struct mbuf *fragment, struct label *fragmentlabel,
    struct ipq *ipq, struct label *ipqlabel);
参数描述锁定

mbuf

IP 碎片

mbuflabel

mbuf 的策略标签

ipq

IP 碎片重组队列

ipqlabel

要更新的 ipq 的策略标签

基于传递的 IP 碎片 mbuf 标头 (mbuf) 的接受更新 IP 碎片重组队列 (ipq) 上的标签。

6.7.3.4. 进程标记事件操作

6.7.3.4.1. mpo_create_cred
void mpo_create_cred(struct ucred *parent_cred, struct ucred *child_cred);
参数描述锁定

parent_cred

父主题凭据

child_cred

子主题凭据

从传递的主题凭据设置新创建的主题凭据的标签。当对新创建的 struct ucred 调用 crcopy(9) 时,此调用将被执行。此调用不应与进程分叉或创建事件混淆。

6.7.3.4.2. mpo_execve_transition
void mpo_execve_transition(struct ucred *old, struct ucred *new,
    struct vnode *vp, struct label *vnodelabel);
参数描述锁定

old

现有主题凭据

不可变

new

要标记的新主题凭据

vp

要执行的文件

已锁定

vnodelabel

vp 的策略标签

基于由执行传递的 vnode (vp) 引起的标签转换,从传递的现有主题凭据 (old) 更新新创建的主题凭据 (new) 的标签。当进程执行传递的 vnode 并且其中一个策略从 mpo_execve_will_transition 入口点返回成功时,此调用会发生。策略可以选择简单地通过调用 mpo_create_cred 并传递两个主题凭据来实现此调用,以便不实现转换事件。即使它们没有实现 mpo_execve_will_transition,策略也不应该在实现 mpo_create_cred 时不实现此入口点。

6.7.3.4.3. mpo_execve_will_transition
int mpo_execve_will_transition(struct ucred *old, struct vnode *vp,
    struct label *vnodelabel);
参数描述锁定

old

execve(2) 之前的主题凭据

不可变

vp

要执行的文件

vnodelabel

vp 的策略标签

确定策略是否希望在传递的主题凭据执行传递的 vnode 后执行转换事件。如果需要转换,则返回 1,否则返回 0。即使策略返回 0,它也应该在 mpo_execve_transition 的意外调用时表现正确,因为该调用可能是由于另一个策略请求转换而发生的。

6.7.3.4.4. mpo_create_proc0
void mpo_create_proc0(struct ucred *cred);
参数描述锁定

cred

要填充的主题凭据

创建进程 0 的主题凭据,它是所有内核进程的父进程。

6.7.3.4.5. mpo_create_proc1
void mpo_create_proc1(struct ucred *cred);
参数描述锁定

cred

要填充的主题凭据

创建进程 1 的主题凭据,它是所有用户进程的父进程。

6.7.3.4.6. mpo_relabel_cred
void mpo_relabel_cred(struct ucred *cred, struct label *newlabel);
参数描述锁定

cred

主题凭据

newlabel

要应用于 cred 的标签更新

从传递的更新标签更新主题凭据上的标签。

6.7.4. 访问控制检查

访问控制入口点允许策略模块影响内核做出的访问控制决策。通常,尽管并非总是如此,访问控制入口点的参数将包括一个或多个授权凭据,以及有关操作中涉及的任何其他对象的任何信息(可能包括标签)。访问控制入口点可以返回 0 以允许操作,或者返回 errno(2) 错误值。跨不同已注册的策略模块调用入口点的结果将按如下方式组合:如果所有模块都允许操作成功,则将返回成功。如果一个或多个模块返回失败,则将返回失败。如果多个模块返回失败,则将使用以下优先级选择要返回给用户的 errno 值,该优先级由 kern_mac.c 中的 error_select() 函数实现。

最高优先级

EDEADLK

EINVAL

ESRCH

EACCES

最低优先级

EPERM

如果所有模块返回的所有错误值都没有列在优先级图表中,则将从该集中随机选择一个值进行返回。通常,这些规则按以下顺序提供对错误的优先级:内核错误、无效参数、对象不存在、访问未被允许、其他。

6.7.4.1. mpo_check_bpfdesc_receive

int mpo_check_bpfdesc_receive(struct bpf_d *bpf_d, struct label *bpflabel,
    struct ifnet *ifnet, struct label *ifnetlabel);
参数描述锁定

bpf_d

主题; BPF 描述符

bpflabel

策略标签用于 bpf_d

ifnet

对象; 网络接口

ifnetlabel

ifnet 的策略标签

确定 MAC 框架是否应该允许从传递的接口发送的数据报传送到传递的 BPF 描述符的缓冲区。成功返回 (0),失败返回 errno 值。建议的失败情况:标签不匹配返回 EACCES,权限不足返回 EPERM。

6.7.4.2. mpo_check_kenv_dump

int mpo_check_kenv_dump(struct ucred *cred);
参数描述锁定

cred

主题凭据

确定主体是否应该被允许检索内核环境(参见 kenv(2))。

6.7.4.3. mpo_check_kenv_get

int mpo_check_kenv_get(struct ucred *cred, char *name);
参数描述锁定

cred

主题凭据

名称

内核环境变量名称

确定主体是否应该被允许检索指定内核环境变量的值。

6.7.4.4. mpo_check_kenv_set

int mpo_check_kenv_set(struct ucred *cred, char *name);
参数描述锁定

cred

主题凭据

名称

内核环境变量名称

确定主体是否应该被允许设置指定的内核环境变量。

6.7.4.5. mpo_check_kenv_unset

int mpo_check_kenv_unset(struct ucred *cred, char *name);
参数描述锁定

cred

主题凭据

名称

内核环境变量名称

确定主体是否应该被允许取消设置指定的内核环境变量。

6.7.4.6. mpo_check_kld_load

int mpo_check_kld_load(struct ucred *cred, struct vnode *vp,
    struct label *vlabel);
参数描述锁定

cred

主题凭据

vp

内核模块 vnode

vlabel

vp 关联的标签

确定主体是否应该被允许加载指定的模块文件。

6.7.4.7. mpo_check_kld_stat

int mpo_check_kld_stat(struct ucred *cred);
参数描述锁定

cred

主题凭据

确定主体是否应该被允许检索加载的内核模块文件列表和关联的统计信息。

6.7.4.8. mpo_check_kld_unload

int mpo_check_kld_unload(struct ucred *cred);
参数描述锁定

cred

主题凭据

确定主体是否应该被允许卸载内核模块。

6.7.4.9. mpo_check_pipe_ioctl

int mpo_check_pipe_ioctl(struct ucred *cred, struct pipe *pipe,
    struct label *pipelabel, unsigned long cmd, void *data);
参数描述锁定

cred

主题凭据

pipe

管道

pipelabel

pipe 关联的策略标签

cmd

ioctl(2) 命令

数据

ioctl(2) 数据

确定主体是否应该被允许执行指定的 ioctl(2) 调用。

6.7.4.10. mpo_check_pipe_poll

int mpo_check_pipe_poll(struct ucred *cred, struct pipe *pipe,
    struct label *pipelabel);
参数描述锁定

cred

主题凭据

pipe

管道

pipelabel

pipe 关联的策略标签

确定主体是否应该被允许轮询 pipe

6.7.4.11. mpo_check_pipe_read

int mpo_check_pipe_read(struct ucred *cred, struct pipe *pipe,
    struct label *pipelabel);
参数描述锁定

cred

主题凭据

pipe

管道

pipelabel

pipe 关联的策略标签

确定主体是否应该被允许读取 pipe

6.7.4.12. mpo_check_pipe_relabel

int mpo_check_pipe_relabel(struct ucred *cred, struct pipe *pipe,
    struct label *pipelabel, struct label *newlabel);
参数描述锁定

cred

主题凭据

pipe

管道

pipelabel

pipe 关联的当前策略标签

newlabel

标签更新到 pipelabel

确定主体是否应该被允许重新标记 pipe

6.7.4.13. mpo_check_pipe_stat

int mpo_check_pipe_stat(struct ucred *cred, struct pipe *pipe,
    struct label *pipelabel);
参数描述锁定

cred

主题凭据

pipe

管道

pipelabel

pipe 关联的策略标签

确定主体是否应该被允许检索与 pipe 相关的统计信息。

6.7.4.14. mpo_check_pipe_write

int mpo_check_pipe_write(struct ucred *cred, struct pipe *pipe,
    struct label *pipelabel);
参数描述锁定

cred

主题凭据

pipe

管道

pipelabel

pipe 关联的策略标签

确定主体是否应该被允许写入 pipe

6.7.4.15. mpo_check_socket_bind

int mpo_check_socket_bind(struct ucred *cred, struct socket *socket,
    struct label *socketlabel, struct sockaddr *sockaddr);
参数描述锁定

cred

主题凭据

socket

要绑定的套接字

socketlabel

socket 关联的策略标签

sockaddr

socket 的地址

6.7.4.16. mpo_check_socket_connect

int mpo_check_socket_connect(struct ucred *cred, struct socket *socket,
    struct label *socketlabel, struct sockaddr *sockaddr);
参数描述锁定

cred

主题凭据

socket

要连接的套接字

socketlabel

socket 关联的策略标签

sockaddr

socket 的地址

确定主体凭据 (cred) 是否可以将传递的套接字 (socket) 连接到传递的套接字地址 (sockaddr)。成功返回 0,失败返回 errno 值。建议的失败情况:标签不匹配返回 EACCES,权限不足返回 EPERM。

6.7.4.17. mpo_check_socket_receive

int mpo_check_socket_receive(struct ucred *cred, struct socket *so,
    struct label *socketlabel);
参数描述锁定

cred

主题凭据

so

套接字

socketlabel

so 关联的策略标签

确定主体是否应该被允许从套接字 so 接收信息。

6.7.4.18. mpo_check_socket_send

int mpo_check_socket_send(struct ucred *cred, struct socket *so,
    struct label *socketlabel);
参数描述锁定

cred

主题凭据

so

套接字

socketlabel

so 关联的策略标签

确定主体是否应该被允许通过套接字 so 发送信息。

6.7.4.19. mpo_check_cred_visible

int mpo_check_cred_visible(struct ucred *u1, struct ucred *u2);
参数描述锁定

u1

主题凭据

u2

对象凭据

确定主体凭据 u1 是否可以“看到”其他具有传递的主体凭据 u2 的主体。成功返回 0,失败返回 errno 值。建议的失败情况:标签不匹配返回 EACCES,权限不足返回 EPERM,或隐藏可见性返回 ESRCH。此调用可能在许多情况下被调用,包括 ps 使用的进程间状态 sysctl,以及在 procfs 查找中。

6.7.4.20. mpo_check_socket_visible

int mpo_check_socket_visible(struct ucred *cred, struct socket *socket,
    struct label *socketlabel);
参数描述锁定

cred

主题凭据

socket

对象;套接字

socketlabel

socket 关联的策略标签

6.7.4.21. mpo_check_ifnet_relabel

int mpo_check_ifnet_relabel(struct ucred *cred, struct ifnet *ifnet,
    struct label *ifnetlabel, struct label *newlabel);
参数描述锁定

cred

主题凭据

ifnet

对象; 网络接口

ifnetlabel

ifnet 的现有策略标签

newlabel

策略标签更新,稍后将应用于 ifnet

确定主体凭据是否可以将传递的网络接口重新标记为传递的标签更新。

6.7.4.22. mpo_check_socket_relabel

int mpo_check_socket_relabel(struct ucred *cred, struct socket *socket,
    struct label *socketlabel, struct label *newlabel);
参数描述锁定

cred

主题凭据

socket

对象;套接字

socketlabel

socket 的现有策略标签

newlabel

标签更新,稍后将应用于 socketlabel

确定主体凭据是否可以将传递的套接字重新标记为传递的标签更新。

6.7.4.23. mpo_check_cred_relabel

int mpo_check_cred_relabel(struct ucred *cred, struct label *newlabel);
参数描述锁定

cred

主题凭据

newlabel

标签更新,稍后将应用于 cred

确定主体凭据是否可以将自身重新标记为传递的标签更新。

6.7.4.24. mpo_check_vnode_relabel

int mpo_check_vnode_relabel(struct ucred *cred, struct vnode *vp,
    struct label *vnodelabel, struct label *newlabel);
参数描述锁定

cred

主题凭据

不可变

vp

对象; vnode

已锁定

vnodelabel

vp 的现有策略标签

newlabel

策略标签更新,稍后将应用于 vp

确定主体凭据是否可以将传递的 vnode 重新标记为传递的标签更新。

6.7.4.25. mpo_check_mount_stat

int mpo_check_mount_stat(struct ucred *cred, struct mount *mp,
    struct label *mountlabel);
参数描述锁定

cred

主题凭据

mp

对象; 文件系统挂载

mountlabel

mp 的策略标签

确定主体凭据是否可以查看在文件系统上执行的 statfs 的结果。成功返回 0,失败返回 errno 值。建议的失败情况:标签不匹配返回 EACCES,权限不足返回 EPERM。此调用可能在许多情况下被调用,包括在调用 statfs(2) 和相关调用时,以及确定要从文件系统列表中排除哪些文件系统,例如当调用 getfsstat(2) 时。

6.7.4.26. mpo_check_proc_debug

int mpo_check_proc_debug(struct ucred *cred, struct proc *proc);
参数描述锁定

cred

主题凭据

不可变

proc

对象; 进程

确定主体凭据是否可以调试传递的进程。成功返回 0,失败返回 errno 值。建议的失败情况:标签不匹配返回 EACCES,权限不足返回 EPERM,或隐藏目标可见性返回 ESRCH。此调用可能在许多情况下被调用,包括使用 ptrace(2)ktrace(2) API,以及某些类型的 procfs 操作。

6.7.4.27. mpo_check_vnode_access

int mpo_check_vnode_access(struct ucred *cred, struct vnode *vp,
    struct label *label, int flags);
参数描述锁定

cred

主题凭据

vp

对象; vnode

标签

vp 的策略标签

标志

access(2) 标志

确定主体凭据在使用传递的访问标志对传递的 vnode 执行 access(2) 和相关调用时应如何返回。这通常应该使用与 mpo_check_vnode_open 中使用的相同语义来实现。成功返回 0,失败返回 errno 值。建议的失败情况:标签不匹配返回 EACCES,权限不足返回 EPERM。

6.7.4.28. mpo_check_vnode_chdir

int mpo_check_vnode_chdir(struct ucred *cred, struct vnode *dvp,
    struct label *dlabel);
参数描述锁定

cred

主题凭据

dvp

对象; 要 chdir(2) 到其中的 vnode

dlabel

dvp 的策略标签

确定主体凭据是否可以将进程工作目录更改为传递的 vnode。成功返回 0,失败返回 errno 值。建议的失败情况:标签不匹配返回 EACCES,权限不足返回 EPERM。

6.7.4.29. mpo_check_vnode_chroot

int mpo_check_vnode_chroot(struct ucred *cred, struct vnode *dvp,
    struct label *dlabel);
参数描述锁定

cred

主题凭据

dvp

目录 vnode

dlabel

dvp 关联的策略标签

确定主体是否应该被允许 chroot(2) 到指定的目录 (dvp)。

6.7.4.30. mpo_check_vnode_create

int mpo_check_vnode_create(struct ucred *cred, struct vnode *dvp,
    struct label *dlabel, struct componentname *cnp, struct vattr *vap);
参数描述锁定

cred

主题凭据

dvp

对象; vnode

dlabel

dvp 的策略标签

cnp

dvp 的组件名称

vap

vap 的 vnode 属性

确定主体凭据是否可以创建具有传递的父目录、传递的名称信息和传递的属性信息的 vnode。成功返回 0,失败返回 errno 值。建议的失败情况:标签不匹配返回 EACCES,权限不足返回 EPERM。此调用可能在许多情况下被调用,包括作为对 open(2) 的调用(使用 O_CREAT)、mkfifo(2) 等的结果。

6.7.4.31. mpo_check_vnode_delete

int mpo_check_vnode_delete(struct ucred *cred, struct vnode *dvp,
    struct label *dlabel, struct vnode *vp, void *label,
    struct componentname *cnp);
参数描述锁定

cred

主题凭据

dvp

父目录 vnode

dlabel

dvp 的策略标签

vp

对象; 要删除的 vnode

标签

vp 的策略标签

cnp

vp 的组件名称

确定主体凭据是否可以从传递的父目录和传递的名称信息中删除 vnode。成功返回 0,失败返回 errno 值。建议的失败情况:标签不匹配返回 EACCES,权限不足返回 EPERM。此调用可能在许多情况下被调用,包括作为对 unlink(2)rmdir(2) 的调用的结果。实现此入口点的策略还应该实现 mpo_check_rename_to 以授权作为重命名目标结果的对象删除。

6.7.4.32. mpo_check_vnode_deleteacl

int mpo_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp,
    struct label *label, acl_type_t type);
参数描述锁定

cred

主题凭据

不可变

vp

对象; vnode

已锁定

标签

vp 的策略标签

类型

ACL 类型

确定主体凭据是否可以从传递的 vnode 中删除传递类型的 ACL。成功返回 0,失败返回 errno 值。建议的失败情况:标签不匹配返回 EACCES,权限不足返回 EPERM。

6.7.4.33. mpo_check_vnode_exec

int mpo_check_vnode_exec(struct ucred *cred, struct vnode *vp,
    struct label *label);
参数描述锁定

cred

主题凭据

vp

对象; 要执行的 vnode

标签

vp 的策略标签

确定主体凭据是否可以执行传递的 vnode。执行权限的确定与任何转换事件的决定分开进行。成功返回 0,失败返回 errno 值。建议的失败情况:标签不匹配返回 EACCES,权限不足返回 EPERM。

6.7.4.34. mpo_check_vnode_getacl

int mpo_check_vnode_getacl(struct ucred *cred, struct vnode *vp,
    struct label *label, acl_type_t type);
参数描述锁定

cred

主题凭据

vp

对象; vnode

标签

vp 的策略标签

类型

ACL 类型

确定主体凭据是否可以从传递的 vnode 中检索传递类型的 ACL。成功返回 0,失败返回 errno 值。建议的失败情况:标签不匹配返回 EACCES,权限不足返回 EPERM。

6.7.4.35. mpo_check_vnode_getextattr

int mpo_check_vnode_getextattr(struct ucred *cred, struct vnode *vp,
    struct label *label, int attrnamespace, const char *name, struct uio *uio);
参数描述锁定

cred

主题凭据

vp

对象; vnode

标签

vp 的策略标签

attrnamespace

扩展属性命名空间

名称

扩展属性名称

uio

I/O 结构指针;参见 uio(9)

确定主体凭据是否可以从传递的 vnode 中检索具有传递的命名空间和名称的扩展属性。使用扩展属性实现标记的策略可能对这些扩展属性的操作感兴趣。成功返回 0,失败返回 errno 值。建议的失败情况:标签不匹配返回 EACCES,权限不足返回 EPERM。

int mpo_check_vnode_link(struct ucred *cred, struct vnode *dvp,
    struct label *dlabel, struct vnode *vp, struct label *label,
    struct componentname *cnp);
参数描述锁定

cred

主题凭据

dvp

目录 vnode

dlabel

dvp 关联的策略标签

vp

链接目标 vnode

标签

vp 关联的策略标签

cnp

正在创建的链接的组件名称

确定主体是否应该被允许创建到 vnode vp 的链接,其名称由 cnp 指定。

6.7.4.37. mpo_check_vnode_mmap

int mpo_check_vnode_mmap(struct ucred *cred, struct vnode *vp,
    struct label *label, int prot);
参数描述锁定

cred

主题凭据

vp

要映射的 vnode

标签

vp 关联的策略标签

prot

mmap 保护(参见 mmap(2)

确定主体是否应该被允许将vnode vpprot中指定的保护映射。

6.7.4.38. mpo_check_vnode_mmap_downgrade

void mpo_check_vnode_mmap_downgrade(struct ucred *cred, struct vnode *vp,
    struct label *label, int *prot);
参数描述锁定

cred

参见 mpo_check_vnode_mmap.

vp

标签

prot

要降级的mmap保护

根据主体和对象标签降低mmap保护。

6.7.4.39. mpo_check_vnode_mprotect

int mpo_check_vnode_mprotect(struct ucred *cred, struct vnode *vp,
    struct label *label, int prot);
参数描述锁定

cred

主题凭据

vp

映射的vnode

prot

内存保护

确定主体是否应该被允许在从vnode vp映射的内存上设置指定的内存保护。

6.7.4.40. mpo_check_vnode_poll

int mpo_check_vnode_poll(struct ucred *active_cred, struct ucred *file_cred,
    struct vnode *vp, struct label *label);
参数描述锁定

active_cred

主题凭据

file_cred

与struct file关联的凭证

vp

轮询的vnode

标签

vp 关联的策略标签

确定主体是否应该被允许轮询vnode vp

6.7.4.41. mpo_check_vnode_rename_from

int mpo_vnode_rename_from(struct ucred *cred, struct vnode *dvp,
    struct label *dlabel, struct vnode *vp, struct label *label,
    struct componentname *cnp);
参数描述锁定

cred

主题凭据

dvp

目录 vnode

dlabel

dvp 关联的策略标签

vp

要重命名的vnode

标签

vp 关联的策略标签

cnp

vp 的组件名称

确定主体是否应该被允许将vnode vp重命名为其他名称。

6.7.4.42. mpo_check_vnode_rename_to

int mpo_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp,
    struct label *dlabel, struct vnode *vp, struct label *label, int samedir,
    struct componentname *cnp);
参数描述锁定

cred

主题凭据

dvp

目录 vnode

dlabel

dvp 关联的策略标签

vp

被覆盖的vnode

标签

vp 关联的策略标签

samedir

布尔值;如果源目录和目标目录相同,则为1

cnp

目标组件名称

确定主体是否应该被允许重命名为vnode vp,进入目录dvp,或重命名为cnp所表示的名称。如果不存在要覆盖的文件,vplabel将为NULL。

6.7.4.43. mpo_check_socket_listen

int mpo_check_socket_listen(struct ucred *cred, struct socket *socket,
    struct label *socketlabel);
参数描述锁定

cred

主题凭据

socket

对象;套接字

socketlabel

socket 关联的策略标签

确定主体凭证是否可以监听传递的套接字。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,或权限不足返回EPERM。

6.7.4.44. mpo_check_vnode_lookup

int mpo_check_vnode_lookup(struct ucred *cred, struct vnode *dvp,
    struct label *dlabel, struct componentname *cnp);
参数描述锁定

cred

主题凭据

dvp

对象; vnode

dlabel

dvp 的策略标签

cnp

正在查找的组件名称

确定主体凭证是否可以在传递的目录vnode中针对传递的名称执行查找。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,或权限不足返回EPERM。

6.7.4.45. mpo_check_vnode_open

int mpo_check_vnode_open(struct ucred *cred, struct vnode *vp,
    struct label *label, int acc_mode);
参数描述锁定

cred

主题凭据

vp

对象; vnode

标签

vp 的策略标签

acc_mode

open(2) 访问模式

确定主体凭证是否可以对传递的vnode执行打开操作,并使用传递的访问模式。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,或权限不足返回EPERM。

6.7.4.46. mpo_check_vnode_readdir

int mpo_check_vnode_readdir(struct ucred *cred, struct vnode *dvp,
    struct label *dlabel);
参数描述锁定

cred

主题凭据

dvp

对象;目录vnode

dlabel

dvp 的策略标签

确定主体凭证是否可以对传递的目录vnode执行readdir操作。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,或权限不足返回EPERM。

int mpo_check_vnode_readlink(struct ucred *cred, struct vnode *vp,
    struct label *label);
参数描述锁定

cred

主题凭据

vp

对象; vnode

标签

vp 的策略标签

确定主体凭证是否可以对传递的符号链接vnode执行readlink操作。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,或权限不足返回EPERM。此调用可能在多种情况下进行,包括用户进程的显式readlink调用,或作为进程在名称查找期间进行隐式readlink的结果。

6.7.4.48. mpo_check_vnode_revoke

int mpo_check_vnode_revoke(struct ucred *cred, struct vnode *vp,
    struct label *label);
参数描述锁定

cred

主题凭据

vp

对象; vnode

标签

vp 的策略标签

确定主体凭证是否可以撤销对传递的vnode的访问权限。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,或权限不足返回EPERM。

6.7.4.49. mpo_check_vnode_setacl

int mpo_check_vnode_setacl(struct ucred *cred, struct vnode *vp,
    struct label *label, acl_type_t type, struct acl *acl);
参数描述锁定

cred

主题凭据

vp

对象; vnode

标签

vp 的策略标签

类型

ACL 类型

acl

ACL

确定主体凭证是否可以对传递的vnode设置传递类型的ACL。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,或权限不足返回EPERM。

6.7.4.50. mpo_check_vnode_setextattr

int mpo_check_vnode_setextattr(struct ucred *cred, struct vnode *vp,
    struct label *label, int attrnamespace, const char *name, struct uio *uio);
参数描述锁定

cred

主题凭据

vp

对象; vnode

标签

vp 的策略标签

attrnamespace

扩展属性命名空间

名称

扩展属性名称

uio

I/O 结构指针;参见 uio(9)

确定主体凭证是否可以设置传递的vnode上传递名称和传递命名空间的扩展属性。实现扩展属性支持的安全标签的策略可能想要为这些属性提供额外的保护。此外,策略应避免根据uio中引用的数据做出决定,因为在此检查和实际操作之间存在潜在的竞争条件。如果正在执行删除操作,uio也可能为NULL。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,或权限不足返回EPERM。

6.7.4.51. mpo_check_vnode_setflags

int mpo_check_vnode_setflags(struct ucred *cred, struct vnode *vp,
    struct label *label, u_long flags);
参数描述锁定

cred

主题凭据

vp

对象; vnode

标签

vp 的策略标签

标志

文件标志;参见 chflags(2)

确定主体凭证是否可以对传递的vnode设置传递的标志。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,或权限不足返回EPERM。

6.7.4.52. mpo_check_vnode_setmode

int mpo_check_vnode_setmode(struct ucred *cred, struct vnode *vp,
    struct label *label, mode_t mode);
参数描述锁定

cred

主题凭据

vp

对象; vnode

标签

vp 的策略标签

mode

文件模式;参见 chmod(2)

确定主体凭证是否可以对传递的vnode设置传递的模式。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,或权限不足返回EPERM。

6.7.4.53. mpo_check_vnode_setowner

int mpo_check_vnode_setowner(struct ucred *cred, struct vnode *vp,
    struct label *label, uid_t uid, gid_t gid);
参数描述锁定

cred

主题凭据

vp

对象; vnode

标签

vp 的策略标签

uid

用户ID

gid

组ID

确定主体凭证是否可以将传递的uid和传递的gid设置为传递的vnode上的文件uid和文件gid。这些ID可以设置为(-1)以请求不更新。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,或权限不足返回EPERM。

6.7.4.54. mpo_check_vnode_setutimes

int mpo_check_vnode_setutimes(struct ucred *cred, struct vnode *vp,
    struct label *label, struct timespec atime, struct timespec mtime);
参数描述锁定

cred

主题凭据

vp

对象;vp

标签

vp 的策略标签

atime

访问时间;参见 utimes(2)

mtime

修改时间;参见 utimes(2)

确定主体凭证是否可以对传递的vnode设置传递的访问时间戳。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,或权限不足返回EPERM。

6.7.4.55. mpo_check_proc_sched

int mpo_check_proc_sched(struct ucred *ucred, struct proc *proc);
参数描述锁定

cred

主题凭据

proc

对象; 进程

确定主体凭证是否可以更改传递进程的调度参数。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,权限不足返回EPERM,或限制可见性返回ESRCH。

有关更多信息,请参见 setpriority(2)

6.7.4.56. mpo_check_proc_signal

int mpo_check_proc_signal(struct ucred *cred, struct proc *proc, int signal);
参数描述锁定

cred

主题凭据

proc

对象; 进程

signal

信号;参见 kill(2)

确定主体凭证是否可以向传递的进程传递传递的信号。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,权限不足返回EPERM,或限制可见性返回ESRCH。

6.7.4.57. mpo_check_vnode_stat

int mpo_check_vnode_stat(struct ucred *cred, struct vnode *vp,
    struct label *label);
参数描述锁定

cred

主题凭据

vp

对象; vnode

标签

vp 的策略标签

确定主体凭证是否可以stat传递的vnode。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,或权限不足返回EPERM。

有关更多信息,请参见 stat(2)

6.7.4.58. mpo_check_ifnet_transmit

int mpo_check_ifnet_transmit(struct ucred *cred, struct ifnet *ifnet,
    struct label *ifnetlabel, struct mbuf *mbuf, struct label *mbuflabel);
参数描述锁定

cred

主题凭据

ifnet

网络接口

ifnetlabel

ifnet 的策略标签

mbuf

对象;要发送的mbuf

mbuflabel

mbuf 的策略标签

确定网络接口是否可以传输传递的mbuf。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,或权限不足返回EPERM。

6.7.4.59. mpo_check_socket_deliver

int mpo_check_socket_deliver(struct ucred *cred, struct ifnet *ifnet,
    struct label *ifnetlabel, struct mbuf *mbuf, struct label *mbuflabel);
参数描述锁定

cred

主题凭据

ifnet

网络接口

ifnetlabel

ifnet 的策略标签

mbuf

对象;要传递的mbuf

mbuflabel

mbuf 的策略标签

确定套接字是否可以接收存储在传递的mbuf头部的报文。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,或权限不足返回EPERM。

6.7.4.60. mpo_check_socket_visible

int mpo_check_socket_visible(struct ucred *cred, struct socket *so,
    struct label *socketlabel);
参数描述锁定

cred

主题凭据

不可变

so

对象;套接字

socketlabel

so的策略标签

确定主体凭证cred是否可以使用系统监控功能“看到”传递的套接字(socket),例如由netstat(8)sockstat(1)使用的功能。成功返回0,失败返回errno值。建议失败:标签不匹配返回EACCES,权限不足返回EPERM,或隐藏可见性返回ESRCH。

6.7.4.61. mpo_check_system_acct

int mpo_check_system_acct(struct ucred *ucred, struct vnode *vp,
    struct label *vlabel);
参数描述锁定

ucred

主题凭据

vp

记账文件;acct(5)

vlabel

vp 关联的标签

确定主体是否应该被允许启用记账,这取决于其标签和记账日志文件的标签。

6.7.4.62. mpo_check_system_nfsd

int mpo_check_system_nfsd(struct ucred *cred);
参数描述锁定

cred

主题凭据

确定主体是否应该被允许调用nfssvc(2).

6.7.4.63. mpo_check_system_reboot

int mpo_check_system_reboot(struct ucred *cred, int howto);
参数描述锁定

cred

主题凭据

howto

来自reboot(2)howto参数

确定主体是否应该被允许以指定方式重启系统。

6.7.4.64. mpo_check_system_settime

int mpo_check_system_settime(struct ucred *cred);
参数描述锁定

cred

主题凭据

确定用户是否应该被允许设置系统时钟。

6.7.4.65. mpo_check_system_swapon

int mpo_check_system_swapon(struct ucred *cred, struct vnode *vp,
    struct label *vlabel);
参数描述锁定

cred

主题凭据

vp

交换设备

vlabel

vp 关联的标签

确定主体是否应该被允许添加vp作为交换设备。

6.7.4.66. mpo_check_system_sysctl

int mpo_check_system_sysctl(struct ucred *cred, int *name, u_int *namelen,
    void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen);
参数描述锁定

cred

主题凭据

名称

参见 sysctl(3)

namelen

old

oldlenp

inkernel

布尔值;如果从内核调用则为1

new

参见 sysctl(3)

newlen

确定主体是否应该被允许执行指定的sysctl(3)事务。

6.7.5. 标签管理调用

当用户进程请求修改对象上的标签时,会发生重新标记事件。会发生两阶段更新:首先,将执行访问控制检查以确定更新是否有效且被允许,然后通过单独的入口点执行更新本身。重新标记入口点通常接受对象、对象标签引用以及进程提交的更新标签。重新标记期间的内存分配不受鼓励,因为重新标记调用不允许失败(应在重新标记检查的早期报告失败)。

6.8. 用户空间架构

TrustedBSD MAC 框架包含许多与策略无关的元素,包括用于抽象管理标签的 MAC 库接口、对系统凭证管理和登录库的修改以支持将 MAC 标签分配给用户,以及一组用于监控和修改进程、文件和网络接口上的标签的工具。有关用户架构的更多详细信息将在不久的将来添加到本节中。

6.8.1. 用于策略无关标签管理的 API

TrustedBSD MAC 框架提供了一系列库和系统调用,允许应用程序使用与策略无关的接口来管理对象上的 MAC 标签。这允许应用程序针对各种策略操纵标签,而无需针对特定策略编写。这些接口被通用工具使用,例如 ifconfig(8)ls(1)ps(1),用于查看网络接口、文件和进程上的标签。这些 API 还支持 MAC 管理工具,包括 getfmac(8)getpmac(8)setfmac(8)setfsmac(8)setpmac(8)。MAC API 文档在 mac(3) 中。

应用程序以两种形式处理 MAC 标签:内部形式用于返回和设置进程和对象上的标签(mac_t),以及外部形式,基于 C 字符串,适合存储在配置文件中、显示给用户或从用户输入。每个 MAC 标签包含多个元素,每个元素都包含一个名称和值对。内核中的策略模块绑定到特定名称,并以策略特定方式解释值。在外部字符串形式中,标签用逗号分隔的名称和值对列表表示,这些对用 / 字符分隔。标签可以直接使用提供的 API 转换为文本并从文本转换回来;当从内核检索标签时,必须首先为所需的标签元素集准备内部化的标签存储。通常,这可以通过两种方式之一完成:使用 mac_prepare(3) 和所需的任意标签元素列表,或者使用从 mac.conf(5) 配置文件加载默认元素集的调用变体之一。每个对象的默认值允许应用程序编写者有意义地显示与对象关联的标签,而无需了解系统中存在的策略。

目前,MAC 库不支持直接操作标签元素,除非转换为文本字符串、字符串编辑和转换回内部化标签。如果应用程序编写者需要这些接口,将来可能会添加这些接口。

6.8.2. 标签绑定到用户

标准用户上下文管理接口 setusercontext(3) 已被修改,以从 login.conf(5) 检索与用户类关联的 MAC 标签。然后,这些标签与其他用户上下文一起设置,无论何时指定 LOGIN_SETALL,还是显式指定 LOGIN_SETMAC

预计在 FreeBSD 的未来版本中,MAC 标签数据库将与 login.conf 用户类抽象分离,并保存在单独的数据库中。但是,setusercontext(3) API 应在进行此类更改后保持不变。

6.9. 结论

TrustedBSD MAC 框架允许内核模块以高度集成的形式增强系统安全策略。他们可以基于现有对象属性或基于在 MAC 框架的帮助下维护的标签数据来做到这一点。该框架足够灵活,可以实施各种策略类型,包括 MLS 和 Biba 等信息流安全策略,以及基于现有 BSD 凭据或文件保护的策略。策略作者在实施新的安全服务时,可能希望参考此文档以及现有安全模块。


最后修改时间:2024 年 9 月 20 日,作者:Fernando Apesteguía