SELinux从入门到放弃

0.前言

关于SELinux,网上的中文资料不多,有水平的文章也没见到几篇,很多文章就是开了个头,没有深入介绍SELinux。这几周也算是看了一些关于SELinux的论文和文章,但是远没到课程要求的阅读源码的阶段。感觉架构和原理都没有弄清楚,于是停下来理理思路,做做记录。这篇blog打算是先介绍一下SELinux,分析一下其实现原理和架构,然后简单的操作一番加深理解。

很多东西也是一边接触一边学习,难免有疏漏错误之处,如果有问题还请留言交流。

1 初识SELinux

大部分运维的人好像都对SELinux有一点偏见,好吧,可能是因为它比较难以把控,使用不便。但是我们不得不承认这是个很强大的安全框架。

大家都知道不论是我们的linux服务器还是日常使用的电脑都具有访问控制机制,举个例子,当你拥有了某台电脑的普通用户权限,你仍然无法查看/etc/shadow文件,这是因为普通用户没有查看/etc/shadow文件的权力,这是属于root权限才能查看的文件。

但是假如你是root用户,你这个时候可以增加一个用户,并把自己的权力赋予它,于是这个普通用户就可以享有一切你具有的权力,包括查看/etc/shadow文件。这个理解起来很简单,你作为系统的国王,你可以把自己的权力分发给你最信任的大臣,比如最重要的兵权。当然了,如果你想的话,你可以把你的印泥交给大臣,让他也拥有至高无上的权力。

但是还有这么一种情况,就是你所拥有的权力只能你用,不能分发给其他人,在这种情况下,所有用户的权力都由操作系统来掌控,这种机制叫做强制访问控制机制,上面的那种情况属于自主访问控制机制。

关于强制访问控制和自主访问控制的区别:

  1. 自主访问控制 (discretionary access control, DAC) 是一种软件机制,用于控制用户对文件和目录的访问。DAC允许所有者根据自己的判断来设置对文件和目录的保护。DAC的两种形式是UNIX权限位和访问控制列表(access control list, ACL)。通过权限位,所有者可以按所有者、组和其他用户来设置读、写和执行保护。在传统的 UNIX 系统中,超级用户或root用户可以覆盖DAC保护。而Trusted Extensions只允许管理员和授权用户覆盖DAC。ACL提供更为精细的访问控制。通过ACL,所有者可以为特定的用户和特定的组单独指定权限
  2. 强制访问控制 (mandatory access control, MAC) 是一种基于标签关系的、由系统强制执行的访问控制机制。系统将敏感标签与创建用来执行程序的所有进程关联起来。MAC策略使用这种标签来进行访问控制决策。一般情况下,进程无法存储信息,也不能与其他进程进行通信,除非目标标签等同于该进程的标签。MAC策略允许进程从同一级别标签对象读取数据,或者从较低级别标签对象读取数据。但是,管理员可以创建一个其中仅存在很少较低级别对象或没有较低级别对象的有标签环境。

其中说到MAC,人们首先会想到的就是SELinux。SELinux就是一种基于域-类型模型(domain-type)的强制访问控制安全系统。

MAC和DAC没有强弱之分,只是适用于不同的场合。

那么SELinux相对于其他强制性访问控制系统有什么优势呢?

  • 控制范围覆盖文件系统、目录、文件、文件启动描述符、端口、消息接口和网络接口。
  • 减少特权升级攻击的漏洞。进程在域中运行,并且每个进程都被隔离开来。 SELinux策略规则定义了进程如何访问文件和其他进程。如果一个进程受到攻击,攻击者只能访问该进程的正常功能。以及该进程已被配置为有权访问的文件。例如,如果Apache HTTP服务器遭到入侵,攻击者无法使用该进程读取用户主目录中的文件,除非已添加或配置了特定的SELinux策略规则来允许此类访问。
  • 等等...

SELinux 的运行机制如下:

当一个主体试图访问一个客体时,内核中的策略执行服务器将检查AVC(Access Vector Cache), 在AVC中,subject 和object的权限被缓存(cached)。如果基于AVC中的数据不能做出决定,则请求安全服务器,安全服务器在一个矩阵中查找“应用+文件”的安全环境。然后根据查询结果允许或拒绝访问,拒绝消息细节位于/var/log/messages中。

