woff 發表於 2020-8-24 23:31:15

SELinux 連線端口問題分析解決

CentOS 5.x 之後,SELinux 已經是個非常完備的核心模塊了,尤其是CentOS 提供了很多管理SELinux 的指令與機制,因此在整理架構上面是單純且容易操作管理的,所以在沒有自行開發網絡服務軟件以及使用其他第三方協力軟件的情況下,也就是全部使用CentOS 官方提供的軟件來使用我們服務器的情況下,建議不要關閉SELinux

#什麼是SELinux
Security Enhanced Linux 的縮寫SELinux,字面意思是安全強化的LInux。至於強化的是哪個部分?下面來了解下

#當初設計的目標:避免資源的誤用
SELinux 是由美國國家安全局(NSA)開發的,需求來源於內部員工資源誤用導致系統出現問題;

資源誤用:將一個/var/www/html/目錄權限設置成777,那麼當啟動www服務器軟件,就意味著這個軟件觸發的進程擁有對該目錄寫入的權限,只要通過該進程服務器對目錄大量寫入,就會導致系統硬盤資源被爆破

SELinux 是在進行進程、文件等西部權限設置依據的一個核心模塊,由於啟動網絡服務的也是進程,因此剛好也能夠控製網絡服務是否能存取系統資源的一道關卡

在講解SELinux 之前,先回顧一下之前講到的:系統文件權限與用戶之間的關係

#傳統的文件權限與賬戶關係:自主式訪問控制DAC
第13 章中講到:系統賬戶主要分為系統管理員(root)與一般用戶,他們能否使用系統上的文件資源與rwx 權限設置有關。(各種權限設置對root 無效)。當某個進程想要對文件進行存取時,系統會根據該進程的擁有者、群組,並比對文件的權限,若通過權限檢查,就可以存取該文件

這種存取文件的方式被稱為自主式訪問控制Discretionary Access Controller簡稱DAC,基本上就是依據進程的擁有者與文件資源的rwx權限來決定有無存取的能力。DAC有如下困擾:

root 具有最高的權限:只要取得屬於root 的進程,那麼就很危險
使用者可以取得進程來變更文件資源的訪問權限:如果將某個目錄權限不小心設置為777,由於對任何人的權限會變成rwx,因此該目錄就會被任何人所任意存取
#以政策規則規定特定進程讀取特定文件:委任式訪問控制MAC
為了避免DAC 的困擾,SELinux 導入了委任式訪問控制Mandatory Access Control 簡稱MAC

MAC可以針對特定的進程與特定的文件資源來進行權限的控制。即使你是root,那麼在使用不同的進程時,你所能取得的權限並不一定是root,而需要看當時該進程的設置。如此一來針對控制的「主體」變成了「進程」而不是使用者,但是真個系統進程很多、文件也很多,一項一項控制太麻煩,所以SELinux也提供一些預設的政策Policy,並在該政策內提供多個規則rule,讓你可以選擇是否啟用該控制規則

在該種模式下,進程能夠活動的空變小了。比如:www服務器軟件達成進程為httpd這個程序,默認情況下, httpd僅能在/var/www目錄下存取文件,如果httpd進程要去其他目錄存儲數據時,除了規則設置要開放外,目標目錄也要設置成httpd可讀取的模式type才行,限制非常多,所以,即使httpd這個進程被黑客取得了控制權限,它也無權限瀏覽其他的目錄文件

簡單說,針對Apache 這個www 網絡服務使用DAC 或MAC 的結果來說,兩者的關係可用下圖來說明



圓環表示畫地為牢,DAC 模式下,由於是root,牢房對root 無效。在MAC 下,牢房就生效了

#SELinux 的運作模式
強調:SELinux是通過MAC方式來管控進程,進程是主體,而目標則是該進程能否讀取的文件資源。

主體Subject:可以看成就是進程

目標Object:目標資源,一般就是文件系統

政策Policy:會根據某些服務來製定基本的存取安全性政策,政策內還會有詳細的規則rule 來指定不同的服務開放某些資源的存取。在目前的CentOS 7.x 裡面僅提供3 個主要的政策:

targeted:針對網絡服務限制較多,針對本機限制較少,是預設的政策
minimum:由target 修正而來,僅針對選擇的進程來保護
mls:完整的SELinux 限制,限制方面較嚴格
安全性本文security context

主體是否能存取目標除了政策指定之外,主體與目標的安全性本文必須一致才能夠順利存取

security context 類似文件系統的rwx,如果設置錯誤,你的某些服務(主體進程)就無法存取文件系統(目標資源),就會出現權限不符對的錯誤信息了

由於SELinux 重點在保護進程讀取文件系統的權限,上述說明的示意圖如下:



傳統的進程與文件的rwx方式,在這中間增加了SELinux月安全性本文規則,通過了這些規則之後,才和傳統的進程與文件的rwx方式一致。

筆者理解為是通過攔截器的方式,出台了SELinux ,前面通過SElinux 攔截細化權限,符合要求的再去到傳統的方式,這樣一來就對傳統的加強了

#安全性本文Security Context
CentOS 7.x 的target 政策提供了非常多的規則,只需要如何開啟關閉某項規則即可。

安全性本文則非常麻煩,可能需要自行配置它,比如你常常設置文件的rwx 權限,那麼這個安全性本文就類似,可以看成是SELinux 中的rwx

安全性本文存在於主體進程中與目標文件資源中,物理位置是放在文件的inode 中,因此主體進程想要讀取目標文件資源時,同樣需要讀取inode,這就可以對比安全性本文一級rwx 等權限是否正確了。

觀察安全性本文可使用ls -Z,但是前提是需要啟動SELinux才行,下個小節會介紹如何啟動SELinux,這裡先介紹知識點

# ls -Z
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 accountadd.sh
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 accountadd.txt
-rwxr--r--+ root root unconfined_u:object_r:admin_home_t:s0 acl_test1
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 addaccount2.sh
-rw-------. root root system_u:object_r:admin_home_t:s0 anaconda-ks.cfg
-rw-r--r--. root root system_u:object_r:admin_home_t:s0 initial-setup-ks.cfg
# 上述字段很长的那一栏就是安全性本文了
   
安全性本文主要用冒號分割為三個字段,含義如下:

identify:身份

相當於賬戶方面的身份識別,常見有幾下幾種類型

unconfined_u:不受限的用戶

該文件來自不受限的進程所產生的,一般來說,可以使用可登錄賬號來取得bash,預設的bash 環境是不受SELinux 管制的,因為bash 並不是什麼特別的網絡服務,因此在該bash 進程所產生的文件,其身份識別大多就是該類型了

system_u:系統用戶

基本上,如果是系統會軟件本身所提供的文件,大多就是該類型,如果是用戶通過bash 自己建立的文件,大多則是不受限的unconfined_u 身份,如果是網絡服務所產生的文件,或則是系統服務運行過程中所產生的文件,則大部分是system_u

role:角色

通過該字段,可以知道這個資料是屬於進程、文件資源還是代表使用者,一般的角色有:

object_r:代表的是文件或目錄等文件資源
system_r:代表的是進程,不過一般使用者也會被指定為system_r
type:類型,最重要

在預設的targeted 政策中, identify 與role 字段基本上是不重要的,而type 是最重要的,基本上,一個主體進程能不能讀取到這個文件資源,與類型字段有關,而類型字段在文件與進程的定義不相同:

type:在文件資源(object)上面稱為類型(type)
domain:在主體進程(subject)則稱為領域(domain)
domain 需要與type 搭配,則該進程才能夠順利的讀取文件資源

