mpo_init策略加载事件。当前进程正持有策略链表上的互斥锁,因此是非睡眠的,对其他内核子系统的调用也须慎重。 如果需要在策略初始化阶段进行可能造成睡眠阻塞的存储分配操作,可以将它们放在一个单独的模块 SYSINIT() 过程中集中进行。
mpo_destroy策略加载事件。必须持有策略链表互斥锁,因此需要慎重行事。
mpo_syscall该入口函数提供策略复用的系统调用,这样策略模块不需要为其向用户进程提供的每一个额外服务而注册专用的系统调用。 由应用程序提供的策略注册名字来确定提供其所申请服务的特定策略,所有参数将通过该入口函数传递给被调用的策略。 当实现新服务时,安全模块必须在必要时通过 MAC 框架调用相应的访问控制检查机制。 比方说,假如一个策略实现了某种额外的信号功能,那么它应该调用相关的信号访问控制检查,以接受 MAC 框架中注册的其他策略的检查。
注意: 不同的模块需要并发地手动进行
copyin()拷贝系统调用数据。
mpo_thread_userret使用该入口函数,策略模块能够在线程返回用户空间时(系统调用返回、异常返回等等)进行 MAC 相关的处理工作。 使用动态进程标记的策略需要使用该入口函数,因为在处理系统调用的过程中,并不是在任意时刻都能申请到进程锁的; 进程的标记可能表示传统的认证信息、进程历史记录或者其他数据。为使用该入口函数,对进程信任状所作的修改 可能被存放在 p_label ,该域受一个进程级自旋锁的保护;接下来,设置线程级的TDF_ASTPENDING 标志位和进程级的PS_MACPENDM标志位,表明将调度一个对 userret 入口函数的调用。通过该入口函数, 策略可以在相对简单的同步上下文中创建信任状的替代品。策略编程人员必须清楚,需要保证与调度一个 AST 相关的事件执行次序, 同时所执行的 AST 可能很复杂,而且在处理多线程应用程序时可能被重入。
mpo_init_bpfdesc_label为一个新近实例化的 bpfdesc(BPF 描述子)初始化标记。可以睡眠。
mpo_init_cred_label为一个新近实例化的用户信任状初始化标记。可以睡眠。
mpo_init_devfsdirent_label为一个新近实例化的 devfs 表项初始化标记。可以睡眠。
mpo_init_ifnet_label为一个新近实例化的网络接口初始化标记。可以睡眠。
mpo_init_ipq_label| 参数 | 说明 | 锁定 |
|---|---|---|
label |
将被应用的新标记 | |
flag |
睡眠/不睡眠 malloc(9); 参见下文 |
为一个新近实例化的 IP 分片重组队列初始化标记。其中的flag域可能取M_WAITOK 或M_NOWAIT之一,用来避免在该初始化调用中因为 malloc(9)
而进入睡眠。IP 分片重组队列的分配操作通常是在
对性能有严格要求的环境下进行的,因此实现代码必须小心地避免睡眠和长时间的操作。IP
分片重组队列分配操作失败时上述入口函数将失败返回。
mpo_init_mbuf_label| 参数 | 说明 | 锁定 |
|---|---|---|
flag |
睡眠/不睡眠 malloc(9); 参见下文 | |
label |
将被初始化的策略标记 |
为一个新近实例化的 mbuf 数据包头部(mbuf)初始化标记。 其中的flag的值可能取M_WAITOK和M_NOWAIT之一, 用来避免在该初始化调用中因为 malloc(9)
而进入睡眠。Mbuf 头部的分配操作常常在对性能有严格要求的环境下被频繁执行,
因此实现代码必须小心地避免睡眠和长时间的操作。上述入口函数在 Mbuf
头部分配操作失败时将失败返回。
mpo_init_mount_label为一个新近实例化的 mount 点初始化标记。可以睡眠。
mpo_init_mount_fs_label为一个新近加载的文件系统初始化标记。可以睡眠。
mpo_init_pipe_label为一个刚刚实例化的管道初始化安全标记。可以睡眠。
mpo_init_socket_label| 参数 | 说明 | 锁定 |
|---|---|---|
label |
将被初始化的新标记 | |
flag |
malloc(9) flags |
为一个刚刚实例化的套接字初始化安全标记。其中的 flag
域的值必须被指定为 M_WAITOK和M_NOWAIT之一,以避免在该初始化程中使用可能睡眠的malloc(9) 。
mpo_init_socket_peer_label| 参数 | 说明 | 锁定 |
|---|---|---|
label |
将被初始化的新标记 | |
flag |
malloc(9) flags |
为刚刚实例化的套接字对等体进行标记的初始化。其中的 flag 域的值必须被指定为 M_WAITOK 和
M_NOWAIT 之一,以避免在该初始化程中使用可能睡眠的 malloc(9)。
mpo_init_proc_label为一个刚刚实例化的进程初始化安全标记。可以睡眠。
mpo_init_vnode_label为一个刚刚实例化的 vnode 初始化安全标记。可以睡眠。
mpo_destroy_bpfdesc_label 销毁一个 BPF 描述子上的标记。在该入口函数中,策略应当释放所有在内部分配与 label 相关联的存储空间,以便销毁该标记。
mpo_destroy_cred_label 销毁一个信任状上的标记。在该入口函数中,策略应当释放所有在内部分配的与 label 相关联的存储空间,以便销毁该标记。
mpo_destroy_devfsdirent_label 销毁一个 devfs 表项上的标记。在该入口函数中,策略应当释放所有在内部分配的与 label 相关联的存储空间,以便销毁该标记。
mpo_destroy_ifnet_label 销毁与一个已删除接口相关联的标记。在该入口函数中,策略应当释放所有在内部分配的与
label 相关联的存储空间,以便销毁该标记。
mpo_destroy_ipq_label 销毁与一个 IP 分片队列相关联的标记。在该入口函数中,策略应当释放所有在内部分配的与
label 相关联的存储空间,以便销毁该标记。
mpo_destroy_mbuf_label 销毁与一个 Mbuf 相关联的标记。在该入口函数中,策略应当释放所有在内部分配的与 label 相关联的存储空间,以便销毁该标记。
mpo_destroy_mount_label 销毁与一个 mount 点相关联的标记。在该入口函数中,策略应当释放所有在内部分配的与
mntlabel 相关联的存储空间,以便销毁该标记。
mpo_destroy_mount_label 销毁与一个 mount 点相关联的标记。在该入口函数中,策略应当释放所有在内部分配的,与
mntlabel 和fslabel
相关联的存储空间,以便销毁该标记。
mpo_destroy_socket_label 销毁与一个套接字相关联的标记。在该入口函数中,策略应当释放所有在内部分配的,与
label 相关联的存储空间,以便销毁该标记。
mpo_destroy_socket_peer_label
销毁与一个套接字相关联的对等实体标记。在该入口函数中,策略应当释放所有在内部分配的,与
label 相关联的存储空间,以便销毁该标记。
mpo_destroy_pipe_label 销毁一个管道的标记。在该入口函数中,策略应当释放所有在内部分配的,与 label 相关联的存储空间,以便销毁该标记。
mpo_destroy_proc_label 销毁一个进程的标记。在该入口函数中,策略应当释放所有在内部分配的,与 label 相关联的存储空间,以便销毁该标记。
mpo_destroy_vnode_label 销毁一个 vnode 的标记。在该入口函数中,策略应当释放所有在内部分配的,与 label 相关联的存储空间,以便销毁该标记。
mpo_copy_mbuf_label 将 src 中的标记信息拷贝到 dest中。
mpo_copy_pipe_label 将 src 中的标记信息拷贝至 dest。
mpo_copy_vnode_label 将 src 中的标记信息拷贝至 dest。
mpo_externalize_cred_labelint mpo_externalize_cred_label(struct label *label,
char *element_name, struct sbuf *sb, int *claimed);
| 参数 | 说明 | 锁定 |
|---|---|---|
label |
将用外部形式表示的标记 | |
element_name |
需要外部表示标记的策略的名字 | |
sb |
用来存放标记的文本表示形式的字符buffer | |
claimed |
如果可以填充element_data 域,则其数值递增 |
根据传入的标记结构,产生一个以外部形式表示的标记。 一个外部形式标记,是标记内容的文本表示,它由用户级的应用程序使用,是用户可读的。 目前的MAC实现方案将依次调用策略的相应入口函数,因此, 具体策略的实现代码,需要在填写sb之前,先检查element_name中指定的名字。 如果element_name中的内容与你的策略名字不相符,则直接返回0。 仅当转换标记数据的过程中出现错误时,才返回非0值。 一旦策略决定填写element_data,递增*claim的数值。
mpo_externalize_ifnet_labelint mpo_externalize_ifnet_label(struct label
*label, char *element_name, struct sbuf *sb, int *claimed);
| 参数 | 说明 | 锁定 |
|---|---|---|
label |
将用外部形式表示的标记 | |
element_name |
需要外部表示标记的策略的名字 | |
sb |
用来存放标记的文本表示形式的字符buffer | |
claimed |
如果可以填充element_data 域,则其数值递增 |
根据传入的标记结构,产生一个以外部形式表示的标记。 一个外部形式标记,是标记内容的文本表示,它由用户级的应用程序使用,是用户可读的。 目前的MAC实现方案将依次调用策略的相应入口函数,因此, 具体策略的实现代码,需要在填写sb之前,先检查element_name中指定的名字。 如果element_name中的内容与你的策略名字不相符,则直接返回0。 仅当转换标记数据的过程中出现错误时,才返回非0值。 一旦策略决定填写element_data,递增*claim的数值。
mpo_externalize_pipe_labelint mpo_externalize_pipe_label(struct label *label,
char *element_name, struct sbuf *sb, int *claimed);
| 参数 | 说明 | 锁定 |
|---|---|---|
label |
将用外部形式表示的标记 | |
element_name |
需要外部表示标记的策略的名字 | |
sb |
用来存放标记的文本表示形式的字符buffer | |
claimed |
如果可以填充element_data 域,则其数值递增 |
根据传入的标记结构,产生一个以外部形式表示的标记。 一个外部形式标记,是标记内容的文本表示,它由用户级的应用程序使用,是用户可读的。 目前的MAC实现方案将依次调用策略的相应入口函数,因此, 具体策略的实现代码,需要在填写sb之前,先检查element_name中指定的名字。 如果element_name中的内容与你的策略名字不相符,则直接返回0。 仅当转换标记数据的过程中出现错误时,才返回非0值。 一旦策略决定填写element_data,递增*claim的数值。
mpo_externalize_socket_labelint mpo_externalize_socket_label(struct label
*label, char *element_name, struct sbuf *sb, int *claimed);
| 参数 | 说明 | 锁定 |
|---|---|---|
label |
将用外部形式表示的标记 | |
element_name |
需要外部表示标记的策略的名字 | |
sb |
用来存放标记的文本表示形式的字符buffer | |
claimed |
如果可以填充element_data 域,则其数值递增 |
根据传入的标记结构,产生一个以外部形式表示的标记。 一个外部形式标记,是标记内容的文本表示,它由用户级的应用程序使用,是用户可读的。 目前的MAC实现方案将依次调用策略的相应入口函数,因此, 具体策略的实现代码,需要在填写sb之前,先检查element_name中指定的名字。 如果element_name中的内容与你的策略名字不相符,则直接返回0。 仅当转换标记数据的过程中出现错误时,才返回非0值。 一旦策略决定填写element_data,递增*claim的数值。
mpo_externalize_socket_peer_labelint mpo_externalize_socket_peer_label(struct label
*label, char *element_name, struct sbuf *sb, int *claimed);
| 参数 | 说明 | 锁定 |
|---|---|---|
label |
将用外部形式表示的标记 | |
element_name |
需要外部表示标记的策略的名字 | |
sb |
用来存放标记的文本表示形式的字符buffer | |
claimed |
如果可以填充element_data 域,则其数值递增 |
根据传入的标记结构,产生一个以外部形式表示的标记。 一个外部形式标记,是标记内容的文本表示,它由用户级的应用程序使用,是用户可读的。 目前的MAC实现方案将依次调用策略的相应入口函数,因此, 具体策略的实现代码,需要在填写sb之前,先检查element_name中指定的名字。 如果element_name中的内容与你的策略名字不相符,则直接返回0。 仅当转换标记数据的过程中出现错误时,才返回非0值。 一旦策略决定填写element_data,递增*claim的数值。
mpo_externalize_vnode_labelint mpo_externalize_vnode_label(struct label
*label, char *element_name, struct sbuf *sb, int *claimed);
| 参数 | 说明 | 锁定 |
|---|---|---|
label |
将用外部形式表示的标记 | |
element_name |
需要外部表示标记的策略的名字 | |
sb |
用来存放标记的文本表示形式的字符buffer | |
claimed |
如果可以填充element_data 域,则其数值递增 |
根据传入的标记结构,产生一个以外部形式表示的标记。 一个外部形式标记,是标记内容的文本表示,它由用户级的应用程序使用,是用户可读的。 目前的MAC实现方案将依次调用策略的相应入口函数,因此, 具体策略的实现代码,需要在填写sb之前,先检查element_name中指定的名字。 如果element_name中的内容与你的策略名字不相符,则直接返回0。 仅当转换标记数据的过程中出现错误时,才返回非0值。 一旦策略决定填写element_data,递增*claim的数值。
mpo_internalize_cred_labelint mpo_internalize_cred_label(struct label *label,
char *element_name, char *element_data, int *claimed);
根据一个文本形式的外部表示标记数据,创建一个内部形式的标记结构。 目前的MAC方案将依次调用所有策略的相关入口函数,来响应标记的内部转换请求, 因此,实现代码必须首先通过比较element_name中的内容和自己的策略名字, 来确定是否需要转换element_data中存放的数据。 类似的,如果名字不匹配或者数据转换操作成功,该函数返回0,并递增*claimed的值。
mpo_internalize_ifnet_labelint mpo_internalize_ifnet_label(struct label
*label, char *element_name, char *element_data, int *claimed);
根据一个文本形式的外部表示标记数据,创建一个内部形式的标记结构。 目前的MAC方案将依次调用所有策略的相关入口函数,来响应标记的内部转换请求, 因此,实现代码必须首先通过比较element_name中的内容和自己的策略名字, 来确定是否需要转换element_data中存放的数据。 类似的,如果名字不匹配或者数据转换操作成功,该函数返回0,并递增*claimed的值。
mpo_internalize_pipe_labelint mpo_internalize_pipe_label(struct label *label,
char *element_name, char *element_data, int *claimed);
根据一个文本形式的外部表示标记数据,创建一个内部形式的标记结构。 目前的MAC方案将依次调用所有策略的相关入口函数,来响应标记的内部转换请求, 因此,实现代码必须首先通过比较element_name中的内容和自己的策略名字, 来确定是否需要转换element_data中存放的数据。 类似的,如果名字不匹配或者数据转换操作成功,该函数返回0,并递增*claimed的值。
mpo_internalize_socket_labelint mpo_internalize_socket_label(struct label
*label, char *element_name, char *element_data, int *claimed);
根据一个文本形式的外部表示标记数据,创建一个内部形式的标记结构。 目前的MAC方案将依次调用所有策略的相关入口函数,来响应标记的内部转换请求, 因此,实现代码必须首先通过比较element_name中的内容和自己的策略名字, 来确定是否需要转换element_data中存放的数据。 类似的,如果名字不匹配或者数据转换操作成功,该函数返回0,并递增*claimed的值。
mpo_internalize_vnode_labelint mpo_internalize_vnode_label(struct label
*label, char *element_name, char *element_data, int *claimed);
根据一个文本形式的外部表示标记数据,创建一个内部形式的标记结构。 目前的MAC方案将依次调用所有策略的相关入口函数,来响应标记的内部转换请求, 因此,实现代码必须首先通过比较element_name中的内容和自己的策略名字, 来确定是否需要转换element_data中存放的数据。 类似的,如果名字不匹配或者数据转换操作成功,该函数返回0,并递增*claimed的值。
策略模块使用MAC 框架提供的“标记事件”类入口函数,对内核对象的标记进行操作。策略模块将感兴趣的被标记内核对象的相关生命周期事件 注册在恰当的入口点上。对象的初始化、创建和销毁事件均提供了钩子点。在某些对象上还可以实现重新标记,即,允许用户进程改变对象上的标记值。 对某些对象可以实现其特定的对象事件,比如与 IP 重组相关的标记事件。一个典型的被标记对象在其生命周期中将拥有下列入口函数:
标记初始化 o
(对象相关的等待) \
标记创建 o
\
重新标记事件, o--<--.
各种对象相关的, | |
访问控制事件 ~-->--o
\
标记销毁 o
使用标记初始化入口函数,策略可以以一种统一的、与对象使用环境无关的方式设置标记的初始值。 分配给一个策略的缺省 slot 值为0,这样不使用标记的策略可能并不需要执行专门的初始化操作。
标记的创建事件发生在将一个内核数据结构同一个真实的内核对象相关联(内核对象实例化)的时刻。 例如,在真正被使用之前,在一个缓冲池内已分配的 mbuf 数据结构,将保持为“未使用”状态。 因此,mbuf 的分配操作将导致针对该 mbuf 的标记初始化操作,而 mbuf 的创建操作则被推迟到该 mbuf 真正与一个数据报相关联的时刻。 通常,调用者将会提供创建事件的上下文,包括创建环境、创建过程中涉及的其他对象的标记等。例如,当一个套接字创建一个 mbuf 时, 除了新创建的 mbuf 及其标记之外,作为创建者的套接字与其标记也被提交给策略检查。 不提倡在创建对象时就为其分配内存的原因有两个:创建操作可能发生在对性能有严格要求的内核接口上; 而且,因为创建调用不允许失败,所以无法报告内存分配失败。
对象特有的事件一般不会引发其他的标记事件,但是在对象上下文发生改变时,策略使用它们可以对相关标记进行修改或更新操作。
例如,在MAC_UPDATE_IPQ 入口函数之内,某个 IP
分片重组队列的标记可能会因为队列中接收了新的 mbuf 而被更新。
访问控制事件将在后续章节中详细讨论。
策略通过执行标记销毁操作,释放为其分配的存储空间或维护的状态,之后内核才可以重用或者释放对象的内核数据结构。
除了与特定内核对象绑定的普通标记之外,还有一种额外的标记类型:临时标记。这些标记用于存放由用户进程提交的更新信息。
它们的初始化和销毁操作与其他标记一样,只是创建事件,MAC_INTERNALIZE,略有不同:
该函数接受用户提交的标记,负责将其转化为内核表示形式。
mpo_associate_vnode_devfsvoid 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)。
mpo_associate_vnode_extattrint mpo_associate_vnode_extattr(struct mount *mp,
struct label *fslabel, struct vnode *vp, struct label *vlabel);
从文件系统扩展属性中读取 vp 的标记。成功,返回 0。 不成功,则在 errno
指定的相应的错误编码。 如果文件系统不支持扩展属性的读取操作,则可以考虑将 fslabel 拷贝至 vlabel。
mpo_associate_vnode_singlelabelvoid mpo_associate_vnode_singlelabel(struct mount
*mp, struct label *fslabel, struct vnode *vp, struct label *vlabel);
在非多重标记文件系统上,使用该入口函数,根据文件系统标记,fslabel, 为 vp
设置策略标记。
mpo_create_devfs_device为传入设备新建的 devfs_dirent 填写标记。该函数将在设备文件系统加载、重构或添加新设备时被调用。
mpo_create_devfs_directoryvoid mpo_create_devfs_directory(char *dirname, int
dirnamelen, struct devfs_dirent *devfs_dirent, struct label *label);
为传入目录参数的新建 devfs_dirent 填写标记。该函数将在加载、重构设备文件系统,或者添加一个需要指定目录结构的新设备时被调用。
mpo_create_devfs_symlinkvoid mpo_create_devfs_symlink(struct ucred *cred,
struct mount *mp, struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent
*de, struct label *delabel);
为新近创建的
devfs(5)
符号链接项填写标记(delabel)。
mpo_create_vnode_extattrint 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 |
文件系统挂载点 | |
label |
文件系统标记 | |
dvp |
父目录 vnode | |
dlabel |
与 dvp 相关联的策略标记 |
|
vp |
新创建的 vnode | |
vlabel |
与 vp 相关联的策略标记 |
|
cnp |
vp中的子域名字 |
将 vp 的标记写入文件扩展属性。成功,将标记填入
vlabel, 并返回 0。否则,返回对应的错误编码。
mpo_create_mountvoid mpo_create_mount(struct ucred *cred, struct
mount *mp, struct label *mnt, struct label *fslabel);
为传入的主体信任状所创建的挂载点填写标记。该函数将在文件系统挂载时被调用。
mpo_create_root_mountvoid mpo_create_root_mount(struct ucred *cred,
struct mount *mp, struct label *mntlabel, struct label *fslabel);
| 参数 | 说明 | 锁定 |
|---|---|---|
| 见 第 6.7.3.1.8 节. | ||
为传入的主体信任状所创建的挂载点填写标记。该函数将在挂载根文件系统时,mpo_create_mount; 之后被调用。
mpo_relabel_vnodevoid mpo_relabel_vnode(struct ucred *cred, struct
vnode *vp, struct label *vnodelabel, struct label *newlabel);
根据传入的新标记和主体信任状,更新参数 vnode 的标记。
mpo_setlabel_vnode_extattrint mpo_setlabel_vnode_extattr(struct ucred *cred,
struct vnode *vp, struct label *vlabel, struct label *intlabel);
将参数 intlabel 给出的标记信息写入指定 vnode
的扩展属性。 该函数被 vop_stdcreatevnode_ea 所调用。
mpo_update_devfsdirentvoid 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 标记进行初始化操作。
mpo_create_mbuf_from_socketvoid mpo_create_mbuf_from_socket(struct socket *so,
struct label *socketlabel, struct mbuf *m, struct label *mbuflabel);
根据传入的套接字标记为新创建的mbuf头部设置标记。 每当套接字产生一个新的数据报或者消息,并将其存储在参数 mbuf 中时,将调用该函数。
mpo_create_pipe根据传入的主体信任状参数,设置新建管道的标记。每当一个新管道被创建,该函数将被调用。
mpo_create_socket根据传入的主体信任状参数,设置新建套接字的标记。每当新建一个套接字,该函数将被调用。
mpo_create_socket_from_socketvoid mpo_create_socket_from_socket(struct socket
*oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label
*newsocketlabel);
| 参数 | 说明 | 锁定 |
|---|---|---|
oldsocket |
监听套接字 | |
oldsocketlabel |
oldsocket 的策略标记 |
|
newsocket |
新建套接字 | |
newsocketlabel |
newsocket 的策略标记 |
根据 listen(2) 套接字 oldsocket, 为新建 accept(2) 的套接字
newsocket,设置标记。
mpo_relabel_pipevoid mpo_relabel_pipe(struct ucred *cred, struct
pipe *pipe, struct label *oldlabel, struct label *newlabel);
为pipe设置新标记newlabel。
mpo_relabel_socketvoid mpo_relabel_socket(struct ucred *cred, struct
socket *so, struct label *oldlabel, struct label *newlabel);
根据传入的标记参数,对套接字的当前标记进行更新。
mpo_set_socket_peer_from_mbufvoid mpo_set_socket_peer_from_mbuf(struct mbuf
*mbuf, struct label *mbuflabel, struct label *oldlabel, struct label
*newlabel);
根据传入的 mbuf 标记,设置某个 stream 套接字的对等标志。 除Unix域的套接字之外,每当一个 stream 套接字接收到第一个数据报时,该函数将被调用。
mpo_set_socket_peer_from_socketvoid mpo_set_socket_peer_from_socket(struct socket
*oldsocket, struct label *oldsocketlabel, struct socket *newsocket, struct label
*newsocketpeerlabel);
| 参数 | 说明 | 锁定 |
|---|---|---|
oldsocket |
本地套接字 | |
oldsocketlabel |
oldsocket 的策略标记 |
|
newsocket |
对等套接字 | |
newsocketpeerlabel |
将为newsocket填写的策略标记 |
根据传入的远程套接字端点,为一个 stream UNIX 与套接字设置对等标记。 每当相应的套接字对之间进行连接时,该函数将在两端分别被调用。
mpo_create_bpfdesc根据传入的主体信任状参数,为新建的 BPF 描述子设置标记。 当进程打开 BPF 设备节点时,该函数将被调用。
mpo_create_ifnet为新建的网络接口设置标记。该函数在以下情况下被调用: 当一个新的物理接口变为可用时,或者当一个伪接口在引导时或由于某个用户操作而实例化时。
mpo_create_ipqvoid 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 分片重组队列设置标记。
mpo_create_datagram_from_ipqvoid mpo_create_create_datagram_from_ipq(struct ipq
*ipq, struct label *ipqlabel, struct mbuf *datagram, struct label
*datagramlabel);
根据 IP 分片重组队列,为刚刚重组完毕的 IP 数据报设置标记。
mpo_create_fragmentvoid mpo_create_fragment(struct mbuf *datagram,
struct label *datagramlabel, struct mbuf *fragment, struct label
*fragmentlabel);
根据数据报所对应的 mbuf 头部信息,为其新建的分片的 mbuf 头部设置标记。
mpo_create_mbuf_from_mbufvoid 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 时。
mpo_create_mbuf_linklayervoid mpo_create_mbuf_linklayer(struct ifnet *ifnet,
struct label *ifnetlabel, struct mbuf *mbuf, struct label *mbuflabel);
为在给定接口上由于某个链路层响应而新建的数据报的mbuf头部设置标记。 该函数将在若干条件下被调用,比如当IPv4和IPv6协议栈在响应ARP或者ND6时。
mpo_create_mbuf_from_bpfdescvoid mpo_create_mbuf_from_bpfdesc(struct bpf_d
*bpf_d, struct label *bpflabel, struct mbuf *mbuf, struct label *mbuflabel);
为使用参数 BPF 描述子创建的新数据报的 mbuf 头部设置标记。 当对参数 BPF 描述子所关联的 BPF 设备进行写操作时,该函数将被调用。
mpo_create_mbuf_from_ifnetvoid mpo_create_mbuf_from_ifnet(struct ifnet
*ifnet, struct label *ifnetlabel, struct mbuf *mbuf, struct label *mbuflabel);
为从网络接口参数创建的数据报的 mbuf 头部设置标记。
mpo_create_mbuf_multicast_encapvoid 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填写的策略标记 |
当传入的已有数据报被给定多播封装接口(multicast encapsulation interface)处理时被调用, 为新创建的数据报所在 mbuf 头部设置标记。 每当使用该虚拟接口传递一个mbuf时,将调用该函数。
mpo_create_mbuf_netlayervoid mpo_create_mbuf_netlayer(struct mbuf *oldmbuf,
struct label *oldmbuflabel, struct mbuf *newmbuf, struct label *newmbuflabel);
为由 IP 堆栈因为响应接收数据报(oldmbuf)而新建的数据报设置其 mbuf 头部的标记。
许多情况下需要调用该函数,比如,响应 ICMP 请求数据报时。
mpo_fragment_matchint mpo_fragment_match(struct mbuf *fragment,
struct label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel);
根据所传入的 IP 分片重组队列(ipq)的标记,
检查包含一个 IP 数据报(fragment)的 mbuf
的头部是否符合其要求。 符合,则返回1。否则,返回0。 每当 IP
堆栈尝试将一个刚刚接收到的分片放入某个已有的分片重组队列中时,将调用该函数进行安全检查;
如果失败,将为分片重新实例化一个新的分片重组队列。
策略可以利用该入口函数,根据标记或者其他信息阻止不期望的 IP 分片重组。
mpo_relabel_ifnetvoid mpo_relabel_ifnet(struct ucred *cred, struct
ifnet *ifnet, struct label *ifnetlabel, struct label *newlabel);
根据所传入的新标记,newlabel,以及主体信任状,
cred,对网络接口的标记进行更新。
mpo_update_ipqvoid mpo_update_ipq(struct mbuf *fragment, struct
label *fragmentlabel, struct ipq *ipq, struct label *ipqlabel);
根据所传入的 IP 分片 mbuf 头部(mbuf)为接收 它的
IP 分片重组队列(ipq)的标记进行更新。
mpo_create_cred根据所传入的主体信任状,为新建的主体信任状设置标记。 每当为一个新建的 struct ucred调用 crcopy(9) 时,将调用此函数。 该函数不应与进程复制(forking)或者创建事件混为一谈。
mpo_execve_transitionvoid mpo_execve_transition(struct ucred *old,
struct ucred *new, struct vnode *vp, struct label *vnodelabel);
一个拥有信任状old的主体由于执行(vp文件而导致标记转换时,
该函数根据vnode标记为该主体重新标记为new。
每当一个进程请求执行vnode文件,而通过 入口函数mpo_execve_will_transition 有成功返回的策略时,将调用该函数。
策略模块可以通过传入两个主体信任状和简单地调用 mpo_create_cred 来实现该入口函数, so as not to implement a
transitioning event. 一旦策略实现了mpo_create_cred函数,即使没有实现 mpo_execve_will_transition,也应该实现该函数。
mpo_execve_will_transition| 参数 | 说明 | 锁定 |
|---|---|---|
old |
在执行execve(2)之前的主体信任状 | 不可改变 |
vp |
将被执行的文件 | |
vnodelabel |
vp 的策略标记 |
由策略决定,当参数主体信任状执行参数 vnode
时,是否需要进行一个标记转换操作。如果需要,返回1;
否则,返回0。即使一个策略返回0,它也必须为自己不期望的对 mpo_execve_transition的调用作好准备,因为只要有其他任何一个策略要求转换,就将执行此函数。
mpo_create_proc0为进程0,所有内核进程的祖先,创建主体信任状。
mpo_create_proc1为进程1,所有用户进程的祖先,创建主体信任状。
mpo_relabel_cred根据传入的新标记,对主体信任状上的标记进行更新。
通过访问控制入口函数,策略模块能影响内核的访问控制决策。
通常情况下,不是绝对,一个访问控制入口函数的参数有,一个或者若干个授权信任状,和相关操作涉及的其他任何对象的信息(其中可能包含标记)。
访问控制入口函数返回0,表示允许该操作;否则,返回一个 errno(2)
错误编码。调用该入口函数,将遍历所有系统注册的策略模块,逐一进行
策略相关的检查和决策,之后按照下述方法组合不同策略的返回结果:只有当所有的模块均允许该操作时,才成功返回。
否则,如果有一个或者若干模块失败返回,则整个检查不通过。如果有多个模块的检查出错返回,将由定义在kern_mac.c 中的 error_select()
函数从它们返回的错误编码中,选择一个合适的,返回给用户。
如果所有策略模块返回的错误编码均没有出现在上述优先级序列表中,则任意选择一个返回。 选择错误编码的一般次序为:内核错误,无效的参数,对象不存在,访问被拒绝,和其他错误。
mpo_check_bpfdesc_receiveint mpo_check_bpfdesc_receive(struct bpf_d *bpf_d,
struct label *bpflabel, struct ifnet *ifnet, struct label *ifnetlabel);
决定 MAC 框架是否应该允许将由参数接口接收到的数据报传递给由 BPF
描述子所对应的缓冲区。成功,则返回0;
否则,返回错误编码信息errno。建议使用的错误编码有:EACCES,用于标记不符的情况; EPERM,用于缺少特权的情况。
mpo_check_kenv_dump决定相关主体是否应该被允许查询内核环境状态(参考 kenv(2))。
mpo_check_kenv_get决定相关主体是否可以查询内核中给定环境变量的状态。
mpo_check_kenv_set决定相关主体是否有权设置给定内核环境变量的值。
mpo_check_kenv_unset决定相关主体是否有权清除给定的内核环境变量的设置。
mpo_check_kld_load决定相关主体是否有权加载给定的模块文件。
mpo_check_kld_stat决定相关主体是否有权访问内核的加载模块文件链表以及相关的统计数据。
mpo_check_kld_unload决定相关主体是否有权卸载一个内核模块。
mpo_check_pipe_ioctlint mpo_check_pipe_ioctl(struct ucred *cred, struct
pipe *pipe, struct label *pipelabel, unsigned long cmd, void *data);
决定相关主体是否有权调用指定的 ioctl(2) 系统调用。
mpo_check_pipe_poll 决定相关主体是否有权对管道pipe执行poll操作。
mpo_check_pipe_read 决定该主体是否有权读取pipe。
mpo_check_pipe_relabelint mpo_check_pipe_relabel(struct ucred *cred,
struct pipe *pipe, struct label *pipelabel, struct label *newlabel);
决定该主体是否有权为pipe重新设置标记。
mpo_check_pipe_stat 决定该主体是否有权查询与pipe相关的统计信息。
mpo_check_pipe_write 决定该主体是否有权写pipe。
mpo_check_socket_bindmpo_check_socket_connectint mpo_check_socket_connect(struct ucred *cred,
struct socket *socket, struct label *socketlabel, struct sockaddr *sockaddr);
决定该主体(cred)是否有权将套接字(socket)绑定到地址 sockaddr。成功,返回0,否则返回一个错误编码errno。
建议采用的错误编码有:EACCES,用于标记不符的情况;EPERM,用于特权不足的情况。