对于以上运行机制不熟悉没关系,我们先来直观感受一下。

2 SELinux安装和基本操作

我所使用的是centos7虚拟机,其系统默认安装了selinux,如果你使用的是ubuntu的话,安装selinux可能会遇到一些麻烦,不过不要紧,折腾环境的过程也是学习的过程,因为我没有在Ubuntu上试验,所以安装过程请自行google解决。

对于centos,其虽然自带了selinux,但是是以最小的模式安装的,很多工具还需要我们自行安装,下面是常用的工具包及其里面的工具简介:

  • policycoreutils:提供与SELinux相关的命令,比如 restorecon, secon, setfiles, semodule , load_policysetsebool 来操作和管理SELinux。
  • policycoreutils-gui:提供图形化软件system-config-selinux来管理 SELinux。
  • policycoreutils-python:提供命令比如semanage, audit2allow, audit2why,和chcat 来管理和操作SELinux。
  • selinux-policy:提供SELinux引用策略,该引用策略包括了所有的SELinux策略,并被用作其他策略(如 Targeted Policy)的基础使用。
  • selinux-policy-targeted:提供SELinux的 targeted 策略。
  • selinux-policy-mls:提供SELinux的 MLS 策略。
  • setools/setools-console/setools-gui:这些安装包提供了与SELinux相关的策略分析、检索、日志审计与监控、文件上下文管理管理的相关工具。setools是元工具,setools-gui提供了apol,seaudit工具;setool-console则提供了 sechecker,sediff,seinfo, sesearch和findcon等命令行工具。
  • libselinux:为SELinux的应用提供 API 支持。
  • libselinux-utils:提供 avcstat, getenforce, getsebool, matchpathcon,selinuxconlist, selinuxdefcon, selinuxenabledsetenforce 工具。

当某些操作提示not found时可查看一下是不是某些库没有安装,当然这篇文章暂时用不到这些。

接下来看一下基本的操作:

1.获取当前 SELinux 运行状态 getenforcesestatus

sestatus ----查看当前系统 SELinux 详细状态
getenforce ----查看当前系统 SELinux 状态

在安全操作系统上,SELinux 其状态有三种:

  • Enforcing,强制模式,表示 SELinux 运行,所设置的所有安全策略都被启用,所有与 SELinux 安全策略相关的服务和程序被策略限制。
  • permissive:宽容模式:表示 SELinux 运行,所设置的所有安全策略都被启用,所有与 SELinux 安全策略相关的服务和程序不会被策略限制,但是会收到警告,可用于 SELinux 的 debug。
  • disabled:关闭,SELinux 被关闭。

2.改变 SELinux 运行状态。setenforce [ Enforcing | Permissive | 1 | 0 ]

该命令可以立刻改变 SELinux 运行状态,在 Enforcing 和 Permissive 之间切换,结果保持至关机。一个典型的用途是看看到底是不是 SELinux 导致某个服务或者程序无法运行。若是在 setenforce 0 之后服务或者程序依然无法运行,那么就可以肯定不是 SELinux 导致的。

改变SELinux状态

若是想要永久变更系统 SELinux 运行环境,可以通过更改配置文件 /etc/selinux/config或者/etc/sysconfig/selinux 实现。

永久改变selinux状态

3.查看安全上下文

ls -Z 显示文件系统客体的安全上下文
ps -Z 显示进程的安全上下文
id -Z 它显示的当前用户的 shell 的安全上下文

查看安全上下文

安全上下文通常的表示方式是: USER:ROLE:TYPE

USER 相当于账号的身份识别,通常有三种身份:root,表示root的帐号身份;system_u:表示系统程序方面的识别,通常就是程序;user_u:代表的是一般使用者帐号相关的身份。

ROLE 即角色,可以用于表示资源是属于程序、用户或是文件与设备。一般的角色有:object_r 表示是文件、目录或者是设备;system_r表示是程序;sysadm_r、staff_r、user_r等表示是用户。