#進程與文件SELinux type 字段的相關性
通過身份識別與角色字段的定義,我們可以大概某個進程所代表的意義

# 观察下系统 进程的 SELinux 相关信息
# 观察下系统 进程的 SELinux 相关信息
# ps -eZ
LABEL                           PID TTY          TIME CMD
system_u:system_r:init_t:s0         1 ?      00:00:01 systemd
system_u:system_r:kernel_t:s0       2 ?      00:00:00 kthreadd
system_u:system_r:kernel_t:s0       4 ?      00:00:00 kworker/0:0H
system_u:system_r:kernel_t:s0       5 ?      00:00:00 kworker/u2:0
...
system_u:system_r:sshd_t:s0-s0:c0.c1023 2344 ? 00:00:00 sshd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 2350 ? 00:00:00 sshd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 2353 pts/0 00:00:00 bash
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 2415 pts/0 00:00:00 su
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 2424 pts/0 00:00:00 bash
system_u:system_r:kernel_t:s0    2726 ?      00:00:00 kworker/u2:2
system_u:system_r:kernel_t:s0    2778 ?      00:00:00 kworker/0:1
system_u:system_r:kernel_t:s0    2836 ?      00:00:00 kworker/0:3
system_u:system_r:kernel_t:s0    2877 ?      00:00:00 kworker/0:0
system_u:system_r:ksmtuned_t:s02885 ?      00:00:00 sleep
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 2886 pts/0 00:00:00 ps

# 基本上进程主要分为两大类,
# 一种是系统有受限的 system_u:system_r,
# 另一种可能是用户自己的,比较不受限的进程(通常是本机用户自己执行的程序 ) unconfined_u:unconfined_r

# unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 2424 pts/0 00:00:00 bash
# 比如上面这个进程,就是我们自己执行命令所在的 bash
   
基本上,這些對於資料在targeted 政策下的對應對下



身份識別角色對應在 targeted 的意義
unconfined_uunconfined_r一般可登陸消費者的進程,比較沒有受限的進程。 大多數都是使用者已經順利登陸系統(不論是網路還是本機登陸來取得可用的 shell)後,所用來操作系統的進程,如 bash x window 相關富安居等
system_usystem_r由於為系統帳戶,因此是非交談式的系統運行進程,大多數的系統進程均是這種類型


如上所述,在預設的target 政策下,最重要的是type 字段,主體與目標之間是否具有可讀寫的權限,與進程的domain 與文件的type 有關。這兩者的關係可以使用crond 以及他的配置文件來說明

# 1. 先看看 crond 这个进程的安全本文内容
# ps -eZ | grep cron
system_u:system_r:crond_t:s0-s0:c0.c1023 1398 ? 00:00:00 atd
system_u:system_r:crond_t:s0-s0:c0.c1023 1400 ? 00:00:00 crond
# 这个安全本文的类型名称为 crond_t 格式

# 2. 看看 /usr/ssbin/crond 、 /etc/cron.d、/etc/cron.d 文件的安全本文内容
# ll -Zd /usr/sbin/crond /etc/crontab /etc/cron.d
drwxr-xr-x. root root system_u:object_r:system_cron_spool_t:s0 /etc/cron.d
-rw-r--r--. root root system_u:object_r:system_cron_spool_t:s0 /etc/crontab
-rwxr-xr-x. root root system_u:object_r:crond_exec_t:s0 /usr/sbin/crond
   
執行/usr/ssbin/crond後,該程序編程的進程domain類似是crond_t,它能夠讀取的配置文件是system_cron_spool_t類型。因此無論/etc/crontab與/etc/cron.d以及/var/spool/cron都會是相關的SELinux類型(/var/spool/cron為user_cron_spool_t類型)。下面圖示說明



crond 執行後,具有crond_exec_t 類型
該文件類型會造成主體進程Subject 具有crond 這個領域domain,政策針對這個領域有許多規則,其中就包括可以讀取的目標資源類型
由於crond domain被設置為可以讀取system_cron_spool_t類型的目標文件object,因此你的配置文件放到/etc/cron.d/目錄下,就能夠被crond進程讀取了
但是最終能不能讀到正確的資料,還需要看傳統的rwx 是否符合Linux 的權限規範
下面來測試上述說明

# 1. 假设你因为不熟悉的缘故,因此是在 root 家目录建立一个如下的 cron 设置
# vim checktime
10 * * * * root sleep 60s

# 2. 发现文件放错目录了,又不想要保留副本,因此使用 mv 移动到正确的目录
# mv checktime /etc/cron.d/
# ll /etc/cron.d/checktime
-rw-r--r--. 1 root root 26 Mar 17 13:12 /etc/cron.d/checktime
# 权限是 644,任何进程都可以读取

