SELinux 安全模型——TE

SELinux 安全模型——TE

首发公号:Rand_cs
通过前面的示例策略,大家对 SELinux 应该有那么点感觉认识了,从这篇开始的三篇文章讲述 SELinux 的三种安全模型,会涉及一些代码,旨在叙述 SELinux 内部的原理

SELinux 提供了 3 种安全模型:

RBAC:Role Based Access Control<基于角色的权限访问控制,它根据用户的角色和职责来管理对系统资源的访问权限。RBAC 将用户分配到不同的角色中,每个角色被赋予一组特定的权限,用户通过被分配到相应的角色来获得相应的权限,从而实现对系统资源的安全访问和管理。

TE:Type Enforcement,SELinux 最主要的安全模型,每一个主体客体都被分配一个类型,且使用白名单策略决定指定类型之间的访问权限。

MLS:Multi-Level Security,用于保护敏感和机密信息。这是 SELinux 对 BLP(Bell-La Padula Model) 模型的实现,编写策略可实现 “no read up, no write down”

本篇文章讲述 SELinux 最重要的安全模型:TE,Type Enforcement,针对类型的一种强制访问控制模式。

两种规则及其数据结构

它是 SELinux 的基石,百分之九十九的规则都是建立在 TE 之上的。TE 这种安全模型主要有两种规则,在之前示例策略种也说过,本文再来复习一遍:

  • Access Vector Rules,简单理解为 allow、neverallow、dontaudit 这些规则属于 AV 规则。其语法为 allow source target : class { perms },表示 source 对 class 类别的 target 的访问权限。
  • Type Rules,这类规则涉及类型转换,总共有 3 个,type_transition、type_change、type_member,后两个先不用管,重点知道 type_transion 就行。其语法规则为 allow a_t b_exec_t : process b_t,表示 a_t 这个类型的进程执行 b_exec_t 这个类型的可执行程序后,类型转换为 b_t。

虽然 TE 分为两大类规则,但是从形式上来讲,它们是统一的,都是 规则名 源类型 目标类型 目标类别 权限/转换后类型,可以看出,只有最后一部分是不一样的。但终归形式统一,所以在内存种这两大类规则对应的数据结构都是一样的。

我们可以将前面部分当作 key,最后的权限/转换后类型当作 value,如此,所有的 TE 规则实际上都以键值对存放在内存当中。

struct avtab_key {u16 source_type;    /* source type */u16 target_type;    /* target type */u16 target_class;   /* target object class */
#define AVTAB_ALLOWED       0x0001
#define AVTAB_AUDITALLOW    0x0002
#define AVTAB_AUDITDENY     0x0004
#define AVTAB_AV        (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY)
#define AVTAB_TRANSITION    0x0010
#define AVTAB_MEMBER        0x0020
#define AVTAB_CHANGE        0x0040
#define AVTAB_TYPE      (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
/* extended permissions */
#define AVTAB_XPERMS_ALLOWED    0x0100
#define AVTAB_XPERMS_AUDITALLOW 0x0200
#define AVTAB_XPERMS_DONTAUDIT  0x0400
#define AVTAB_XPERMS        (AVTAB_XPERMS_ALLOWED | \AVTAB_XPERMS_AUDITALLOW | \AVTAB_XPERMS_DONTAUDIT)
#define AVTAB_ENABLED_OLD   0x80000000 /* reserved for used in cond_avtab */
#define AVTAB_ENABLED       0x8000 /* reserved for used in cond_avtab */u16 specified;  /* what field is specified */
};

上述为 key 值定义,可以看出 类型 type,类别 class 在内存中都是一个 16 位的无符号整数,可以看作它们的 ID 值,所以理论上来说最多只能定义 65535 个类型。

specified 指明当前是哪种具体的 TE 规则

struct avtab_datum {union {u32 data; /* access vector or type value */struct avtab_extended_perms *xperms;} u;
};

key 值对应的数据如上所示,只有一个元素 32 bit 无符号,扩展属性暂时不用了解,基本没人用

对于 AV 规则,data 为一组权限向量,比如说:

#define FILE__IOCTL                               0x00000001UL
#define FILE__READ                                0x00000002UL
#define FILE__WRITE                               0x00000004UL
#define FILE__CREATE                              0x00000008UL
#define FILE__GETATTR                             0x00000010UL
#define FILE__SETATTR                             0x00000020UL
#define FILE__LOCK                                0x00000040UL
.......

上述是 file 这个类别的权限位定义,在内核里面搜索会发现并没有上述定义,这些宏是内核编译的时候自动生成的,生成脚本对应着 linux/scripts/selinux/genheaders