TYPE 适用于将主体和客体划分为不同的组,给每个主体和系统中的客体定义了一个类型,为进程运行提供最低的权限环境。所有的进程也赋予各自的一个叫 domain 的类型。

3 关于SELinux的一些术语概念

进一步了解和操作SELinux之前,我们需要先来了解一些概念。下面将简单的介绍一下。

3.1 主体

在SELinux中,主体通常指的是进程。

3.2 客体

客体通常是用于信息共享、存储和通讯的系统资源(如文件、目录、套接字、共享内存等)。一个客体类别代表某个确定类型(如文件或套接字)的所有资源.一个客体类别的实例(如某个特定的文件或套接字)被称为一个客体, 如/etc/passwd 这个文件,我们称之为客体。

3.3 DAC/MAC

DAC --> 自主访问控制机制
MAC --> 强制访问控制

在标准 Linux,所采用的访问类型为任意访问类型,即 DAC。DAC 特点是基于用户标识的访问控制,如一个文件,文件所有者,
同组用户,其它组用户。

在 SELinux 当中,主体对客体所采用的访问类型为MAC,即强制访问控制。MAC 用于将系统中的信息分密级和类进行管理,以保证每个用户只能访问到那些被标明可以由他访问的信息的一种访问约束机制。通俗的来说,在强制访问控制下,用户(或其他主体)与文件(或其他客体)都被标记了固定的安全属性(如安全级、访问权限等),在每次访问发生时,系统检测安全属性以便确定一个用户是否有权访问该文件。

3.4 安全上下文

SELinux 系统中的进程和文件都标记了 SELinux 的上下文,这个上下文包含了许多有用的信息,包括SELinux用户(不同于Linux系统的用户)、角色(Role)、类型(Type)和级别(Security Level)等等。在运行 SELinux 的时候,这些上下文信息被用来辅助进行访问控制,它们可以看做是 SELinux 策略的“维度”。最新的 SELinux 综合提供了 RBAC、TE(类型增强)和 MLS(Multi-Security Level,多级别安全)三种访问控制机制。

安全上下文通常的表示方式是: USER:ROLE:TYPE

3.5 AV/AVC

访问向量(Access vectors,Avs),用来表示策略的规则。如允许域访问各种系统客体,一个 AV 是一套许可。一个基本的 AV 规则是主体和客体的类型对,AV 规则的语法如下:

<av_kind><source_type(s)><target_type(s)>:<class(es)>
<permission(s)>

<av_kind>有四种设置:allow,表示允许主体对客体执行允许的操作;neverallow,表示不允许主体对客体执行指定的操作;auditallow,表示允许操作并记录访问决策信息;dontaudit,表示不记录违反规则的决策信息,且违反规则不影响运行。

AV 的例子如下:

allow init_t apache_exec_t : file execute;
allow userdomain shell_exec_t: file{ read getattr lock execute ioctl};

AVC 提供了从安全服务器获得的访问策略的缓冲区(cache),提高了安全机制的运行性能。它提供了 hook 函数高效检查授权的接口,提供了安全服务器管理 cache 的接口。

看到这里有些困惑?形象点说这就是一张权力表的一项,你作为进程拥有哪些权力,都记录在这张表上,当你进行操作时,系统就会查这张表来决定你是否有权力操作。

3.6 域

由于历史原因,一个进程的类型通常被称为一个域(域类型)。“域”和“域类型”都是指同一个,在平时我们看到文档中以及日常交流中,我们认为域、域类型、主体类型和进程类型都是指同一种意思。

3.7 策略

因为 SELinux 默认不允许任何访问,所以,所有的访问都必须明确授权,不管用户/组ID是什么, 在SELinux中,通过allow语
句对主体授权对客体的访问权限。Allow规则由四部分组成:源类型(Source type(s))是尝试访问进程的域类型;目标类型(Target type(s))被进程访问的客体的类型;客体类别(Object class(es))是指定允许访问的客体的类型,如 file,dir,socket 等;许可(Pemission(s))象征目标类型允许源类型访问客体类型的访问种类。

allow user_t bin_t:file {read execute getattr}

