1. 简介
SELinux策略语言主要描述policy.conf的相关语法,其相关部分如下图所示:
2. 客体类别
定义内核支持的客体类别和许可的策略语言指令,并对SELinux系统中内核客体类别标准做一个概述。
2.1 SELinux中客体类别的用途
客体类别及其许可是SELinux中访问控制的基础,客体类别代表资源的范畴,如文件和套接字,许可代表对这些资源的访问权限,如读或发送。理解客体类别和许可是SELinux中比较困难的部分,因为这需要SELinux和Linux两方面的知识。
一个客体类别代表某个确定类型(如文件或套接字)的所有资源,一个客体类别的实例(如某个特定的文件或套接字)被称为一个客体,通常,客体类别和客体这两个术语可以交替使用,但是理解其定义是相当重要的,客体类别指的是资源(文件)的所有范畴,客体指的是客体类别的某个特定实例(/etc/passwd)。
2.2 在SELinux策略中定义客体类别
策略中必须包括所有SELinux内核支持的客体类别和许可的声明,以及其他客体管理器。
添加新的客体类别和修改现有客体类别的许可是一项复杂的任务,仅当修改真实系统代码本身时应该这样做,与SELinux策略语言的其他方面不同,客体类别和许可依赖于Linux的实现细节,特别是内核。实际上,客体类别和许可被设计为尽可能准确地代表系统执行的资源,正是由于这个原因,改变客体类别或在系统中改变对应的许可才变得有意义。
声明许可有两种方法,第一种叫做通用许可(被多个客体类别所共用),它允许我们创建与客体类别一起作为一个组的许可,通用许可在类似的客体类别(如文件和符号连接)共享一套访问许可时很有用;第二种方法叫做特定类别许可(由某个客体类别所独用),它允许我们单独为客体类别声明特定的许可,正如将会看到的,有一些客体类别只有特定的许可,有一些只有通用许可,还有一些是这两者都有。
客体类别和许可定义方法如下:
• 声明客体类别:class 类别名字
• 通用许可:common 通用名 {许可集}
• 联合许可和客体类别:class 类别名 [inherits 通用许可集名] [{许可集}]
2.3 有效的客体类别和许可
在Kernel3.0.36客体类别和许可定义如下(定义见kernel/security/selinux/include/classmap.h),共有49个客体类别 被定义:
[cpp]
view plain
copy
-
-
-
#define COMMON_FILE_SOCK_PERMS "ioctl", "read", "write", "create", \
-
"getattr", "setattr", "lock", "relabelfrom", "relabelto", "append"
-
-
#define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \
-
"rename", "execute", "swapon", "quotaon", "mounton", "audit_access", \
-
"open", "execmod"
-
-
#define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \
-
"listen", "accept", "getopt", "setopt", "shutdown", "recvfrom", \
-
"sendto", "recv_msg", "send_msg", "name_bind"
-
-
#define COMMON_IPC_PERMS "create", "destroy", "getattr", "setattr", "read", \
-
"write", "associate", "unix_read", "unix_write"
-
-
/*
-
* Note: The name for any socket class should be suffixed by "socket",
-
* and doesn't contain more than one substr of "socket".
-
*/
-
struct security_class_mapping secclass_map[] = {
-
{ "security", //客体类别
-
{ "compute_av", "compute_create", "compute_member", //许可
-
"check_context", "load_policy", "compute_relabel",
-
"compute_user", "setenforce", "setbool", "setsecparam",
-
"setcheckreqprot", "read_policy", NULL } },
-
{ "process", //客体类别
-
{ "fork", "transition", "sigchld", "sigkill",
-
"sigstop", "signull", "signal", "ptrace", "getsched", "setsched",
-
"getsession", "getpgid", "setpgid", "getcap", "setcap", "share",
-
"getattr", "setexec", "setfscreate", "noatsecure", "siginh",
-
"setrlimit", "rlimitinh", "dyntransition", "setcurrent",
-
"execmem", "execstack", "execheap", "setkeycreate",
-
"setsockcreate", NULL } },
-
{ "system",
-
{ "ipc_info", "syslog_read", "syslog_mod",
-
"syslog_console", "module_request", NULL } },
-
{ "capability",
-
{ "chown", "dac_override", "dac_read_search",
-
"fowner", "fsetid", "kill", "setgid", "setuid", "setpcap",
-
"linux_immutable", "net_bind_service", "net_broadcast",
-
"net_admin", "net_raw", "ipc_lock", "ipc_owner", "sys_module",
-
"sys_rawio", "sys_chroot", "sys_ptrace", "sys_pacct", "sys_admin",
-
"sys_boot", "sys_nice", "sys_resource", "sys_time",
-
"sys_tty_config", "mknod", "lease", "audit_write",
-
"audit_control", "setfcap", NULL } },
-
{ "filesystem",
-
{ "mount", "remount", "unmount", "getattr",
-
"relabelfrom", "relabelto", "transition", "associate", "quotamod",
-
"quotaget", NULL } },
-
{ "file",
-
{ COMMON_FILE_PERMS,
-
"execute_no_trans", "entrypoint", NULL } },
-
{ "dir",
-
{ COMMON_FILE_PERMS, "add_name", "remove_name",
-
"reparent", "search", "rmdir", NULL } },
-
{ "fd", { "use", NULL } },
-
{ "lnk_file",
-
{ COMMON_FILE_PERMS, NULL } },
-
{ "chr_file",
-
{ COMMON_FILE_PERMS, NULL } },
-
{ "blk_file",
-
{ COMMON_FILE_PERMS, NULL } },
-
{ "sock_file",
-
{ COMMON_FILE_PERMS, NULL } },
-
{ "fifo_file",
-
{ COMMON_FILE_PERMS, NULL } },
-
{ "socket",
-
{ COMMON_SOCK_PERMS, NULL } },
-
{ "tcp_socket",
-
{ COMMON_SOCK_PERMS,
-
"connectto", "newconn", "acceptfrom", "node_bind", "name_connect",
-
NULL } },
-
{ "udp_socket",
-
{ COMMON_SOCK_PERMS,
-
"node_bind", NULL } },
-
{ "rawip_socket",
-
{ COMMON_SOCK_PERMS,
-
"node_bind", NULL } },
-
{ "node",
-
{ "tcp_recv", "tcp_send", "udp_recv", "udp_send",
-
"rawip_recv", "rawip_send", "enforce_dest",
-
"dccp_recv", "dccp_send", "recvfrom", "sendto", NULL } },
-
{ "netif",
-
{ "tcp_recv", "tcp_send", "udp_recv", "udp_send",
-
"rawip_recv", "rawip_send", "dccp_recv", "dccp_send",
-
"ingress", "egress", NULL } },
-
{ "netlink_socket",
-
{ COMMON_SOCK_PERMS, NULL } },
-
{ "packet_socket",
-
{ COMMON_SOCK_PERMS, NULL } },
-
{ "key_socket",
-
{ COMMON_SOCK_PERMS, NULL } },
-
{ "unix_stream_socket",
-
{ COMMON_SOCK_PERMS, "connectto", "newconn", "acceptfrom", NULL
-
} },
-
{ "unix_dgram_socket",
-
{ COMMON_SOCK_PERMS, NULL
-
} },
-
{ "sem",
-
{ COMMON_IPC_PERMS, NULL } },
-
{ "msg", { "send", "receive", NULL } },
-
{ "msgq",
-
{ COMMON_IPC_PERMS, "enqueue", NULL } },
-
{ "shm",
-
{ COMMON_IPC_PERMS, "lock", NULL } },
-
{ "ipc",
-
{ COMMON_IPC_PERMS, NULL } },
-
{ "netlink_route_socket",
-
{ COMMON_SOCK_PERMS,
-
"nlmsg_read", "nlmsg_write", NULL } },
-
{ "netlink_firewall_socket",
-
{ COMMON_SOCK_PERMS,
-
"nlmsg_read", "nlmsg_write", NULL } },
-
{ "netlink_tcpdiag_socket",
-
{ COMMON_SOCK_PERMS,
-
"nlmsg_read", "nlmsg_write", NULL } },
-
{ "netlink_nflog_socket",
-
{ COMMON_SOCK_PERMS, NULL } },
-
{ "netlink_xfrm_socket",
-
{ COMMON_SOCK_PERMS,
-
"nlmsg_read", "nlmsg_write", NULL } },
-
{ "netlink_selinux_socket",
-
{ COMMON_SOCK_PERMS, NULL } },
-
{ "netlink_audit_socket",
-
{ COMMON_SOCK_PERMS,
-
"nlmsg_read", "nlmsg_write", "nlmsg_relay", "nlmsg_readpriv",
-
"nlmsg_tty_audit", NULL } },
-
{ "netlink_ip6fw_socket",
-
{ COMMON_SOCK_PERMS,
-
"nlmsg_read", "nlmsg_write", NULL } },
-
{ "netlink_dnrt_socket",
-
{ COMMON_SOCK_PERMS, NULL } },
-
{ "association",
-
{ "sendto", "recvfrom", "setcontext", "polmatch", NULL } },
-
{ "netlink_kobject_uevent_socket",
-
{ COMMON_SOCK_PERMS, NULL } },
-
{ "appletalk_socket",
-
{ COMMON_SOCK_PERMS, NULL } },
-
{ "packet",
-
{ "send", "recv", "relabelto", "forward_in", "forward_out", NULL } },
-
{ "key",
-
{ "view", "read", "write", "search", "link", "setattr", "create",
-
NULL } },
-
{ "dccp_socket",
-
{ COMMON_SOCK_PERMS,
-
"node_bind", "name_connect", NULL } },
-
{ "memprotect", { "mmap_zero", NULL } },
-
{ "peer", { "recv", NULL } },
-
{ "capability2", { "mac_override", "mac_admin", "syslog", NULL } },
-
{ "kernel_service", { "use_as_override", "create_files_as", NULL } },
-
{ "tun_socket",
-
{ COMMON_SOCK_PERMS, NULL } },
-
{ NULL }
-
};
-
为了易于理解,我们将内核客体类别分解成四大类:文件相关的,网络相关的,System V IPC和杂项。
2.3.1 与文件相关的客体类别
此类客体类别是那些与文件及其他存储在文件系统中的资源有关的,这是大多数用户最熟悉的客体类别了,它包括了所有的与持续不变的,在磁盘上的文件系统和在内存中的文件系统,如proc和sysfs结合在一起的客体类别。与文件相关的客体类别如下表所示:
客体类别
|
描述
|
filesystem
|
文件系统(如一个真实的分区)
|
file
|
普通文件
|
dir
|
目录
|
fd
|
文件描述符
|
lnk_file
|
符号链接
|
chr_file
|
字符文件
|
blk_file
|
块文件
|
sock_file
|
UNIX域套接字
|
fifo_file
|
命名管道
|
2.3.2 与网络相关的客体类别
与网络有关的客体类别代表网络资源如网络接口、不同种类的套接字和主机。目前的客体类别足以允许对单个系统上的网络进行广泛的控制,另外还有增强,如标记网络数据包,下表列出了与网络和套接字有关的客体类别。
客体类别
|
描述
|
socket
|
其它的套接字
|
tcp_socket
|
TCP套接字
|
udp_socket
|
UDP套接字
|
rawip_socket
|
发送原始IP数据包的套接字
|
node
|
代表一个IP地址或一段IP地址的主机
|
netif
|
网络接口(如eth0)
|
netlink_socket
|
所有其它的Netlink套接字
|
packet_socket
|
发送其它类型的原始数据包的套接字
|
key_socket
|
PF_KEY协议家族的套接字,用于管理IPsec中的密钥
|
unix_stream_socket
|
本地机器上(unix域)的IPC流套接字
|
unix_dgram_socket
|
本地机器上(unix域)的IPC数据报套接字
|
netlink_route_socket
|
用于控制和管理网络资源如路由表和IP地址的Netlink套接字
|
netlink_firewall_socket
|
用于创建用户空间防火墙过滤器的Netlink套接字
|
netlink_tcpdiag_socket
|
用于监视TCP连接的Netlink套接字
|
netlink_nflog_socket
|
用于接收Netfilter日志消息的Netlink套接字
|
netlink_xfrm_socket
|
用于获取、管理和设置IPsec<IP Security>参数的Netlink套接字
|
netlink_selinux_socket
|
用于接收策略载入通知,强制模式切换和清空AVC缓存的Netlink套接字
|
netlink_audit_socket
|
用于控制审核的Netlink套接字
|
netlink_ip6fw_socket
|
用于创建用户空间IPV6防火墙过滤器的Netlink套接字
|
netlink_dnrt_socket
|
用于控制DECnet路由的Netlink套接字
|
association
|
IPsec安全联盟
|
netlink_kobject_uevent_socket
|
用于在用户空间接收内核事件通知的Netlink套接字
|
appletalk_socket
|
|
packet
|
|
dccp_socket
|
|
tun_socket
|
|
使用IP安全(IPsec)的通讯拥有额外的资源,由客体类别association和key_socket表示,IPsec安全联盟是为通讯提供安全服务的连接,association客体类别代表IPsec联盟,IPsec需要通过密钥管理(PF_KEY)套接字管理密钥,它通过key_socket客体类别进行表现。
Linux系统上的本地通讯可以使用unix域套接字(PF_UNIX)实现,这些套接字通常用于本地IPC,面向连接的套接字也叫做流套接字,通过unix_stream_socket客体类别进行表现,数据报套接字通过unix_dgram_socket表现,unix域套接字可以与文件系统上的某个特定文件关联起来,让其它应用程序很容易就连接到套接字,这个文件通过sock_file客体类别表现,它是一个与文件有关的客体类别。
SELinux中最后一组套接字是Netlink套接字,这些套接字最初是开发用于在Linux最后提供一个标准意义的网络配置,现在它们常常用于在内核与用户空间之间通讯,基于协议类型的不同有多种表示Netlink套接字的客体类别,常见的netlink_socket表示无特定客体类别的保留协议。
2.3.3 System V IPC客体类别
与IPC有关的客体类别代表System V IPC资源,msgq和msg客体类别分别代表消息队列和消息队列中的消息,sem客体类别代表信号量,shm客体类别代表共享内存段,注意对关于所有System V IPC资源的全局系统信息的访问是通过system类别上的许可进行控制的。
客体类别
|
描述
|
sem
|
信号量
|
msg
|
消息队列中的消息
|
msgq
|
消息队列
|
shm
|
共享内存段
|
ipc
|
已经没有使用了
|
2.3.4 其它杂类客体类别
下表列出了剩下的客体类别,这些客体类别与其它种类不容易混合在一起。
客体类别
|
描述
|
security
|
内核中的SELinux安全服务器
|
process
|
SELinux中的进程
|
system
|
整个系统
|
capability
|
Linux中表示权利的特权
|
key
|
|
memprotect
|
|
peer
|
|
capability2
|
|
kernel_service
|
|
3. 客体类别许可(file和process)
在2.3中,描述了每种客户类别的许可,为了更好地理解许可是如何控制对系统资源的访问,下面我们进一步讨论一下两个客体类别许可:file和process。
3.1 文件客体类别许可
下表列出了file客体类别许可,大多数对所有与文件有关的客体类别的许可都是公用的,只有execute_no_trans,entrypoint和execmod是特定给file客体类别的(这些许可都加了星号*)。
file许可
|
描述
|
分类
|
ioctl
|
ioctl(2)系统调用请求
|
|
read
|
读取文件内容,对应标准Linux下的r访问权
|
标准Linux许可
|
write
|
写入文件内容,对应标准Linux下的w访问权
|
标准Linux许可
|
create
|
创建一个新文件
|
|
getattr
|
获取文件的属性,如访问模式(例如:stat,部分ioctl)
|
|
setattr
|
改变文件的属性,如访问模式(例如:chmod,部分ioctl)
|
|
lock
|
设置和清除文件锁
|
|
relabelfrom
|
从现有类型改变安全上下文
|
SELinux特定许可
|
relabelto
|
改变新类型的安全上下文
|
SELinux特定许可
|
append
|
附加到文件内容(即用o_append标记打开)
|
文件扩展许可
|
unlink
|
移除硬链接(删除)
|
|
link
|
创建一个硬链接
|
|
rename
|
重命名一个硬链接
|
|
execute
|
执行,与标准Linux下的x访问权一致
|
标准Linux许可
|
swapon
|
不赞成使用。它用于将文件当做换页/交换空间
|
文件扩展许可
|
quotaon
|
允许文件用作一个限额数据库
|
文件扩展许可
|
mounton
|
用作挂载点
|
文件扩展许可
|
audit_access
|
|
|
open
|
打开文件
|
|
execmod
|
使被修改过的文件可执行(含有写时复制的意思)
|
SELinux特定许可
|
execute_no_trans
|
在访问者域转换的执行文件(即没有域转换)
|
SELinux特定许可
|
entrypoint
|
通过域转换,可以用作新域的入口点的文件
|
SELinux特定许可
|
文件客体类别有三类许可:直接映像到标准Linux访问控制许可的许可,标准Linux许可的扩展和SELinux特定的许可。
3.1.1 标准Linux许可
许可read,write和execute基本上与标准Linux学科读,写和执行(即r,w,x)类似,但与标准许可检查有些不同,在标准Linux中,访问权通常是在文件打开时进行检查,在SELinux中,访问权是每次使用时都会检查,read许可包括了读取整个文件的能力,它包括以一种随机方式访问文件的许可,write许可包括写入文件的许可,包括附加。与read许可类似,write许可包括了随机访问写,当一个文件被映像到内存中时,也会检查read和write许可,例如:mmap(2)系统调用,或使用mprotect(2)系统调用保护现有映像被改变。
execute许可使用execve(2)系统调用控制执行文件的能力,不管有没有域转换(参考下面的exec_no_trans),它都是必需要有的,execute许可在成功使用一个文件作为共享库时也是必需的。
3.1.2 标准Linux访问控制的扩展
SELinux的一个好处就是它提供了额外的许可,可以更细粒度地进行控制。
在标准Linux中,创建文件的能力受到写入容纳该文件的目录的权限限制,在SELinux中,create许可直接控制创建每个特定SELinux类型文件的能力,使用这个许可,我们可以允许一个域类型创建etc_t类型的文件,而不是shadow_t类型,与SELinux中的大多数许可类似,文件create许可是必需的,但并不充分,例如:创建域类型也必须要有权在dir客体中创建客体,并且要有创建file客体的许可,我们可能需要write许可。
最后的文件扩展许可是mounton,quotaon和swapon。mounton许可控制使用文件作为一个挂载点的能力(mount(2)系统调用),更常见的是使用目录作为一个挂载点,然而,在执行绑定挂载时(MS_BIND),可以使用文件作为挂载点。quotaon许可控制存储限额信息,当使用quotactl(2)系统调用(q_quotaon)开启限额时,存储限额信息的文件的路径就确定了,调用进程域类型必须要有那个文件的quotaon许可,才能成功完成系统调用。
3.1.3 SELinux特定许可
对于文件而言有五种SELinux特定许可:relabelfrom,relabelto,execute_no_trans,enTRypoint和execmod。
relabelfrom和relabelto许可控制域类型将文件从一个类型改为另一个类型的能力,为了使重新标记文件成功,域类型必须要有该文件客体当前类型的relabelfrom许可,并且还要有新类型的relabelto许可,注意这些许可不允许控制确切的许可对,域可以将它有relabelfrom许可的任何类型改为它有relabelto许可的任何类型,在重新标记时可以增加约束。
execute_no_trans许可允许域执行一个无域转换的文件,这个许可还不够执行一个文件,还需要execute许可,没有execute_no_trans许可,进程可能只能在一个域内执行,如果我们想要确保一个执行过程总是会引发一个域转换(或失败)时,此时就会想要排除execute_no_trans许可,例如:当登陆进程为一个用户登陆执行一个shell时,我们总是想要shell进程从有特权的登陆域类型转移出来。
entrypoint许可控制使用可执行文件允许域转换的能力,execute,execute_no_trans和entrypoint许可允许精确控制什么代码可以执行什么域类型,SELinux控制各个程序域类型的能力是它能够提供强壮灵活的安全的主要原因。
execmod许可控制执行在进程内存中已经被修改了的内存映像文件的能力,这在防止共享库被另一个进程修改时非常有用,没有这个许可时,如果一个内存映像文件在内存中已经被修改了,进程就不能再执行这个文件了。
3.2 进程客体类别许可
下表列出了进程客体类别许可,与文件许可不同,许多进程许可没有直接对应到标准的Linux访问控制,因为传统的Linux没有将进程作为一个正式的客体对待。
process许可
|
描述
|
分类
|
fork
|
派生两个进程
|
创建进程
|
transition
|
通过execve(2)系统调用转换到一个新的上下文(域类型)
|
进程域类型转换
|
sigchld
|
发送sigchld信号
|
进程信号
|
sigkill
|
发送sigkill信号
|
进程信号
|
sigstop
|
发送sigstop信号
|
进程信号
|
signull
|
不发送信号测试另一个进程的存在性
|
进程信号
|
signal
|
发送一个非sigkill,sigstop或sigchld的信号
|
进程信号
|
ptrace
|
跟踪程序执行的父进程或子进程
|
|
getsched
|
获取进程的优先级
|
进程属性
|
setsched
|
设置进程的优先级
|
进程属性
|
getsession
|
获取进程的会话ID
|
进程属性
|
getpgid
|
获取进程的组进程ID
|
进程属性
|
setpgid
|
设置进程的组进程ID
|
进程属性
|
getcap
|
获取这个进程允许的Linux能力
|
进程属性
|
setcap
|
为进程设置允许的Linux能力
|
进程属性
|
share
|
允许与克隆的或派生的进程共享状态
|
创建进程
|
getattr
|
通过/proc/[pid]/attr/目录获取进程的属性
|
|
setexec
|
下一次调用execve(2)时覆盖默认的上下文
|
|
setfscreate
|
允许进程设置由其创建的客体的上下文
|
|
noatsecure
|
禁用清除安全模式环境,允许进程在execve(2)上禁用glibc的安全模式特性
|
进程域类型转换
|
siginh
|
在execve(2)上继承信号状态
|
创建进程
|
setrlimit
|
改变进程硬性资源限制
|
|
rlimitinh
|
在execve(2上)继承进程资源限制
|
创建进程
|
dyntransition
|
允许进程动态地转移到新的上下文中
|
进程域类型转换
|
setcurrent
|
设置当前的进程上下文,当进程试图执行一个动态域转换时,这是第一个检查的能力
|
|
execmem
|
产生一个匿名的映像或可写的私有文件映像可执行体
|
执行可写入内存
|
execstack
|
产生进程堆栈可执行体
|
执行可写入内存
|
execheap
|
产生一个堆栈可执行体
|
执行可写入内存
|
setkeycreate
|
|
|
setsockcreate
|
|
|
3.2.1 创建进程
fork许可控制进程使用fork(2)系统调用的能力,这个系统调用创建一个进程的副本,只是进程标识符和资源利用数据有所不同,派生进程的安全上下文不能改变,通常,执行一个新程序的第一步就是派生,控制进程派生的能力,限制它使用系统资源的能力,可以潜在地预防某些类型的拒绝服务攻击。
三个其它的许可在进程转换时控制状态的共享,share许可控制进程状态的共享,如在一个execve(2)系统调用上的文件描述符和内存地址空间,siginh许可控制信号状态的继承,包括任意挂起的信号,最后,rlimitnh许可控制从父进程那里继承的资源限制。
3.2.2 进程域类型转换
transition许可控制进程通过execve(2)系统调用从一个域转到另一个域的能力,如果允许,域转换或明确地请求时可能会自动产生一个type_transition规则,请求明确的域转换的能力是由setexec许可控制的,这个请求会往proc文件系统中写一个特定的文件,这个过程在setexeccon(3)库函数中被抽象出来,为下一个请求execve(2)系统调用查看当前请求的转换的能力是由getattr许可控制的。
noatsecure许可使内核在进行域转换时不设置glibc的安全模式,在安全模式下,glibc清除进程环境,包括相当多的环境变量,如LD_PRELOAD,如果不清除环境,源域可能会控制目标域的关键部分,当域转换进入更高特权域时,允许noatsecure许可是特别危险的。
dyntransition许可与转换许可类似,但它是控制进程在任何时间改变域类型的能力,不仅仅是执行程序那一刻,这个许可比transition许可更危险,因为它允许起始域在新域中执行任意的代码,由于这个原因,dyntransition许可只有在目标域是起始域的一个受限的子集时可以安全地使用,否则,想要理解域改变的保护就会失败,所有授予目标域的访问权对起始域都必须要能够可访问。
3.2.3 创建文件
与域转换类似,与文件有关的客体的安全上下文设置可以通过继承或type_transition规则进行自动创建,也可以明确地创建,通过在proc文件系统中写入一个特定的文件实现与文件有关的客体的安全上下文的设置,这个过程抽象在setfscreatecon(3)库调用中,setfscreate许可控制产生这个明确请求的能力,与setexeccon类似,查看文件系统客体上下文请求的当前状态是由getattr许可控制的。
3.2.4 进程信号
向进程发送信号的权力非常大,因为它可能允许结束或停止进程,此外,信号可以用于在进程间传输信息,sigchld,sigkill和sigstop许可分别控制发送SIGCHLD,SIGKILL和SIGSTOP信号的能力,signull许可控制发送空信号的能力,例如:通过传递一个0字符作为一个信号参数给kill(2)系统调用,最后,signal许可控制发送其它信号的能力。
为什么有的信号有明确的许可定义,而剩下的都在常见的signal许可控制之下呢?有两个原因,SIGKILL和SIGSTOP这两个信号有明确的许可,因为它们不能由进程阻碍,SIGCHLD信号有它自己的许可主要是因为它是被正式使用的(如它经常是每个进程init时使用),剩下的安全属性都相同,因此它们都由signall许可控制。
3.2.5 进程属性
查询或设置调度优先级以及进程策略的能力是由getsched和setched许可控制的,设置调度优先级和策略,特别是设置SCHED_FIFO策略,使用sched_setscheduler(2)系统调用可以允许进程不受限制占用CPU时间,因此,它可以用于拒绝服务攻击。
进程组和会话标识符控制大部分进程的交互,包括终端处理和信号传递,getpgid和setpgid许可控制查询和设置进程组标识符,getsession许可控制进程标识符的查询。
getcap和setcap许可控制查询和设置进程的Linux许可,要成功设置一个许可,这个许可也必须被标记了域类型的capability客体类别接受。
资源限制,如核心转储的最大大小或CPU时间的最大大小,都是使用setrlimit(2)系统调用,setrlimit许可控制设置硬性资源限制的能力。
3.2.6 执行可写入内存
正如在file客体类别的execmod许可中讨论的那样,执行可写入内存段的能力是许多安全事件的起源,为了帮助标记出这些事件,首先创建execmem,execstack和execheap许可,它们分别控制可执行的匿名映像、堆栈和堆的创建,许可的执行依赖于另外的软件,如ExecShied,硬件特性,如NX。
ExecShied是Red Hat开发的内核补丁,控制内存执行,并添加了其它安全特性,它包括在所有的Fedora Core和自Red HatEnterprise Linux 3以来的版本中。NX是一个硬件设置,它实现了许多ExecShied相同的目标。
4. 小结
客体类别和许可是SELinux中访问控制的基础,它们是策略语言和内核中访问实施机制的一部分。
客体类别代表资源,如文件、进程、目录和套接字,每种系统资源都对应着一个客体类别。
许可代表对系统资源的访问权,每个客体类别都有一套定义好的许可,叫做访问向量。
客体类别使用类别声明语句(class)进行声明。
使用访问向量语句(也是class)将许可与客体类别进行关联。
SELinux中定义了两类许可:通用许可和特定类别许可。
通用许可是一套由多个客体类别共享的许可集,使用访问向量语句将它们与客体类别作为一个组进行关联。
SELinux提供客体类别和许可精确地覆盖了所有的系统资源,在FC 4中,有超过40个客体类别,反映了Linux的丰富和复杂。
理解所有的客体类别和许可需要深入理解SELinux和Linux。在Linux中允许访问完成多个任务需要一个或多个客体类别的多个许可。