上述可以看出,每个权限都是 32 bit 中的某一位, data 中某一比特位为 1 表示拥有该权限,为 0 表示没有该权限权限。举个例子,如果存在规则 allow a_t b_file_t : file read; 那么当查询 a_t 类型的进程 对 b_file_t 类型的文件有什么访问权限时,返回结果 data 值中对应 FILE__READ 那个比特位应该为 1

对于 Type 规则,也就是类型转换类的规则,data 表示转换后类型的 ID 值

AVC

TE 规则当中又数 AV 规则使用的最频繁,为了加快查找速度,内核设计了 AVC,Access Vector Cache。

struct avc_entry {u32         ssid;u32         tsid;u16         tclass;struct av_decision  avd;struct avc_xperms_node  *xp_node;
};struct avc_node {struct avc_entry    ae;struct hlist_node   list; /* anchored in avc_cache->slots[i] */struct rcu_head     rhead;
};struct avc_cache {struct hlist_head   slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */spinlock_t      slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */atomic_t        lru_hint;   /* LRU hint for reclaim scan */atomic_t        active_nodes;u32         latest_notif;   /* latest revocation notification */
};

整个 cache 就是一个哈希表,由 avc_node 组成,每个 avc_node 又由 key 值(ssid, tsid, tclass)和 value(avd) 组成。

这里的 key 值有三个,ssid、tsid、tclass,我们对哈希表增删查改需要的 hash 值也是由这三个值算出来。sid,全称 security id,对于 sid 后面会详细讲述,这里先简单说一说。之前有提到过,在 SELinux 中,每个主体和客体都有一个安全上下文(标签),由 4 部分组成(user:role:type:mls),内核中由 struct context 来表示,而 sid 则是与 context 对应的一个 id 值,context 和 sid 一一对应

value 值为 av_decision,其结构体表示如下:

struct av_decision {u32 allowed;      u32 auditallow;u32 auditdeny;u32 seqno;u32 flags;
};

AV 规则有 4 种语句,allow,auditallow,dontaudit,neverallow,前三个与上述的定义对应,最后一个 neverallow 语句是在编译期间起作用,所以内核没有相关定义

对于每一种 AV 规则,内核都定义了一组权限向量,但其实只有 allowed 对应的向量才表示权限授予与否,其他的都是指示当前访问是否应该被日志记录。

比如说对于 FILE__WRITE,如果在 allowed 中对应的比特位为 0,表示没有权限写;如果在 auditdeny 中对应的比特位为 1,即使在 allowed 中表示没有权限写,但是也不会记录在日志中。

上述就是对 AVC 涉及的数据结构进行介绍,其他一些函数大多是哈希表常见的增删改查函数,这里不做详细说明,可以自己阅读相关内核代码,比较简单。这里主要说明权限检查函数,avc_has_perm。

int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,u32 requested, struct common_audit_data *auditdata)
{//将存放权限查询结果struct av_decision avd; int rc, rc2;//调用此函数来进行真正的权限查询,查询结果存放在 avd 中rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0,&avd);//日志记录相关rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc,auditdata);if (rc2)return rc2;return rc;
}inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,u16 tclass, u32 requested,unsigned int flags,struct av_decision *avd)
{u32 denied;struct avc_node *node;if (WARN_ON(!requested))return -EACCES;rcu_read_lock();// 根据键值在 avb 中查询 avd_nodenode = avc_lookup(ssid, tsid, tclass);// 如果 node 不存在,则会去查询 security server,然后分配 node,填充node,插入哈希表等操作if (unlikely(!node)) {rcu_read_unlock();return avc_perm_nonode(ssid, tsid, tclass, requested,flags, avd);}// ae.avd.allowed 记录着allowed权限向量,request 表示要查询权限对应的比特位// 一通位操作下来,denied 为 1 表示没有该权限,反之有该权限denied = requested & ~node->ae.avd.allowed;memcpy(avd, &node->ae.avd, sizeof(*avd));rcu_read_unlock();// 一般不太可能为 denied,这么想,如果一个系统的 denied 很多,多半策略有问题,而且系统也不能正常运行// 如果为 denied=1,则 SELinux 还有其他配置让它变为 allowed,比如说如果当前开启了 permissive 模式// 所以这里还需要调用 avc_denied 再次判断当前模式、策略下是否真的没有该权限if (unlikely(denied))return avc_denied(ssid, tsid, tclass, requested, 0, 0,flags, avd);// 返回 0 表示有权限return 0;
}

举个栗子

这一小节用两个例子说明内核里面到底是如何进行 SELinux 权限检查和类型转换的

假如我们正在执行某个 exec 调用,需要检查当前进程是否对该文件有执行权限。内核里面是如何做检查的呢?首先是 DAC 检查,也就是检查是该文件是否有 x 权限位。