上述例子显示了TE allow规则的基础语法,这个规则包含两个类型标识符:源类型(或主体类型或域)user_t,目标类型(或客体类型)bin_t,标识符 file 是定义在策略的客体类别名称,表示的是一个普通文件,大括号的许可是文件客体类别有效许可。整条规则解释是:拥有域类型user_t的进程可以读/执行或获取具体有bin_t类型的文件客体的属性。

3.8 域转换

SELinux一大特点就是将进程和用户的执行权限限定在一个域(Domain)内。因此,即使 root 用户也不可能具有太大权限,从而保证了系统整体的安全性。SELinux 中定义的域会限定进程的执行权限或范围,但进程执行的时候是可以从一个域转换到另外一个域的,以获得另外一个域内限定的权限。

4 SELinux的工作模式和架构

既然是奔着学习的目的,那么我们不仅仅是会用,更要了解其是如何工作的,那么我们就来了解一下SELinux的工作模式。

首先我们需要明白的是,SELinux并不是直接就被嵌入到内核中的,因为SELinux并不是惟一一个用于增强Linux安全性的安全系统。所以linus(linux之父)也不会同意将SELinux直接包含在内核中,相反,创建了Linux Security Modules系统,允许安全子系统作为模块使用,这意味着可以比较方便地连接新的模块。

SELinux是通过LSM框架合并到内核中的。可以这么认为:

LSM是目前linux的安全框架,而SELinux是其中的一个modules。

那么LSM是怎么和SELinux进行调用和交互的呢?

LSM在内核系统调用逻辑中提供了一套钩子(hooks),这些钩子通常放在标准Linux访问检查后、且内核调用访问真实资源之前,下图举例说明了LSM框架的基础。

SELinux作为一个LSM模块载入内核,在访问被允许之前进行额外的访问确认。只有当标准Linux访问(DAC)检查成功后SELinux才会生效。实际上,这在访问控制策略方面没有负面影响,因为SELinux访问控制比标准Linux DAC约束更多,而且它也不会覆盖DAC的决定。

SELinux内部结构大概如下图所示:

SELinux 包含五个基本组成:

  • 用于处理文件系统的辅助模块
  • 用于集成 Linux Security Modules 事件钩的模块
  • 一个用于组织访问控制的基本机制
  • Policy Enforcement Server,一个系统安全性策略数据库
  • Access Vector Cache (AVC),一种辅助机制,用于提高生产力

根据上图SELinux 的操作可以分为下面几个步骤:

1.操作系统主体(流程)尝试访问特定对象(文件、流程、套接字)上的某个操作,这在 Linux 标准自主安全系统(DAC)中是允许的。这将向对象发起一个请求流。

2.每个要求对对象执行操作的请求都由 Linux Security Modules 截获并传递给 SELinux Abstraction & Hook Logic 子系统,同时还包括主体和对象的安全上下文,SELinux Abstraction & Hook Logic 子系统负责与 LSM 交互。

3.从 SELinux Abstraction and Hook Logic 子系统接收到的信息将转发给基本的 Policy Enforcement Server 模块,后者负责确定是否允许主体访问该对象。

4.要接收是否允许或禁止该操作的决定,策略实施服务器将与 Access Vector Cache 子系统通信,后者通常会缓存要使用的规则。

5.如果 AVC 没有包含相关策略的缓存规则,对所需的安全策略的请求将再次转发给安全策略数据库。

6.在找到安全策略后,该策略将被传递给接收决策的策略服务器。

7.如果所请求的操作符合找到的策略,那么将允许执行该操作。反之,将禁止执行该操作,并且所有决策制定信息将被写入到 SELinux 日志文件中。

除了判断是否允许或禁止某些操作外,Policy Enforcement Server 模块还负责执行一些辅助任务,例如安全标签管理(分配和移除)。

更详细的细节如下图所示:

图看起来有点复杂,其实也就是一些具体的实现,参考上面的过程也还是比较容易理解的。

5 SELinux应用

了解了SELinux的基本知识之后,我们通过一个例子来加深对SELinux的认识。

SELinux 在 httpd 中的运用

首先我们来安装并且启动httpd服务,httpd也就是apache,很常见的web服务器。

