我们已经知道进程按照特定的SELinux域来执行的,域被SELinux用来检查进程针对某一上下文的文件的权限。我们需要知道如何设置文件的上下文,知道如何让这可管理。由此以来,如果当出现因为错误的上下文而权限拒绝。我们需要纠正这个问题。
SELinux中的文件(目录)的上下文通过它的扩展属性来设置的,但是不得不手动为所有文件设置上下文,这需要包含所有可能的文件路径和相关的SELinux上下文的数据集合。所以这不太容易被管理,SELinux使用文件上下文定义,这需要依靠正则表达式。
创建一个文件上下文定义/表达式
在审计日志的例子中,假设在/var/log/audit目录下的所有文件都是用于审计记录,这样的假设是比较有效的。所以我们可以说/var/log/audit/.*很好的匹配了拥有auditd_log_t类别的文件。虽然正确,但是剩下/var/log/audit自己还没被定义。
SELinux策略作者会怎么处理刚才那个例子呢,他们会使用正则表达式来匹配目录和它包含的内容:
/var/log/audit(/.*)?
接下来需要定义赋予什么样的上下文。在我们例子中,使用auditd_log_t类型。
SELinux管理工具会自动修改为完整的安全上下文 system_u:object_t:auditd_log_t(或者system_u:object_t:auditd_log_t:s0 –上下文结构和附加字段将在后面讨论):
/var/log/audit(/.*)? system_u:object_r:auditd_log_t
我们依然缺少了实用的类别。因为我们使用的表达式匹配了文件和目录,我们通常说所有类别适用。
/var/log/audit(/.*)? all files system_u:object_r:auditd_log_t
使用semanagefcontext,我们可以查询现有的SELinux文件上下文定义.
root #semanage fcontext -l | grepauditd_log_t
/var/log/audit(/.*)? allfiles system_u:object_r:auditd_log_t
所有文件上下文定义
semanage fcontext –l 命令将会显示SELinux策略作者提供的所有文件上下文定义。
记住SELinux策略作者提供了文件上下文的“数据库”很重要:如果你需要编写你自己的应用程序策略,你不得不按照策略相同的方法添加定义上下文。发型版--RHEL已加载的SELinux策略是所有应用程序完整的策略集合,RHEL并且对此进行支持,我们可以注意到这个列表相当巨大。这是因为所有策略已经加载,并且所有上下文定义也已加载。
注意 semanage使用/etc/selinux/*/contexts/files 下的文 件作为它的源。
发型版—Gentoo,只加载了系统适合的策略规则(当使用标准依赖结构安装附加应用程序时,附加策略规则被加载),这个列表依然很庞大但稍微好管理些。
semanage命令从保存在/etc/selinux下的文件来获取这些信息。不好的是,它不能显示应用到系统上完整的上下文和表达式。它只显示那些不是“自动产生”上下文部分,比如home目录的上下文。为了知道上下文应该是什么(根据SELinux配置文件),可以使用matchpathcon
user $/usr/sbin/matchpathcon/home/swift/.config
/home/swift/.config staff_u:object_r:xdg_config_home_t
应用上下文到文件
文件拥有正确的上下文十分重要。
保证目标文件和目录拥有正确的SELinux上下文是让系统正常工作的基础。很多时候用户关闭SELinux原因就是SELinux禁止了某些访问,问题可能仅仅是他们的文件没有标示正确。
这里引入restorecon工具,它检查文件的上下文并与SELinux上下文定义的表达式进行对比。它使用了特别的对比算法确保(正则)表达式是最适合文件的,对比文件已经存在的上下文和应该有的上下文,如果不匹配,则修改文件的上下文。
映射算法核对表达式,过滤表达式来匹配文件。在这些表达式集合中,算法会:
1. 检查是否存在没有通配符的表达式(比如 /var/log/audit/audit\.log)
2. 如果没有,便寻找通配符离起始最远的表达式(比如/var/log/audit(/.*)?和/var/log/audit/.*,后者通配符离开始最远)
3. 如果多个表达式同样的距离,它会选择字符最多的一项(/var/log/audit(/.*)?和/var/log/audit(/.*)\.log,后者拥有更多的字符)
虽然还有一些更多的规则,但是以上的三点是解释的最简单的,99.9%的情况都是有效的。你也可以使用 findcon工具来显示所有匹配的表达式,根据我们所说的,最后返回的值就是选择的那项(但是不确定的话,如果真正想确定,可以使用 matchpathcon)。user $findcon /etc/selinux/strict/contexts/files/file_contexts -p /var/cache/gorg/doc
/.* system_u:object_r:default_t
/var/.* system_u:object_r:var_t
/var/cache/gorg(/.*)? system_u:object_r:gorg_cache_t
对于新文件或者目录,执行下restorecon:
root#restorecon -v /var/log/audit/audit.log
没有输出是对的,它说明上下文开始就是正确的,以下试着递归执行:
root #restorecon-Rv /etc
restorecon reset/etc/resolv.conf.tail contextstaff_u:object_r:etc_t->staff_u:object_r:net_conf_t
restorecon reset /etc/dnsmasq.confcontext staff_u:object_r:etc_t->staff_u:object_r:dnsmasq_etc_t
restorecon reset /etc/csh.env contextstaff_u:object_r:etc_t->staff_u:object_r:etc_runtime_t
例子中,restorecon修改了三个文件的上下文。比如,dnsmasq.conf文件之前是etc_t类型,后来设置为dnsmasq_etc_t类型。
注意:并不是所有上下文都会被restorecon命令默认重置。有些类型被称为“定制类型”(customizable types),意思是系统的任何地方类型都可以被设置,因为固定路径很难被定义。restorecon将不会管这个,除非你使用-F选项。如果你想重置整个上下文(所有字段)而不是安全上下文类型(第三个字段),你需要指定-F选项。
设置上下文的其他方法
这有其他设置文件上下文的其他方法,但是他们存在不足…
一些发行版系统支持.autorelabel文件,它存放于root文件系统中。当我们按照如下操作,发行版将会在重启后,对所有文件执行restorecon。
root #touch/.autorelabel
root #reboot
你需要查找你发行版的说明文档来确定是否支持以上情况。不过实际上,等待重启在很多情况下不是很实用。
另外一个方法是使用chcon。这个工具代表的意思就是修改上下文,允许你可以直接修改上下文,并且不需要从策略中查询SELinux上下文定义。不过这个命令的缺点是下次使用restorecon将会重置上下文为SELinux策略中的上下文定义。建议测试上下文类型的时候,使用chcon命令。
增加自己定义的规则
当着手于处理SELinux文件上下文的时候,需要自己设置上下文。这样做是因为使用了非标准的路径,或者说是路径依赖于一些东西,比如服务器名字什么等,当前策略策略处理得可能不敬人意。所以来学学自己设置上下文。
首先,你需要知道一个文件的上下文应该是什么。比如你配置audit守护进程在/srv/logs/audit记录日志而不是在/var/log/audit。默认SELinux将会这个目录应该为var_t上下文。
root #matchpathcon/srv/logs/audit
/srv/logs/auditsystem_u:object_r:var_t:s0
这样问题就会是,auditd_t域没有权限对var_t进行操作。我们可以使用sesearch查询当前加载的SELinux策略:
root #sesearch-s auditd_t -t var_t -SA
Found 9 semantic av rules:
allow auditd_t file_type : filesystemgetattr ;
allow domain var_t : file { read getattr} ;
allow daemon var_t : dir { getattrsearch open } ;
allow domain var_t : dir { getattrsearch open } ;
allow domain var_t : sock_file { readwrite getattr } ;
allow auditd_t var_t : dir { getattrsearch open } ;
注意:上面的例子中,注意到不仅显示了要求的域(auditd_t)的allow语句,同时显示了其他的域,比如domain和daemon。这是因为SELinux支持属性(attributes或者标签(labels))的概念。例如,用于进程的类型(types,域将会操作的)是按照域属性(标签)给出的。普遍的策略(比如,允许所有的域通过var_t打标签的路径来搜索)可以使用这个属性代替在多种显示类型间迭代。因为auditd_t域也被daeman和domain属性标识,我们可以看到相关的Allow语句。
于是我们要做的就是标记/srv/logs为var_log_t,标记/srv/logs/audit和子目录和文件为auditd_log_t。按照以下操作:
root #semanagefcontext -a -t var_log_t "/srv/logs(/.*)?"
root #semanagefcontext -a -t auditd_log_t "/srv/logs/audit(/.*)?"
root #restorecon-Rv /srv/logs
restorecon reset /srv/logscontext unconfined_u:object_r:var_t->unconfined_u:object_r:var_log_t
restorecon reset/srv/logs/audit contextunconfined_u:object_r:var_t->unconfined_u:object_r:auditd_log_t
我们所做的就是,告诉SELinux管理程序使用类型var_log_t(-t var_log_t)和auditd_log_t增加(-a)文件上下文定义(fcontext)。接着根据最近修改的定义,使用restorecon来更新文件上下文。
semanage工具是用来修改和更新系统上SELinux设置的主要工具。所以通过它删除之前设置的上下文定义也是它所支持的,我们需要做的就是使用-d(删除)来代替-a。
root #semanagefcontext -d -t var_log_t "/srv/logs(/.*)?"
我们需要记住
1. 文件的上下文是SELinux安全系统最重要的部门之一
2. 错误的上下文是SELinux相关拒绝和权限问题最普遍的原因
3. 上下文定义是通过semanage fcontext使用正则表达式来映类型
4. 通过restorecon是上下文最好的应用和部署。
链接:https://wiki.gentoo.org/wiki/SELinux/Tutorials/Controlling_file_contexts_yourself