# 3. 强制重新启动 crond,然后查看登录日志
# systemctl restart crond         
# tail /var/log/cron
Mar 17 13:01:01 study run-parts(/etc/cron.hourly): finished mcelog.cron
Mar 17 13:10:01 study CROND: (root) CMD (/usr/lib64/sa/sa1 1 1)
Mar 17 13:14:01 study crond: ((null)) Unauthorized SELinux context=system_u:system_r:system_cronjob_t:s0-s0:c0.c1023 file_context=unconfined_u:object_r:admin_home_t:s0 (/etc/cron.d/checktime)
Mar 17 13:14:01 study crond: (root) FAILED (loading cron table)
Mar 17 13:15:08 study crond: (CRON) INFO (Shutting down)
Mar 17 13:15:08 study crond: (CRON) INFO (RANDOM_DELAY will be scaled with factor 13% if used.)
Mar 17 13:15:08 study crond: ((null)) Unauthorized SELinux context=system_u:system_r:system_cronjob_t:s0-s0:c0.c1023 file_context=unconfined_u:object_r:admin_home_t:s0 (/etc/cron.d/checktime)
Mar 17 13:15:08 study crond: (root) FAILED (loading cron table)
Mar 17 13:15:08 study crond: (CRON) INFO (running with inotify support)
Mar 17 13:15:08 study crond: (CRON) INFO (@reboot jobs will be run at computer's startup.)

# 上述日志中有 Unauthorized 的信息,表示有错误,因为原本的安全本文与文件的实际安全本文无法搭配的缘故,
# 信息还列出了 SELinux context 与 file_context 的信息,表示的确不匹配
   
從如上的測試來看,上述測試由於安全本文不匹配導致進程無法讀取該文件

#SELinux 三種模式的啟動、關閉與觀察
並非所有的Linux distribution 都支持SELinux,CentOS 7.x 本身就有支持SELinux,所以你不需要自行編譯SELinux 到你的Linux 核心中。目前SELinux 是否啟動有三種模式:

enforcing:強制模式,表示SELinux 運行中,且已經正確的開始限制domain/type 了
permissive:寬容模式,表示SELinux 運行中,不過僅有警告進行並不會實際限制domain/type 的存取。這種模式可以用來debug SELinux 的配​​置
disabled:SELinux 關閉中
三種模式的示意圖如下:



注意:並非有所的進程都受SELinux的管控,注意是有受限的進程主體,可以通過ps -eZ來觀察該進程是否有受限(confined)。下面來觀察crond與bash程序是否有被限制

# ps -eZ | grep -E 'cron|bash'
system_u:system_r:crond_t:s0-s0:c0.c1023 1398 ? 00:00:00 atd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 2353 pts/0 00:00:00 bash
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 2424 pts/0 00:00:00 bash
system_u:system_r:crond_t:s0-s0:c0.c1023 4073 ? 00:00:00 crond
   
因為目前target這個政策下,只有第3個字段type會有影響,因此可以看到crond有crond_t類型,是受限的,而bash是unconfined_t類型,是不受限的,也就是說bash不會經過上圖的流程,而直接去判定rwx

可以通過以下方式獲取當前的SELinux 模式
# getenforce
Enforcing
   
查詢當前SELinux 的政策(Policy)

sestatus [-vb]

选项与参数:
      -v:检查 /etc/sestatus.conf 内的文件与进程的安全性本文内容
      -b:将目前政策的规则布尔值列出,即某些规则 rule 是否要启动(0/1)
   
# 范例 1:列出目前 SELinux 使用的哪个政策 Policy

# sestatus                  
SELinux status:               enabled                              # SELinux 是否启动
SELinuxfs mount:                /sys/fs/selinux                # SELinux 的相关文件数据挂载点
SELinux root directory:         /etc/selinux                # SELinux 的根目录所在
Loaded policy name:             targeted                        # 当前的政策
Current mode:                   enforcing                        # 当前模式
Mode from config file:          enforcing                        # 目前配置文件内规范的 SELinux 模式
Policy MLS status:            enabled                              # 是否含有 MLS 的模式机制
Policy deny_unknown status:   allowed                              # 是否预设抵挡未知的主体进程
Max kernel policy version:      31
   
上述信息科知道,SELinux 目前的政策是targeted ,可通過如下方式修改

# vim /etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#   enforcing - SELinux security policy is enforced.
#   permissive - SELinux prints warnings instead of enforcing.
#   disabled - No SELinux policy is loaded.
SELINUX=enforcing                         # 可选择为上述 3 个
# SELINUXTYPE= can take one of three values:
#   targeted - Targeted processes are protected,
#   minimum - Modification of targeted policy. Only selected processes are protected.
#   mls - Multi Level Security protection.
SELINUXTYPE=targeted                # 可选值为上述 3 个
   
#SElinux 的啟動與關閉
由於SElinux 是整合到核心中去的,因此修改上述配置文件之後,需要重新啟動。

注意:如果從disable轉到啟動SELinux的模式時,由於系統必須要針對文件寫入安全性本文信息,因此開機過程需要耗費不少時間等待重新寫入SELinux安全性本文(有時也稱為SELinux Label) ,而且在寫完之後還需要重新啟動一次,啟動成功之後,再使用getenforce 和 sestatus來觀察是否有成功啟動到Enforcing模式

如果當前已經是Enforcing 模式,可能由於一些設置問題大道至SELinux 讓某些服務無法正常的運行,此時可將模式修改為寬容模式(permissive),讓SELinux 只發出警告信息

setenforce

选项与参数:
      0:转成 permissive 宽容模式
      1:转成 Enforcing 强制模式
注意:无法在 Disabled 模式下进程模式的切换
   
某些時候從Disabled換成Enforcing之後,有部分服務可能無法順利啟動,可能會報錯/lib/xxx數據沒有權限讀取的錯誤信息。這大多數是由於重新寫入Selinux type(Relabel)出錯的原因,使用Permissive模式就沒有該錯誤。最簡單的辦法是在Permissive模式下使用指令restorecon -Rv /重新還原所有SELinux的類型

#SELinux 政策內的規則管理
#SELinux 各個規則的布爾值查詢:getsebool
getsebool [-a] [规则名称]

选项与参数:
      -a:列出目前系统上所有 SELinux 规则的布尔值为开启或关闭(on/off)
   
# 范例 1:查询所有的布尔值设置
# 范例 1:查询所有的布尔值设置
# getsebool -a
abrt_anon_write --> off
abrt_handle_event --> off
abrt_upload_watch_anon_write --> on
...
cron_can_relabel --> off                # 这个与 cron 有关
cron_system_cronjob_use_shares --> off
cron_userdomain_transition --> on
...
httpd_anon_write --> off                # 与网页 http 有关
httpd_builtin_scripting --> on
httpd_can_check_spam --> off
# 每一行都是一个规则
   
#SELinux 各個規則規範的主體進程能夠讀取的文件SELinux type 查詢seinfo、sesearch
上述指令知道了所有的規則開啟情況,可以通過seinfo、sesearch 等工具來查看每個規則具體在限制什麼。

上述工具並未預裝,請拿出安裝光盤掛載到/mnt目錄下,安裝

# blkid
/dev/sr0: UUID="2019-09-11-18-50-31-00" LABEL="CentOS 7 x86_64" TYPE="iso9660" PTTYPE="dos"
/dev/sda1: UUID="e9d54afb-2afe-42de-87fe-9f55d747fcd9" TYPE="xfs"
/dev/sda2: UUID="CNUXwS-J3Lh-0nDA-TssW-l1vT-90us-MHYnT1" TYPE="LVM2_member"
/dev/mapper/centos_study-root: UUID="d7e09bb4-2f04-4ed4-b377-91a22fe85ce7" TYPE="xfs"
/dev/mapper/centos_study-swap: UUID="684eebc0-3f70-4fc1-9a5d-d683f6a07cd0" TYPE="swap"
# mount /dev/sr0 /mnt/
mount: /dev/sr0 is write-protected, mounting read-only
# yum install /mnt/Packages/setools-console-*                              
...
Complete!
# umount /mnt/# 卸载光盘
   
seinfo [-Atrub]

选项与参数:
      -A:列出 SELinux 的状态、规则布尔值、身份识别、角色、类型等所有信息
      -u:列出 SELinux 的所有身份识别 user 种类
      -r:列出 SELinux 的所有角色 role 种类
      -t:列出 SELinux 的所有类型 type 种类
      -b:列出所有规则的种类(布尔值)
   
# 范例 1:列出 SELinux 在此政策下的统计状态
# seinfo

Statistics for policy file: /sys/fs/selinux/policy
Policy Version & Type: v.31 (binary, mls)

   Classes:         130    Permissions:       272
   Sensitivities:       1    Categories:       1024
   Types:            4792    Attributes:      253
   Users:               8    Roles:            14
   Booleans:          316    Cond. Expr.:       362
   Allow:          107360    Neverallow:          0
   Auditallow:      157    Dontaudit:       10020
   Type_trans:      18129    Type_change:      74
   Type_member:      35    Role allow:         39
   Role_trans:      416    Range_trans:      5899
   Constraints:       143    Validatetrans:       0
   Initial SIDs:       27    Fs_use:             32
   Genfscon:          103    Portcon:         614
   Netifcon:            0    Nodecon:             0
   Permissives:         0    Polcap:            5
   
# 当前政策是 targeted ? (哪里显示的?),此政策下的 Types 类型有 4792 个
# SELinux 的规则(Booleans)有 316 条
   
在前面讲到过几个身份识别 user 与 角色 role,seinfo 可以查询到所有的种类,可自行查询

在前面讲到 /etc/cron.d/checktime 的 SElinux type 类型不太对,我们知道 crond 进程的 type 是 crond_t,那么查找下 crond_t 能够读取的文件 SELinux type 有哪些

sesearch [-A] [-s 主体类别] [-t 目标类别] [-b 布尔值]

选项与参数:
      -A:列出后面数据中,允许「读取或放行」的相关数据
      -t:后面还要接 type、例如 -t httpd_t
      -b:后面接 SELinux 的规则,例如 -b httpd_enable_ftp_server
   
# 范例 1:找出 crond_t 主体进程能够读取的文件 SELinux type

# 范例 1:找出 crond_t 主体进程能够读取的文件 SELinux type

# sesearch -A -s crond_t | grep spool
   allow crond_t var_spool_t : dir { ioctl read getattr lock search open } ;
   allow crond_t system_cron_spool_t : dir { ioctl read getattr lock search open } ;
   allow crond_t user_cron_spool_t : lnk_file { read getattr } ;
   allow crond_t user_cron_spool_t : file { ioctl read write create getattr setattr lock append unlink link rename open } ;
   allow crond_t system_cron_spool_t : file { ioctl read write create getattr setattr lock append unlink link rename open } ;
   allow crond_t var_spool_t : file { ioctl read getattr lock open } ;
   allow crond_t cron_spool_t : file { ioctl read write create getattr setattr lock append unlink link rename open } ;
   allow daemon user_cron_spool_t : file { ioctl read write getattr lock append } ;
   allow crond_t cron_spool_t : dir { ioctl read write getattr lock add_name remove_name search open } ;
   allow crond_t user_cron_spool_t : dir { ioctl read write getattr lock add_name remove_name search open } ;
   allow crond_t user_cron_spool_t : file { ioctl read write create getattr setattr lock append unlink link rename open } ;
   allow crond_t system_cron_spool_t : file { ioctl read write create getattr setattr lock append unlink link rename open } ;
   
# allow 后面是主体进程以及文件的 SELinux type,上面数据是截取出来的
# crond_t 可以读取 system_cron_spool_t 的文件/目录类型等

# 范例 2:找出 crond_t 是否能读取 /etc/cron.d/checktime 这个我们自定义的配置文件?
# ll -Z /etc/cron.d/checktime
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 /etc/cron.d/checktime
# 两个重点:SELinux type 为 admin_home_t,一个是文件(file)

# sesearch -A -s crond_t | grep admin_home_t
   allow domain admin_home_t : dir { getattr search open } ;
   allow crond_t admin_home_t : dir { ioctl read getattr lock search open } ;
   allow userdom_filetrans_type admin_home_t : lnk_file { read getattr } ;
   allow userdom_filetrans_type admin_home_t : dir { ioctl read write getattr lock add_name remove_name search open } ;
   allow domain admin_home_t : lnk_file { read getattr } ;
   allow crond_t admin_home_t : lnk_file { read getattr } ;
   
# 发现有 crond_t admin_home_t 存在,不过这个是总体的信息
# 没有针对某些规则的查询,所以不能确定 checktime 能否被读取,但是基本上就是 SELinux type 出现问题,才无法读取的
   
現在知道了/etc/cron.d/checktime是SELinux type錯誤導致無法讀取的。看來在getsebool -a中看到的httpd_enable_homedirs是什麼?又是規範了哪些主體進程能夠讀取的SELinux type

# semanage boolean -l | grep httpd_enable_homedirs
httpd_enable_homedirs          (off,off)Allow httpd to enable homedirs
# httpd_enable_homedirs 的功能是允许 httpd 进程读取用户家目录

# 范例 3:列出该规则中,主体进程能够读取的文件SELinux type
# sesearch -A -b httpd_enable_homedirs
Found 77 semantic av rules:
   allow httpd_t user_home_type : lnk_file { read getattr } ;
   allow httpd_suexec_t user_home_type : lnk_file { read getattr } ;
   allow httpd_suexec_t user_home_dir_t : lnk_file { read getattr } ;
   allow httpd_t nfs_t : lnk_file { read getattr } ;
   allow httpd_sys_script_t nfs_t : file { ioctl read getattr lock open } ;
   allow httpd_sys_script_t cifs_t : lnk_file { read getattr } ;
   allow httpd_user_script_t user_home_type : lnk_file { read getattr } ;
   allow httpd_user_script_t user_home_type : dir { getattr search open } ;
   allow httpd_t cifs_t : file { ioctl read getattr lock open } ;
   allow httpd_sys_script_t nfs_t : dir { getattr search open } ;
   allow httpd_sys_script_t nfs_t : dir { ioctl read getattr lock search open } ;
   allow httpd_sys_script_t nfs_t : dir { getattr search open } ;
   allow httpd_sys_script_t nfs_t : dir { ioctl read getattr lock search open } ;
   allow httpd_t user_home_dir_t : dir { getattr search open } ;
   allow httpd_sys_script_t cifs_t : file { ioctl read getattr lock open } ;
   allow httpd_sys_script_t user_home_dir_t : dir { getattr search open } ;
   allow httpd_sys_script_t user_home_dir_t : lnk_file { read getattr } ;
   xxx
# 从上面的数据才可以理解,主要是放行 httpd_t 能否读取用户家目录的文件 (笔者这里是懵逼的没有看出来)
# 所以,如果该规则没有启动,基本上 httpd_t 这种进程就无法读取用户家目录下的文件
   
#修改SELinux 規則的布爾值setsebool
查詢到某個SELinux rule ,並且以seaserch 知道該規則的用途後,可以通過下面的方式來管理

setsebool [-p] [规则名称]

-P:直接将设置值写入配置文件,该设置数据未来会生效
   
# 范例 1:查询 httpd_enable_homedirs 这个规则的状态,并且修改这个规则为不同的布尔值
# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> off                        # 关闭状态
# setsebool -P httpd_enable_homedirs 1                # 开启它
# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> on
#SELinux 安全本文的修改
SELinux 對受限的主體進程沒有影響:

考慮SELinux 的三種類型
考慮SELinux的政策規則是否放行
比對SELinux type 關係
上面講解過可以通過sesearch 來找到主體進程與文件的SELinux type 關係,那麼怎麼修改文件的SELinux type,能讓主體進程讀到呢?

#使用chcon 手動修改文件的SELinux type
chcon [-R] [-t type] [-u user] [-r role] 文件
chcon [-R] --reference=范例文件 文件

选项与参数:
      -R:连同该目录下的次目录也同时修改
      -t:后面接安全性本文的类型字段,例如 httpd_sys_content_t
      -u:后面接身份识别,例如 system_u (不重要)
      -r:后面接角色,例如 system_r (不重要)
      -v:若有变化成功,将变动的结果列出来
      --reference=文件:拿某个文件档范例来修改后续接的文件的类型
   
# 范例 1:查询 /etc/hosts 的 SELinux type,并将该类型套用到 /etc/cron.d/checktime 上
# ll -Z /etc/hosts
-rw-r--r--. root root system_u:object_r:net_conf_t:s0/etc/hosts
# net_conf_t 是上面文件中的类型
# chcon -v -t net_conf_t /etc/cron.d/checktime
changing security context of '/etc/cron.d/checktime'
# ll -Z /etc/cron.d/checktime
-rw-r--r--. root root unconfined_u:object_r:net_conf_t:s0 /etc/cron.d/checktime

# 范例 2:直接以 /etc/shadow 的 type 套用
# chcon -v --reference=/etc/shadow /etc/cron.d/checktime
changing security context of '/etc/cron.d/checktime'
# ll -Z /etc/shadow /etc/cron.d/checktime
-rw-r--r--. root root system_u:object_r:shadow_t:s0    /etc/cron.d/checktime
----------. root root system_u:object_r:shadow_t:s0    /etc/shadow
   
上面的示例並不能解決crond不能讀取/etc/cron.d/checktime的問題,因為需要改成/etc/cron.d下的標準type才行。可以使用restorecon來讓SELinux自己默認解決目錄下的type問題

#使用restorecon 讓文件恢復正確的SELinux type
restorecon [-Rv] 文件或目录

选项与参数:
      -R:连同次目录一起修改
      -v:将过程显示到屏幕上
   
# 范例 3:将 /etc/cron.d/ 下的文件都恢复成预设的 SELinux type
# restorecon -Rv /etc/cron.d/
restorecon reset /etc/cron.d/checktime context system_u:object_r:shadow_t:s0->system_u:object_r:system_cron_spool_t:s0

# 上面将shadow_t 改成了 system_cron_spool_t 类型

# 范例 4:重新启动 crond 看看有没有正确启动 checktime
# systemctl restart crond         
# tail /var/log/cron
Mar 17 16:01:01 study CROND: (root) CMD (run-parts /etc/cron.hourly)
Mar 17 16:01:01 study run-parts(/etc/cron.hourly): starting 0anacron
Mar 17 16:01:01 study run-parts(/etc/cron.hourly): finished 0anacron
Mar 17 16:01:01 study run-parts(/etc/cron.hourly): starting mcelog.cron
Mar 17 16:01:01 study run-parts(/etc/cron.hourly): finished mcelog.cron
Mar 17 16:10:01 study CROND: (root) CMD (/usr/lib64/sa/sa1 1 1)
Mar 17 16:12:48 study crond: (CRON) INFO (Shutting down)
Mar 17 16:12:48 study crond: (CRON) INFO (RANDOM_DELAY will be scaled with factor 62% if used.)
Mar 17 16:12:49 study crond: (CRON) INFO (running with inotify support)
Mar 17 16:12:49 study crond: (CRON) INFO (@reboot jobs will be run at computer's startup.)
# 没有报错信息
   
從這裡看來restorecon 很方便,chcon 還是比較麻煩的

#semanage 默認目錄的安全性本文查詢與修改
為什麼restorecon 可以恢復原本的SELinux type 呢?那一定是有個地方在記錄每個文件/目錄的SELinux 默認類型

如何查詢預設的SELinux type
如何增加、修改、刪除預設的SELinux type
semanage {login|user|port|interface|fcontext|translation} -l
semanage fcontext -{a|d|m} [-frst] file_spec

选项与参数:
      fcontext:主要用在安全性本文方面的用途, -l 为查询
      -a:增加;可以增加一些目录的默认安全性本文类型设置
      -m:修改
      -d:删除
# 范例 1:查询 /etc/   /etc/cron.d/ 的预设 SELinux type
# semanage fcontext -l | grep -E '^/etc |^/etc/cron'
/etc/cron.daily(/.*)?                              all files          system_u:object_r:bin_t:s0
/etc/cron.weekly(/.*)?                           all files          system_u:object_r:bin_t:s0
/etc/cron.hourly(/.*)?                           all files          system_u:object_r:bin_t:s0
/etc/cron.monthly(/.*)?                            all files          system_u:object_r:bin_t:s0
/etc/cron.minutely/openshift-facts               regular file       system_u:object_r:openshift_cron_exec_t:s0
/etc/cron\.(daily|monthly)/acct                  regular file       system_u:object_r:acct_exec_t:s0
/etc/cron\.(daily|weekly)/sysklogd               regular file       system_u:object_r:logrotate_exec_t:s0
/etc/cron\.(daily|monthly)/mailman               regular file       system_u:object_r:mailman_queue_exec_t:s0
/etc/cron\.(daily|weekly)/man-db.*               regular file       system_u:object_r:mandb_exec_t:s0
/etc/cron\.(daily|monthly)/radiusd               regular file       system_u:object_r:radiusd_exec_t:s0
/etc/cron\.(daily|weekly)/ntp-simple               regular file       system_u:object_r:ntpd_exec_t:s0
/etc/cron\.(daily|weekly)/ntp-server               regular file       system_u:object_r:ntpd_exec_t:s0
/etc/cron\.((daily)|(weekly)|(monthly))/freeradius regular file       system_u:object_r:radiusd_exec_t:s0
/etc/cron\.d(/.*)?                                 all files          system_u:object_r:system_cron_spool_t:s0
/etc/cron\.daily/locate                        regular file       system_u:object_r:locate_exec_t:s0
/etc/cron\.weekly/(c)?fingerd                      regular file       system_u:object_r:fingerd_exec_t:s0
/etc                                             all files          system_u:object_r:etc_t:s0
/etc/crontab                                       regular file       system_u:object_r:system_cron_spool_t:s0
/etc/cron\.daily/prelink                           regular file       system_u:object_r:prelink_cron_system_exec_t:s0
/etc/cron\.daily/calamaris                         regular file       system_u:object_r:calamaris_exec_t:s0
/etc/cron\.daily/certwatch                         regular file       system_u:object_r:certwatch_exec_t:s0
/etc/cron\.monthly/proftpd                         regular file       system_u:object_r:ftpd_exec_t:s0
看/etc/cron\.d(/.*)? all files system_u:object_r:system_cron_spool_t:s0 這一行,這也是為什麼直接使用vim在/etc/cron.d下新建文件時,預設SELinux type是正確的。

練習:下面要建立一個/srv/mycron目錄,默認也是需要變成system_cron_spool_t時

# 1. 先建立 mycron 目录,再放入配置文件,观察 SELinux type
# mkdir /srv/mycron
# cp /etc/cron.d/checktime /srv/mycron/
# ll -dZ /srv/mycron/ /srv/mycron/checktime
drwxr-xr-x. root root unconfined_u:object_r:var_t:s0   /srv/mycron/
-rw-r--r--. root root unconfined_u:object_r:var_t:s0   /srv/mycron/checktime
# 发现变成了 var_t

# 2. 观察上层 /srv 的 SELinux type
# semanage fcontext -l | grep '^/srv'
/srv/.*                                          all files          system_u:object_r:var_t:s0
/srv/([^/]*/)?www(/.*)?                            all files          system_u:object_r:httpd_sys_content_t:s0
/srv/([^/]*/)?ftp(/.*)?                            all files          system_u:object_r:public_content_t:s0
/srv/([^/]*/)?rsync(/.*)?                        all files          system_u:object_r:public_content_t:s0
/srv/([^/]*/)?www/logs(/.*)?                     all files          system_u:object_r:httpd_log_t:s0
/srv/node(/.*)?                                    all files          system_u:object_r:swift_data_t:s0
/srv/gallery2(/.*)?                              all files          system_u:object_r:httpd_sys_content_t:s0
/srv/lib/gitosis(/.*)?                           all files          system_u:object_r:gitosis_var_lib_t:s0
/srv/gallery2/smarty(/.*)?                         all files          system_u:object_r:httpd_sys_rw_content_t:s0
/srv/loopback-device(/.*)?                         all files          system_u:object_r:swift_data_t:s0
/srv                                             all files          system_u:object_r:var_t:s0
# 可以看到这里默认就是var_t 类型的

# 3. 将 mycron 默认值改为 system_cron_spool_t
# semanage fcontext -a -t system_cron_spool_t "/srv/mycron(/.*)?"
# semanage fcontext -l | grep '^/srv/mycron'
/srv/mycron(/.*)?                                  all files          system_u:object_r:system_cron_spool_t:s0

# 4. 回复 /srv/mycron 以及子目录相关的 SELinux type
# restorecon -Rv /srv/mycron/
restorecon reset /srv/mycron context unconfined_u:object_r:var_t:s0->unconfined_u:object_r:system_cron_spool_t:s0
restorecon reset /srv/mycron/checktime context unconfined_u:object_r:var_t:s0->unconfined_u:object_r:system_cron_spool_t:s0
通過這個例子來看,restorecon 的確是很方便,學會這些基礎的工具,對於SELinux 來說基本上也夠用了

#一個網絡服務案例及登錄文件協助
本章在SELinux 小節中介紹到的各個指令,尤其是setsebool、chcon、restorecon 等都是為了當你的某些網絡服務無法正常提供相關功能時,才需要進行修改的一些指令動作。

可以通過主動檢查的方式來檢查是否有SELinux 產生的錯誤。而不是等客戶端聯機失敗來反饋

#setroubleshoot:錯誤信息寫入 /var/log/messages
幾乎所有SELinux相關的程序都是以se開頭,該服務時錯誤克服,啟動後,會將關於SELinux的錯誤信息與克服方法記錄到/var/log/messages與/var/log/setroubleshoot/*中

需要安装:setroubleshoot 与 setroubleshoot-server。原本 SELinux 信息是两个服务来记录的,分别是 auditd 与 setroubleshoot。在 CentOS 6.x 起整合成 auditd 了。所以安装好 setroubleshoot-server 后,需要重新启动 auditd 服务,否则 setroubleshoot 功能不会被启动

实际上。CentOS 7.x 对 setroubleshoot 的运行方式是:先由 auditd 去呼叫 audispd 服务,然后 audispd 服务启动 sedispatch 程序, sedispatch 再将原本的 auditd 信息转成 setroubleshoot 的信息,存储下来

# rpm -qa | grep setroubleshoot
setroubleshoot-3.2.30-7.el7.x86_64
setroubleshoot-plugins-3.0.67-4.el7.noarch
setroubleshoot-server-3.2.30-7.el7.x86_64
   
在预设的情况下 setroubleshoot 被安装了,记得刚安装 setroubleshoot 的话,需要重新启动 auditd 服务的、

目前我们没有任何受限的网络服务主体进程在运行,下面使用一个简单的 FTP 服务器软件示例,来了解上面讲到的许多重点应用

#实例说明:通过 vsftpd 这个 FTP 服务器来存取系统上的文件
在 CentOS 7.x 环境下, FTP 的默认服务器软件主要是 vsftpd

详细的 FTP 协议在服务器篇讲解,这里简单利用 vsftpd 与 FTP 的协议来讲解 SELinux 的问题与错误克服。

下面只接受一些简单的 FTP 知识:客户端需要使用 FTP 账户登录 FTP 服务器,有一个称为「匿名 (anonymous)」的账户可以登录系统,但是这个匿名的账户登录后,只能存取一个特定的目录,而无法脱离该目录

在 vsftpd 中,一般用户与匿名者的家目录说明如下:

匿名者:如果使用瀏覽器來聯機到FTP服務器,那預設就是使用匿名者登錄系統。匿名者的家目錄默認是在/var/ftp中,同時,匿名者在家目錄下只能下載數據,不能上傳數據到FTP服務器,同時匿名者無法離開FTP服務器的/var/ftp目錄
一般FTP 賬戶:在預設情況下,所有UID 大於1000 的賬戶,都可以使用FTP 來登錄系統,登錄系統後,所有的賬戶都能夠取得自己家目錄下的文件數據,預設也可以上傳、下載文件的
為了避免與之前章節的用戶產生誤解情況,創建一個名為ftptest 的賬戶,且賬戶密碼為myftp123

# useradd -s /sbin/nologin ftptest
# echo "myftp123" | passwd --stdin ftptest
Changing password for user ftptest.
passwd: all authentication tokens updated successfully.

   
下面來安裝vsftp 服務器軟件(還是在光盤中安裝,前面掛載那樣)

# yum install /mnt/Packages/vsftpd-3*                  

# systemctl start vsftpd                # 启动 vsftpd 服务
# systemctl enable vsftpd                # 设置为开机启动
Created symlink from /etc/systemd/system/multi-user.target.wants/vsftpd.service to /usr/lib/systemd/system/vsftpd.service.
# netstat -tlnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address         Foreign Address         State       PID/Program name   
tcp      0      0 127.0.0.1:631         0.0.0.0:*               LISTEN      1374/cupsd         
tcp      0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      1578/master         
tcp      0      0 127.0.0.1:6010          0.0.0.0:*               LISTEN      2350/sshd: mrcode@p
tcp      0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      1/systemd         
tcp      0      0 192.168.122.1:53      0.0.0.0:*               LISTEN      1975/dnsmasq      
tcp      0      0 0.0.0.0:22            0.0.0.0:*               LISTEN      1378/sshd         
tcp6       0      0 ::1:631               :::*                  LISTEN      1374/cupsd         
tcp6       0      0 ::1:25                  :::*                  LISTEN      1578/master         
tcp6       0      0 ::1:6010                :::*                  LISTEN      2350/sshd: mrcode@p
tcp6       0      0 :::111                  :::*                  LISTEN      1/systemd         
tcp6       0      0 :::21                   :::*                  LISTEN      6656/vsftpd         
tcp6       0      0 :::22                   :::*                  LISTEN      1378/sshd

# 可以看到   6656/vsftpd 这行数据,代表已经启动了

   
#匿名者無法下載的問題
模擬一些FTP的常用狀態,假設將/etc/securetty以及主要的/etc/sysctl.conf放置給所有人下載,那麼可以能會這樣做

# cp -a /etc/securetty /etc/sysctl.conf /var/ftp/pub
# ll /var/ftp/pub/
total 8
-rw-------. 1 root root 221 Oct 312018 securetty
-rw-r--r--. 1 root root 449 Aug92019 sysctl.conf


   
一般來說,默認要給用戶下載的FTP文件會放在/var/ftp/pub目錄中。下面使用簡單的終端機瀏覽器curl來觀察

# 1. 查看 FTP 根目录下有哪些内容
# curl ftp://localhost
drwxr-xr-x    2 0      0            42 Mar 17 09:03 pub
# 确实看到了 pub 目录

# 2. 查看 pub 目录内的内容
# curl ftp://localhost/pub
curl: (78) RETR response: 550
# 无法访问,是因为 pub 是一个目录需要后缀 / 结尾
# curl ftp://localhost/pub/
-rw-------    1 0      0             221 Oct 302018 securetty
-rw-r--r--    1 0      0             449 Aug 082019 sysctl.conf

# 3. 查看里面的文件内容
# curl ftp://localhost/pub/sysctl.conf
# sysctl settings are defined through files in
# /usr/lib/sysctl.d/, /run/sysctl.d/, and /etc/sysctl.d/.
#
# Vendors settings live in /usr/lib/sysctl.d/.
# To override a whole file, create a new file with the same in
# /etc/sysctl.d/ and put new settings there. To override
# only specific settings, add a file with a lexically later
# name in /etc/sysctl.d/ and put new settings there.
#
# For more information, see sysctl.conf(5) and sysctl.d(5).

# 上面不是错误信息,是哪个文件的内容

# 4. 继续查看下一个文件内容
# curl ftp://localhost/pub/securetty
curl: (78) RETR response: 550
# 这里看不到了,但是 securetty 的确是一个文件而不是一个目录,基本原因应该是权限问题
# 因为 vsftpd 默认放在 /var/ftp/pub 内的资料,无论什么 SELinux type 几乎都可以被读取才对

# 5. 修正权限后,再观察一次 securetty 文件
# ll /var/ftp/pub/
total 8
-rw-------. 1 root root 221 Oct 312018 securetty
-rw-r--r--. 1 root root 449 Aug92019 sysctl.conf
# 可以看到 securetty 的其他人权限没有。改变成其他人也可以读取
# chmod a+r /var/ftp/pub/securetty
# curl ftp://localhost/pub/securetty
console
vc/1
vc/2
vc/3
# 此时已经能看到文件内容了

# 6. 修正 SELinux type 的内容(非必须)
# restorecon -Rv /var/ftp/
restorecon reset /var/ftp/pub/securetty context system_u:object_r:etc_runtime_t:s0->system_u:object_r:public_content_t:s0
restorecon reset /var/ftp/pub/sysctl.conf context system_u:object_r:system_conf_t:s0->system_u:object_r:public_content_t:s0

   
上述列子告訴我們,要先從權限角度來檢查,如果無法被讀取,可能是因為沒有r 或則沒有rx 權限,並不一定是SELinux 引起的。下面看看用一般賬戶登錄

#無法從家目錄下載文件的問題分析與解決
由於通過一般賬戶,前面建立的ftptest 賬戶登錄的話,文字型的FTP 客戶端軟件,默認會將用戶引導在根目錄,而不是家目錄,因此,訪問的URL 需要更改一下

# 0. 在 ftptest 家目录下创建一些数据
# echo~ftptest/
/home/ftptest/
# echo "testing" >~ftptest/test.txt
# cp -a /etc/hosts /etc/sysctl.conf ~ftptest/
# ll ~ftptest/
total 12
-rw-r--r--. 1 root root 158 Jun72013 hosts
-rw-r--r--. 1 root root 449 Aug92019 sysctl.conf
-rw-r--r--. 1 root root   8 Mar 17 17:23 test.txt

# 1. 一般账户直接登录 FTP 服务器,同时变换目录到家目录
# curl ftp://ftptest:myftp123@localhost/~/
curl: (67) Access denied: 530                        # 这里报错了
# 注意:书上在增加 ftptest 用户的时候,使用的是 /sbin/nologin,就无法访问 ftp,这里修改下,就可以了
# usermod -s/bin/bash ftptest
# curl ftp://ftptest:myftp123@localhost/~/
-rw-r--r--    1 0      0             158 Jun 072013 hosts
-rw-r--r--    1 0      0             449 Aug 082019 sysctl.conf
-rw-r--r--    1 0      0               8 Mar 17 09:23 test.txt
# 看左边的权限也是没有问题的
# 从这里开始,笔者的实验和书上的结果对不上了,下面只记录书上的操作指令
# 就是因为上面修改用户的 bash 后,虽然可以访问了,但是下面的却可以下载文件,无法达到和书上的效果一样

# 2. 下载上面可以阅读的权限文件
# curl ftp://ftptest:myftp123@localhost/~/test.txt
curl:(78) RETR response:550
# 无法访下载,是否是 SELinux 造成的?

# 3. 将 SELinux 从 Enforce 转成 Permissive
# setenforce 0
# curl ftp://ftptest:myftp123@localhost/~/test.txt
testing
# setenforce 1      # 确定是 SELinux 权限问题后,改回来
# 需要该规则还是该 type?现在不知道
# 所以先查询下登录日志有没有相关的信息提供给我们处理

# vim /var/log/messages
Aug 9 02:55:58 station3-39 setroubleshoot:SELinux is preventing /usr/sbin/vsftpd
      from lock access on the file /home/ftptest/test.txt. For complete SELinux messages.
      run sealert -l 3axxxxxxxx
# 之类的字样,关键词就是 sealert ,执行这条命令
# sealert -l 3axxxxxxxx
SELinux is preventing /usr/sbin/vsftpd from lock access on the file /home/ftptest/test/txt.
# 下面说有 47.5% 的几率是由于这个原因所发生,并且可以使用 setsebool 去解决的意思
******* Plugin catchall_boolean(47.5 confidence) suggests ********

if you want to allow ftp to home dir
...
Do
setsebool -P ftp_home_dir 1

******* Plugin catchall(6.38confidence) suggests ********
DO
# grep vsftpd /var/log/audit/audit.log | audit2allow -M mypol
# semodule -i mypol.pp

# 下面就重要了,是整个问题发生的主要原因
Additional Information:
Source Context      system_u:system_r:ftpd_t:s0-s0:c0.c1023
Target Context      unconfined_u:object_r:user_home_t:s0
Target Objects      /home/ftptest/test/txt [ file ]


   
通過上面的測試,知道主要的問題發生在SElinux 的type 不是vsftpd_t 所能讀取的原因,上面47.5 的概率問題,ftp_home_dir 是SELinux rules 的配置

# 1. 确认下 SELinux 的模式,并且无法访问
# getenforce
Enforcing
# curl ftp://ftptest:myftp123@localhost/~/test.txt
curl:(78) RETR response:550
# setsebool -P ftp_home_dir 1
Boolean ftp_home_dir is not defined
# 可惜笔者这里提示没有被定义,与书上对不上啊

   
#一般賬戶用戶從非正規目錄上傳/下載文件
提供/srv/gogogo目錄給ftptest用戶使用,該如何處理?假設不考慮SELiunx的話,就是如下方式

# 1. 处理好所需要的目录数据
# mkdir /srv/gogogo
# chgrp ftptest /srv/gogogo/
# 把用户组改成 ftptest 这个组
# ll -d /srv/gogogo/
drwxr-xr-x. 2 root ftptest 22 3月17 22:43 /srv/gogogo/
# echo "test" > /srv/gogogo/test.txt
# curl ftp://ftptest:myftp123@localhost//srv/gogogo/test.txt
curl: (78) RETR response: 550
# 访问不了,查看日志
# grep sealert /var/log/messages | tail
Mar 17 22:46:35 study setroubleshoot: SELinux is preventing /usr/sbin/vsftpd from read access on the file test.txt. For complete SELinux messages run: sealert -l 88f08c09-c510-4518-bbcc-58bcee06ffb0

# sealert -l 88f08c09-c510-4518-bbcc-58bcee06ffb0
SELinux is preventing /usr/sbin/vsftpd from read access on the file test.txt.

# 虽然这个可信度很高,不过,因为会全部方向 FTP,所以不考虑
*****Plugin catchall_boolean (57.6 confidence) suggests   ******************

If you want to allow ftpd to full access
Then you must tell SELinux about this by enabling the 'ftpd_full_access' boolean.

Do
setsebool -P ftpd_full_access 1

# 因为是非正规目录的使用,所以这边加上预设 SELinux type 恐怕能解决
*****Plugin catchall_labels (36.2 confidence) suggests   *******************

If you want to allow vsftpd to have read access on the test.txt file
Then you need to change the label on test.txt
Do
# 下面这一条数据
# semanage fcontext -a -t FILE_TYPE 'test.txt'
.... 很多数据
Then execute:
restorecon -v 'test.txt'                # 还有这一条数据,都是要参考的解决方案

*****Plugin catchall (7.64 confidence) suggests   **************************

If you believe that vsftpd should be allowed read access on the test.txt file by default.
Then you should report this as a bug.
You can generate a local policy module to allow this access.
Do
allow this access for now by executing:
# ausearch -c 'vsftpd' --raw | audit2allow -M my-vsftpd
# semodule -i my-vsftpd.pp


Additional Information:
Source Context                system_u:system_r:ftpd_t:s0-s0:c0.c1023
Target Context                unconfined_u:object_r:var_t:s0
Target Objects                test.txt [ file ]
Source                        vsftpd
Source Path                   /usr/sbin/vsftpd
Port                        <Unknown>
Host                        study.centos.mrcode
Source RPM Packages         
Target RPM Packages         
Policy RPM                  selinux-policy-3.13.1-252.el7.noarch
Selinux Enabled               True
Policy Type                   targeted
Enforcing Mode                Enforcing
Host Name                     study.centos.mrcode
Platform                      Linux study.centos.mrcode 3.10.0-1062.el7.x86_64
                              #1 SMP Wed Aug 7 18:08:02 UTC 2019 x86_64 x86_64
Alert Count                   2
First Seen                  2020-03-17 22:46:17 CST
Last Seen                     2020-03-17 22:46:32 CST
Local ID                      88f08c09-c510-4518-bbcc-58bcee06ffb0

Raw Audit Messages
type=AVC msg=audit(1584456392.386:979): avc:denied{ read } forpid=10979 comm="vsftpd" name="test.txt" dev="dm-0" ino=35108539 scontext=system_u:system_r:ftpd_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:var_t:s0 tclass=file permissive=0


Hash: vsftpd,ftpd_t,var_t,file,read

# 3. 查看 /var/ftp 的 SELinux type
#ll -Zd /var/ftp/
drwxr-xr-x. root root system_u:object_r:public_content_t:s0 /var/ftp/
#ll -Zd /srv/gogogo/
drwxr-xr-x. root ftptest unconfined_u:object_r:var_t:s0   /srv/gogogo/

# 4. 以 sealert 建议的方法来处理好 SELinux type
# semanage fcontext -a -t public_content_t '/srv/gogogo(/.*)?'
# restorecon -Rv /srv/gogogo
restorecon reset /srv/gogogo context unconfined_u:object_r:var_t:s0->unconfined_u:object_r:public_content_t:s0
restorecon reset /srv/gogogo/test.txt context unconfined_u:object_r:var_t:s0->unconfined_u:object_r:public_content_t:s0
# 再次访问就可以了
# curl ftp://ftptest:myftp123@localhost//srv/gogogo/test.txt
test

   
在這個範例中,修改的是type,前一個範例中修改的是rule,不太一樣的

#無法變更FTP 聯機端口問題分析解決
比如你想要改變FTP 默認的啟動端口21 改成555,基本上,既然SELinux 的主體進程大多是被受限的網絡服務,很有可能連端口也限制了,下面嘗試修改端口,來查看是怎麼解決問題的

# 1. 先处理 vsftpd 的配置文件,加入 port 的端口参数
# vim /etc/vsftpd/vsftpd.conf
listen_port=555

# 2. 重启服务,并查看日志
# systemctl restart vsftpd
Job for vsftpd.service failed because the control process exited with error code. See "systemctl status vsftpd.service" and "journalctl -xe" for details.
# grep sealert /var/log/messages
Mar 17 23:03:23 study setroubleshoot: SELinux is preventing /usr/sbin/vsftpd from name_bind access on the tcp_socket port 555. For complete SELinux messages run: sealert -l e3e3dee0-83eb-4cb8-b894-8be590fee082

# sealert -l e3e3dee0-83eb-4cb8-b894-8be590fee082
SELinux is preventing /usr/sbin/vsftpd from name_bind access on the tcp_socket port 555.

# 这个 92.2 的概率,基本上就是这个了
*****Plugin bind_ports (92.2 confidence) suggests   ************************

If you want to allow /usr/sbin/vsftpd to bind to network port 555
Then you need to modify the port type.
Do
# semanage port -a -t PORT_TYPE -p tcp 555
    where PORT_TYPE is one of the following: certmaster_port_t, cluster_port_t, ephemeral_port_t, ftp_data_port_t, ftp_port_t, hadoop_datanode_port_t, hplip_port_t, isns_port_t, port_t, postgrey_port_t, unreserved_port_t.

*****Plugin catchall_boolean (7.83 confidence) suggests   ******************

If you want to allow nis to enabled
Then you must tell SELinux about this by enabling the 'nis_enabled' boolean.

Do
setsebool -P nis_enabled 1

*****Plugin catchall (1.41 confidence) suggests   **************************

If you believe that vsftpd should be allowed name_bind access on the port 555 tcp_socket by default.
Then you should report this as a bug.
You can generate a local policy module to allow this access.
Do
allow this access for now by executing:
# ausearch -c 'vsftpd' --raw | audit2allow -M my-vsftpd
# semodule -i my-vsftpd.pp


Additional Information:
Source Context                system_u:system_r:ftpd_t:s0-s0:c0.c1023
Target Context                system_u:object_r:hi_reserved_port_t:s0
Target Objects                port 555 [ tcp_socket ]
Source                        vsftpd
Source Path                   /usr/sbin/vsftpd
Port                        555
Host                        study.centos.mrcode
Source RPM Packages         vsftpd-3.0.2-25.el7.x86_64
Target RPM Packages         
Policy RPM                  selinux-policy-3.13.1-252.el7.noarch
Selinux Enabled               True
Policy Type                   targeted
Enforcing Mode                Enforcing
Host Name                     study.centos.mrcode
Platform                      Linux study.centos.mrcode 3.10.0-1062.el7.x86_64
                              #1 SMP Wed Aug 7 18:08:02 UTC 2019 x86_64 x86_64
Alert Count                   1
First Seen                  2020-03-17 23:03:20 CST
Last Seen                     2020-03-17 23:03:20 CST
Local ID                      e3e3dee0-83eb-4cb8-b894-8be590fee082

Raw Audit Messages
type=AVC msg=audit(1584457400.225:1008): avc:denied{ name_bind } forpid=11443 comm="vsftpd" src=555 scontext=system_u:system_r:ftpd_t:s0-s0:c0.c1023 tcontext=system_u:object_r:hi_reserved_port_t:s0 tclass=tcp_socket permissive=0


type=SYSCALL msg=audit(1584457400.225:1008): arch=x86_64 syscall=bind success=no exit=EACCES a0=4 a1=55e9e4d4e800 a2=1c a3=3 items=0 ppid=11440 pid=11443 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm=vsftpd exe=/usr/sbin/vsftpd subj=system_u:system_r:ftpd_t:s0-s0:c0.c1023 key=(null)

Hash: vsftpd,ftpd_t,hi_reserved_port_t,tcp_socket,name_bind

# 3. 根据建议解决执行指令, 92% 哪个指令下面 PORT_TYPE 下面又可选的 ftp_port_t
# 但是笔者还是懵逼的,不知道为什么那么多里面就选这个了
# semanage port -a -t ftp_port_t -p tcp 555
# systemctl restart vsftpd
# netstat -tlnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address         Foreign Address         State       PID/Program name   
tcp      0      0 127.0.0.1:631         0.0.0.0:*               LISTEN      1374/cupsd         
tcp      0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      1578/master         
tcp      0      0 127.0.0.1:6010          0.0.0.0:*               LISTEN      2350/sshd: mrcode@p
tcp      0      0 127.0.0.1:6011          0.0.0.0:*               LISTEN      10579/sshd: root@pt
tcp      0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      1/systemd         
tcp      0      0 192.168.122.1:53      0.0.0.0:*               LISTEN      1975/dnsmasq      
tcp      0      0 0.0.0.0:22            0.0.0.0:*               LISTEN      1378/sshd         
tcp6       0      0 ::1:631               :::*                  LISTEN      1374/cupsd         
tcp6       0      0 ::1:25                  :::*                  LISTEN      1578/master         
tcp6       0      0 ::1:6010                :::*                  LISTEN      2350/sshd: mrcode@p
tcp6       0      0 ::1:6011                :::*                  LISTEN      10579/sshd: root@pt
tcp6       0      0 :::555                  :::*                  LISTEN      11573/vsftpd      
tcp6       0      0 :::111                  :::*                  LISTEN      1/systemd         
tcp6       0      0 :::22                   :::*                  LISTEN      1378/sshd   
# 可以看到 vsftpd 的端口变成了 555 了

# 4. 实验看看该 port 是否可用
# curl ftp://localhost:555
drwxr-xr-x    2 0      0            42 Mar 17 09:03 pub

文章出處
頁: [1]
查看完整版本: SELinux 連線端口問題分析解決