[centos@centos ~]$ sudo yum install httpd
[centos@centos ~]$ service httpd start

此时访问127.0.0.1是这样的:

这是因为我们的web服务器目录下还没有文件,显示了默认的页面。验证如下:

[centos@centos ~]$ ll /var/www/html
总用量 0

那么我们就在home文件下新建一个文件index.html,并将其移动到/var/www/html文件夹下面。

[centos@centos ~]$ vi index.html

hello,world
this is a test page

[centos@centos ~]$ sudo mv index.html /var/www/html/
[centos@centos ~]$ cd /var/www/html/
[centos@centos html]$ ls
index.html

好了,大功告成接下来再访问网站试试:

什么鬼?403forbiden?而且这个时候SELinux安全性也报警了,于是我们猜想这是SELinux限制了访问。

我们可以查看/var/log/audit文件夹下面的audit.log文件查看原因(需要root用户权限)
可以看到最后几条为:

type=AVC msg=audit(1544021445.279:278): avc:  denied  { read } for  pid=4149 comm="httpd" name="index.html" dev="dm-0" ino=68570897 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file
type=SYSCALL msg=audit(1544021445.279:278): arch=c000003e syscall=2 success=no exit=-13 a0=55d557c6f2d0 a1=80000 a2=0 a3=4 items=0 ppid=4141 pid=4149 auid=4294967295 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4294967295 comm="httpd" exe="/usr/sbin/httpd" subj=system_u:system_r:httpd_t:s0 key=(null)
type=PROCTITLE msg=audit(1544021445.279:278): proctitle=2F7573722F7362696E2F6874747064002D44464F524547524F554E44

看来是SELinux限制了httpdindex.htmlread操作。

接着来查看一下index.html安全上下文信息。

[centos@centos ~]$ ls -Z /var/www/html
-rw-rw-r--. centos centos unconfined_u:object_r:user_home_t:s0 index.html

可以看出index.html的type是user_home_t,而我们查看/var/www/html目录的上下文就会发现其是属于httpd_sys_content_t组的。

[centos@centos ~]$ ls -Z -d /var/www/html
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html

我们此时的SELinux的工作模式是 enforcing,所以对于违反策略的行动是被禁止的。

我们可以通过手动改变index.html的安全上下文来解决问题。有两个命令可供选择: restorecon 或者 chcon

  • 命令 restorecon 可以用来恢复文件默认的上下文:
restorecon reset /var/www/html/index.html context //-R表示递归,如果是目录,则该目录下的所有子目录、文件都会得到修复
unconfined_u:object_r:user_home_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
[centos@centos ~]$ ls -Z -d /var/www/html
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html
  • 命令 chcon 可以改变文件的上下文信息
[centos@centos ~]$ chcon -t httpd_sys_content_t /var/www/html/index.html
[centos@centos ~]$ ls -Z -d /var/www/html
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html

一般我们可以选择一个参考文件。比如在/var/www/html新建一个文件test.html,然后依据test.html来修改index.html的安全上下文。

[centos@centos ~]$ sudo vi /var/www/html/test.html

testfile 

[centos@centos ~]$ ls -Z /var/www/html
-rw-rw-r--. centos centos unconfined_u:object_r:user_home_t:s0 index.html
-rw-r--r--. root   root   unconfined_u:object_r:httpd_sys_content_t:s0 test.html

[centos@centos ~]$ sudo chcon --reference=/var/www/html/test.html /var/www/html/index.html
[centos@centos ~]$ ls -Z /var/www/html
-rw-rw-r--. centos centos unconfined_u:object_r:httpd_sys_content_t:s0 index.html
-rw-r--r--. root   root   unconfined_u:object_r:httpd_sys_content_t:s0 test.html

修改完上下文之后再来访问一下网站试试

成功访问。

参考

https://www.ibm.com/developerworks/cn/linux/l-secure-linux-ru/index.html

https://blog.csdn.net/MyArrow/article/details/10063581

http://www.cnblogs.com/xiaoluo501395377/archive/2013/05/26/3100444.html

The SELinux Notebook

1 + 4 =
快来做第一个评论的人吧~