SeLinux全称为安全增强式 Security-Enhanced Linux(SeLinux),是一个在内核的强制存取控制(MAC)安全性机制。SeLinux的整体架构和原理都比较简单,使用也不复杂,其复杂的地方在于规则非常复杂,每个进程都要有规则策略;
图片来源:https://www.cnblogs.com/klb561/p/14411953.html
SeLinux 遵从最小权限的理念,在开启SeLinux的情况下(enforcing 模式),所有访问默认是被拒绝的,而有一系列例外的策略来允许系统的元素(服务、进程、用户)具备访问资源的权限,例外的策略通过类型强制描述文件进行描述。不同于基于用户和角色的权限访问控制,Selinux的规则可以做到,与用户/角色没有关系,策略针对每一个可运行的进程进行配置,很好的避免了越权访问的问题,但正因为麻烦,所以很多服务器上默认是关闭了Selinux配置;
Linux内核提供了一个安全模块框架层,这个公共框架类似于文件系统中的VFS。它为调用者提供统一的接口。之所以要提供统一接口是因为Linux内核不仅仅支持SELinux安全特性,还支持Apparmor等很多安全特性。以打开文件为例,当我们调用内核中打开文件的接口是,在其内部会调用security_file_open函数。该函数就是Linux内核安全框架(LSM)的公共接口。然后该函数通过函数指针的方式调用所有注册到LSM的安全模块。以SELinux为例,最终会调用到selinux_file_open函数。
图片来源:https://www.cnblogs.com/klb561/p/14411953.html
TE: TYPE ENFORECE 规则 类型强制策略;
用来描述SeLinux规则的文件就是TE文件,TE 规则是将权限与程序的访问结合在一起;
一个简单的 AV 规则有:
规则名称,源类型,目标类型,客体类别和许可操作,如:
allow user_t bin_t : file execute;
这个 allow 规则的源类型为 user_t,目标类型为 bin_t,客体类别 file,许可 execute,这个规则可以解读为"允许 user_t 执行类型为 bin_t 的文件"。
规则名称包括:
allow 表示允许主体对客体执行允许的操作。
dontaudit 表示不记录违反规则的决策信息,且违反规则不影响运行。
auditallow 表示允许操作并记录访问决策信息。
neverallow 表示不允许主体对客体执行指定的操作
如auditallow 规则,只需要替换掉规则名称即可:
auditallow user_t bin_t : file execute;
源类型通常是进程名,目标类型则是操作的客体类别
|-------------------------|-------------------------------|--------------------------------------------| | 与文件有关的客体类别 | blk_file | 块文件 | | | che_file | 字符文件 | | | dir | 目录 | | | fd | 文件描述符 | | | fifo_file | 命名管道 | | | file | 普通文件 | | | filesystem | 文件系统(如一个真实的分区) | | | lnk_file | 符号链接 | | | sock_file | UNIX域套接字 | | | | | | 与网络有关的客体类别 | | | | | association | IPSec安全联盟 | | | key_socket | PF_KEY协议家族的套接字、用于管理IPSec中的密钥 | | | netif | 网络接口 如eth0 | | | netlink_audit_socket | 用于控制审核的Netlink套接字 | | | netlink_dnrt_socket | 用于控制DECnet路由的Netlink套接字 | | | netlink_firewall_socket | 用于创建用户空间防火墙过滤器的Netlink套接字 | | | netlink_ip6fw_socket | 用于创建用户空间防火墙过滤器的Netlink套接字 | | | netlink_kobject_uevent_socket | 用于创建用户空间接收内核事件通知的Netlink套接字 | | | netlink_route_socket | 用于控制和管理网络资源如路由表和IP地址的Netlink套接字 | | | netlink_selinux_socket | 用于接收策略载入通知,强制模式切换和清空AVC缓存的Netlink套接字 | | | netlink_tcpdiag_socket | 用于监视TCP连接的Netlink套接字 | | | netlink_soecket | 所有其它的Netlink套接字 | | | netlink_xfrm_socket | 用于获取、管理和设置 IPsec 参数的 | | | Netlink | 套接字 | | | node | 代表一个 IP 地址或一段 IP 地址的主机 | | | packet_socket | 协议在用户空间执行的原始套接字 | | | rawip_socket | 既不是 TCP 也不是 UDP 的 IP 套接字 | | | tcp_socket | TCP 套接字 | | | udp_socket | UDP 套接字 | | | unix_dgram_socket | 本地机器上(unix 域)的 IPC 数据报套接字 | | | unix_stream_socket | 本地机器上(unix 域)的 IPC 流套接字 | | IPC有关的客体类别 | ipc | 已经没有使用了 | | | msg | 消息队列中的消息 | | | msgq | 消息队列 | | | sem | 信号量 | | | shm | 共享内存段 | | 其它杂类客体类别 | capability | Linux中标识权利的特权 | | | process | Selinux中的进程 | | | security | 内核中的Selinux安全服务器 | | | system | 整个系统 | | | | | | 文件客体类别 | file | | | | append | 附加到文件内容(即用 o_append 标记打开) | | | create | 创建一个新文件 | | | entrypoint* | 通过域转换,可以用作新域的入口点的文件 | | | execmod* | 使被修改过的文件可执行(含有写时复制的意思) | | | execute | 执行,与标准 Linux 下的 x 访问权一致 | | | execute_no_trans* | 在访问者域转换的执行文件(即没有域转换) | | | ioctl | ioctl(2)系统调用请求 | | | link | 创建一个硬链接 | | | lock | 设置和清除文件锁 | | | mounton | 用作挂载点 | | | quotaon | 允许文件用作一个限额数据库 | | | swapon | 不赞成使用。它用于将文件当做换页/交换空间 | | | relabelfrom | 从现有类型改变安全上下文 | | | relabelto | 改变新类型的安全上下文 | | | rename | 重命名一个硬链接 | | | setattr | 改变文件的属性,如访问模式(例如:chmod,部分 ioctls) | | | getattr | 获取文件的属性,如访问模式(例如:stat,部分ioctls) | | | unlink | 移除硬链接(删除) | | | write | 写入文件内容,对应标准 Linux 下的 w 访问权 | | | read | 读取文件内容,对应标准 Linux 下的 r 访问权 | | | | | | | | | | 进程许可类别 | dyntransition | 允许进程动态地转移到新的上下文中 | | process | execheap | 产生一个堆栈可执行体 | | {read.execute, getattr} | execmem | 产生一个匿名的映像、堆栈和堆的创建,或可写的私有文件映像可执行体 | | | execstack | 产生进程堆栈可执行体 | | | fork | 派生两个进程 | | | getattr | 通过/proc/[pid]/attr/目录获取进程的属性 | | | setcap | 为进程设置允许的 Linux 能力 | | | getcap | 获取这个进程允许的 Linux 能力 | | | setpgid | 设置进程的组进程 ID | | | getpgid | 获取进程的组进程 ID | | | setsched | 设置进程的优先级 | | | getsched | 获取进程的优先级 | | | getsession | 获取进程的会话 ID | | | noatsecure | 禁用清除安全模式环境,允许进程在 execve(2)上禁用glibc 的安全模式特性 | | | ptrace | 跟踪程序执行的父进程或子进程 | | | rlimitnh | 在 execve(2 上)继承进程资源限制 | | | setcurrent | 设置当前的进程上下文,当进程试图执行一个动态域转换时,这是第一个检查的能力 | | | setexec | 下一次调用 execve(2)时覆盖默认的上下文 | | | setfscreate | 允许进程设置由其创建的客体的上下文 | | | setrlimit | 改变进程硬性资源限制 | | | share | 允许与克隆的或派生的进程共享状态 | | | siginh | 在 execve(2)上继承信号状态 | | | sigkill | 发送 sigkill 信号 | | | sigchld | 发送 sigchld 信号 | | | signal | 发送一个非 sigkill,sigstop 或 sigchld 的信号 | | | signull | 不发送信号测试另一个进程的存在性 | | | sigstop | 发送 sigstop 信号 | | | transition | 在 execve(2)上转换到一个新的上下文 |
特殊类型 self
策略语言保留了一个关键字 self,它用于 AV 规则中的目标区域,可以当做一个类型使
用,如下面这两条规则是相等的:
这两条规则是相等的
allow user_t user_t : process signal;
allow user_t self : process signal
2021/07/22更新:Android系统对Selinux的配置,关键搞清楚如何配置新增进程的规则:
SELinux 依靠标签来匹配操作和政策。标签用于决定允许的事项。套接字、文件和进程在 SELinux 中都有标签。
SELinux 在做决定时需参照两点:
一是为这些对象分配的标签;
二是定义这些对象如何交互的政策;
标签采用以下形式表示:user:role:type:mls_level,其中 type 是访问决定的主要组成部分,可通过构成标签的其他组成部分进行修改。对象会映射到类,对每个类的不同访问类型由权限表示。
域(domain):一个进程或一组进程的标签。也称为域类型,因为它只是指进程的类型。
域的声明使用
type backup_t;
政策规则采用以下形式:
allow domains types:classes permissions;,其中:
domains - 一个进程或一组进程的标签。也称为域类型,因为它只是指进程的类型。
types - 一个对象(例如,文件、套接字)或一组对象的标签。
classes - 要访问的对象(例如,文件、套接字)的类型。
permissions- 要执行的操作(例如,读取、写入)。
使用政策规则时将遵循的结构示例:
allow appdomain app_data_file:file rw_file_perms;
表示所有应用域都可以读取和写入带有 app_data_file 标签的文件。请注意,该规则依赖于在 global_macros 文件中定义的宏,您还可以在 te_macros 文件中找到一些其他非常实用的宏。
可以通过属性引用一组域或类型。简单来说,属性是一组域或类型的名称。每个域或类型都可以与任意数量的属性相关联。当编写的规则指定了某个属性名称时,该名称会自动扩展为列出与该属性关联的所有域或类型。例如,domain 属性与所有进程域相关联,file_type 属性与所有文件类型相关联。
属性与类型关联
type http_user_content_t,file_type;
type httpd_user_content_t, file_type, httpdcontent;
typeattribute 语句,这个语句允许我们在声明类型时单独关联属性
#下面是两条语句
type httpd_user_content_t;
typeattribute httpd_user_content_t file_type,
httpdcontent;
参考:https://www.cnblogs.com/klb561/p/14411953.html
2021/08/31更新
策略文件的加载,核心就是通过security_load_policy接口,对用户空间传进来的te镜像文件进行解析并加载(见:https://blog.csdn.net/bruk_spp/article/details/107283935)
init进程上下文的恢复,selinux.cpp的SetupSelinux方法中会执行selinux_android_restorecon
--
avc:access vector cache,用来缓存MAC访问控制策略,在进行策略检查的时候,先到avc中进行检查,如果没有找到,则进行根据安全上下文进行计算,将结果缓存到AVC中:
security/selinux/avc.c
struct avc_entry {
u32ssid;
u32tsid;
u16tclass;
struct av_decisionavd;
struct avc_xperms_node*xp_node;
};
ssid怎么来的:
security/selinux/ss/mls.c
int mls_context_to_sid(struct policydb *pol,
char oldc,
char **scontext,
struct context *context,
struct sidtab *s,
u32 def_sid);
void mls_sid_to_context(struct policydb *p,
struct context *context,
char **scontext);