当我们访问文件的时候,内核里面经常会调用 inode_permission(idmap, inode, mask) 检查权限。比如说这里想要检查是否有 exec 权限,便会调用inode_permission(idmap, nd->inode, MAY_EXEC);之后会存在如下的调用路径:

inode_permissionsecurity_inode_permissionselinux_inode_permission//将想要查询的权限用 SELinux 中的向量表示file_mask_to_av// 这里的mode就是inode中的mode元素,作用之一就是指示当前文件类型if (!S_ISDIR(mode)){    // mask 可以看作上层想要查询的权限,之后转换为SELinux中对应的权限if (mask & MAY_EXEC)av |= FILE__EXECUTE;} else {//如果访问的是目录,想要检查是否有 exec 权限,那么实际上是想要检查是否有搜索权限if (mask & MAY_EXEC)  av |= DIR__SEARCH;return av// 调用 avc_has_perm 来查询权限,查询结果存放在 &avd 结构中avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0, &avd);

在 SELinux 中,对于目录和文件的执行权限有不同解释,对于普通文件,那就是真的检查是否可执行。但是对于目录文件来说检查是否能够执行其实指的是能否对该目录进行搜索。

其实在 DAC 中,对于目录和普通文件的 x 权限位解释也是不一样的,一个文件如果有 x,说明该文件可以被执行,如果一个目录有 x,指的是可以进入这个目录, 通俗来讲可以 cd 进去,就需要该目录有 x 权限。

我们上层的种种操作,其背后都需要各种权限,在 SELinux 安全检查的时候都会进行 SELinux 权限检查。

对于类型转换的流程,例子先不说了,这玩意儿还有点点复杂,后面单独来一篇文章说明,好了本文就先到这里,有什么问题欢迎来交流讨论
首发公号:Rand_cs

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/590482.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

matplotlib范围曲线简例

想在画&#xff08;平均&#xff09;loss 曲线时顺便表示方差&#xff0c;即每一个 epoch 的平均 loss 用 plot 画曲线&#xff0c;而在曲线周围用一个浅色区域表示方差。效果&#xff1a; 参考 [1-3]&#xff0c;用到 matplotlib.pyplot.fill_between 函数。为显示对浅色区及…

不吹不黑,辩证看待开发者是否需要入坑鸿蒙

前言 自打华为2019年发布鸿蒙操作系统以来&#xff0c;网上各种声音百家争鸣。尤其是2023年发布会公布的鸿蒙4.0宣称不再支持Android&#xff0c;更激烈的讨论随之而来。 本文没有宏大的叙事&#xff0c;只有基于现实的考量。 通过本文&#xff0c;你将了解到&#xff1a; Har…

Python列表推导式(for表达式)及用法

for 表达式&#xff08;列表推导式&#xff09;用于利用其他区间、元组、列表等可迭代对象创建新的列表。 for 表达式的语法格式如下&#xff1a; [表达式 for 循环计数器 in 可迭代对象] 从上面的语法格式可以看出&#xff0c;for 表达式与普通 for 循环的区别有以下两点&a…

【C++】基于C++11的线程池:threadpool

1、参考 作者博客&#xff1a;https://www.cnblogs.com/lzpong/p/6397997.html 源码&#xff1a;https://github.com/lzpong/threadpool 2、源码 原理&#xff1a;利用生产者-消费者模型&#xff0c;管理一个任务队列&#xff0c;一个线程队列&#xff0c;然后每次取一个任务…

什么是JavaScript

文章目录 一、❄️什么是JavaScript&#xff1f;二、❄️JavaScript的特点三、❄️JavaScript的组成&#x1f9eb;1、核心&#xff08;ECMAScript&#xff09;&#x1f9ff;2、文档对象模型&#xff08;DOM&#xff09;&#x1f94f;3、浏览器对象模型&#xff08;BOM&#xff…

深入理解MySQL索引底层数据结构

听课问题(听完课自己查资料) 什么是二叉树 二叉树是怎么存储数据的一个链表是一个集合的数据结构 List是怎么便利找到指定下标元素为什么会快&#xff1f;什么是红黑树 红黑树是怎么存储数据的什么是B TREE 是怎么存储数据的什么是BTREE 是怎么存储数据的 疑惑答案 a. 二叉树…

SQL性能优化-索引

1.性能下降sql慢执行时间长等待时间长常见原因 1&#xff09;索引失效 索引分为单索、复合索引。 四种创建索引方式 create index index_name on user (name); create index index_name_2 on user(id,name,email); 2&#xff09;查询语句较烂 3&#xff09;关联查询太多join&a…

【力扣100】【好题】200.岛屿数量

添加链接描述 解法一&#xff1a;dfs class Solution:def numIslands(self, grid: List[List[str]]) -> int:# 思路是dfs&#xff0c;使用一个指针遍历元素&#xff0c;如果找到1&#xff0c;就递归把跟这个1连着的1都变成0&#xff0c;用result记录结果if not grid or le…

如何学习TS?

文章目录 一. 8种内置基础类型.ts二. void、never、any、unknown类型void类型never类型any类型unknown类型总结&#xff1a;void和any在项目中是比较常见的&#xff0c;never和unknown不常用。 三. 数组和函数类型定义.ts四. 元组与交叉类型使用元组数组一般有同类型的值组成&a…

AutoSAR(基础入门篇)4.9-Autoar_BSW小结

Autoar_BSW小结 Autoar_BSW小结 一、Autoar_BSW小结 1、BSW组件图 2、BSW的功能概述 3、BSW在工程里的应用实际工程

ubuntu 20.04 自由切换 python 的版本

问题描述 当前 ubuntu 20.04 默认安装了多个 python 的版本&#xff0c;执行 python 时&#xff0c;默认版本是 Python 2.7.18 zhangszzhangsz:~$ python Python 2.7.18 (default, Jul 1 2022, 12:27:04) [GCC 9.4.0] on linux2 Type "help", "copyright&quo…

url编码未转义导致参数丢失

原来的请求&#xff1a; "&url${ctx}/loanform/risk/loanItemRiskItemReport/main.ht?baseProductType${baseProductType}""&itemReportId"itemReportId修改后&#xff1a; 原因&#xff1a;请求地址拼接时&#xff0c;会判断name为url的属性是…

多模态大模型的前世今生

1 引言 前段时间 ChatGPT 进行了一轮重大更新&#xff1a;多模态上线&#xff0c;能说话&#xff0c;会看图&#xff01;微软发了一篇长达 166 页的 GPT-4V 测评论文&#xff0c;一时间又带起了一阵多模态的热议&#xff0c;随后像是 LLaVA-1.5、CogVLM、MiniGPT-5 等研究工作…

什么是IDE?新手用哪个IDE比较好?

什么是 IDE&#xff1f; IDE&#xff08;Integrated Development Environment&#xff0c;集成开发环境&#xff09;是提供给程序员用来编写代码的软件应用程序。一个 IDE 通常包含以下组件&#xff1a; 代码编辑器&#xff1a;支持编写和编辑源代码的文本编辑器。 编译器或解…

Impala4.x源码阅读笔记(三)——Impala如何管理Iceberg表元数据

前言 本文为笔者个人阅读Apache Impala源码时的笔记&#xff0c;仅代表我个人对代码的理解&#xff0c;个人水平有限&#xff0c;文章可能存在理解错误、遗漏或者过时之处。如果有任何错误或者有更好的见解&#xff0c;欢迎指正。 上一篇文章Impala4.x源码阅读笔记&#xff0…

simulink代码生成(五)——ePWM模块初级应用

前面分别讲到了SCI及ADC的配置及使用&#xff0c;现在梳理一下ePWM的配置和使用&#xff1b; 先打一些基础的DSP28335的基础知识&#xff1b; F28335 关于ePWM中断与SOC采样信号的一些思考_socasel-CSDN博客 F28335 ePWM模块简介——TMS320F28335学习笔记&#xff08;四&…

【虹科分享】利用ProfiShark 构建便携式网络取证工具包

文章速览&#xff1a; 为什么要使用便携式网络取证工具&#xff1f;构建便携式网络取证套件法证分析ProfiShark 1G作为便携式分路器的优点 网络安全领域日益重视便携式取证工具的灵活应用。本文介绍了如何构建一个以ProfiShark 1G为核心的便携式网络取证工具包&#xff0c;以提…

YHZ011 Python 显式类型转换

资源编号&#xff1a;YHZ011 配套视频&#xff1a;https://www.bilibili.com/video/BV1zy4y1Z7nk?p12 &#x1f981; 显式类型转换 在显式类型转换中&#xff0c;用户将对象的数据类型转换为所需的数据类型。 我们使用 int()、float()、str() 等预定义函数来执行显式类型转换…

软件开发必知必会的计算机基础

1.计算机基本介绍 1.1 什么是计算机 计算机(Computer)俗称为电脑&#xff0c;计算机是一种高速计算的电子机器&#xff0c;计算机可以进行数值运算&#xff0c;逻辑判断&#xff0c;接收或者是存储信息数据(文本、图片、音频、视频)&#xff0c;按照存储在其内部的程序对海量的…

V8 环境搭建

前言 早就想入门V8了&#xff0c;但是之前环境配置搞了好几次都没成功&#xff0c;所以就放弃了。之前一直想着给虚拟机搭全局VPN &#xff0c;但是其实根本没那么麻烦。 准备 Ubuntu 18.04&#xff1a;据说该版本是最匹配V8的&#xff0c;当然也有说最好用 20.04 的&#x…