詳解SELinux故障排查和陷阱規避
譯文【51CTO.com快譯】維護我們服務器的安全是一項艱巨的工作,與第三方解決方案提供商打交道時尤為如此。在許多情況下,面臨的挑戰是要求禁用SELinux,以便應用程序可以順利運行。幸好,這種情況越來越少了。在大多數情況下,一番分析足以找到正確的故障排查或解決方法。
SELinux是一個標簽系統,它告訴我們系統中的每個文件、目錄或對象都有對應的標簽(Label)。策略控制這些元素之間的交互關系,內核則執行這些規則。
兩個最重要的概念是標簽(文件、進程和端口等)和類型強制(根據進程的類型將進程彼此隔離開來)。
標簽使用的格式為:user:role:type:level(可選)。
要找出當前配置,請運行getenforce和sestatus兩個命令:
- # getenforce
- Enforcing
- # sestatus
- SELinux status: enabled
- SELinuxfs mount: /sys/fs/selinux
- SELinux root directory: /etc/selinux
- Loaded policy name: targeted
- Current mode: enforcing
- Mode from config file: enforcing
- Policy MLS status: enabled
- Policy deny_unknown status: allowed
- Memory protection checking: actual (secure)
- Max kernel policy version: 32
最佳實踐告訴我們,我們測試一個新的第三方應用程序時,應該在許可模式下臨時配置SELinux,以便確定哪些策略或布爾值(更改行為的簡單字符串)必不可少。運行該命令:
- # setenforce 0
查看日志,您可以找到SELinux使應用程序正常運行所需的條件。
SELinux試圖告訴我什么?
SELinux中生成警報的錯誤只有四個主要原因:
- 標簽。
- SELinux需要知道。
- SELinux策略及/或應用程序可能有錯誤。
- 您的信息可能被泄露。
最后一種情況是由于對攻擊漏洞進行了修改或避免了活動跟蹤,不過在這兩種情況下,都必須查看這些警報,這點暫且不介紹。
標簽
標簽問題:/srv/myweb中的文件未正確標記,因而無法訪問。
SELinux為同一服務所涉及的每個元素分配一個標簽:
- 二進制文件:/usr/sbin/httpd→httpd_exec_t
- 配置文件:/etc/httpd→httpd_config_t
- 日志文件:/var/log/httpd→httpd_log_t
- 內容目錄:/var/www/html→httpd_sys_content_t
- 啟動腳本:/usr/lib/systemd/system/httpd.service→httpd_unit_file_t
- 進程:/usr/sbin/httpd→httpd_t
- 端口:80/tcp,443/tcp→httpd_t和httpd_port_t
在Web服務器上,在httpd_t上下文中運行的進程只能與帶有httpd_something_t標簽的對象進行交互。
解決方案:正確標記文件。
如果您知道正確的標簽,請運行:
- # semanage fcontext -a -t httpd_sys_content_t '/srv/myweb(/.*)?'
如果您知道擁有相等標簽的文件,請運行:
- # semanage fcontext -a -e /srv/myweb /var/www
針對這兩種情況,恢復文件的默認上下文:
- # restorecon -vR /srv/myweb
標簽問題:如果某個文件被移動而不是被拷貝,它保留原始標簽。
- $ mv index.html /var/www/html/
解決方案:正確標記文件。
將上下文更換成正確的標簽:
- # chcon -t httpd_system_content_t /var/www/html/index.html
更換擁有參考標簽的上下文:
- # chcon --reference /var/www/html/ /var/www/html/index.html
針對這兩種情況,恢復文件的默認上下文:
- # restorecon -vR /var/www/html/
SELinux需要知道
服務定制:Web服務器將在端口8585上偵聽請求。
要把所需的端口添加到上下文,請運行:
- # semanage port -a -t http_port_t -p tcp 8585
為服務添加功能:Web服務器將能夠發送電子郵件。
要啟用郵件發送功能,開啟布爾值,運行:
- # setsebool -P httpd_can_sendmail 1
-P標志使變更在布爾值中具有持久性。
要獲得所有布爾值,運行:
- # getsebool -a
要檢查布爾值的狀態,運行:
- # semanage boolean -l
策略故障排查
服務未運行:使用wicd而不是NetworkManager服務來處理無線連接。
檢查audit.log文件,查找被拒絕的訪問:
- # grep denied audit.log | cut -d{ -f2 | sort -n | uniq -u
- create } for pid=2670 comm="wicd" scontext=system_u:system_r:NetworkManager_t:s0 tcontext=system_u:system_r:NetworkManager_t:s0 tclass=appletalk_socket permissive=1
- create } for pid=2670 comm="wicd" scontext=system_u:system_r:NetworkManager_t:s0 tcontext=system_u:system_r:NetworkManager_t:s0 tclass=ax25_socket permissive=1
- ioctl } for pid=2670 comm="wicd" path="socket:[52681]" dev="sockfs" ino=52681 ioctlcmd=0x8b01 scontext=system_u:system_r:NetworkManager_t:s0 tcontext=system_u:system_r:NetworkManager_t:s0 tclass=ax25_socket permissive=1
- ioctl } for pid=2670 comm="wicd" path="socket:[52684]" dev="sockfs" ino=52684 ioctlcmd=0x8b01 scontext=system_u:system_r:NetworkManager_t:s0 tcontext=system_u:system_r:NetworkManager_t:s0 tclass=appletalk_socket permissive=1
- setattr } for pid=2214 comm="wicd" name="dhclient.conf.template" dev="dm-0" ino=437068 scontext=system_u:system_r:NetworkManager_t:s0 tcontext=unconfined_u:object_r:etc_t:s0 tclass=file permissive=0
注意:上下文NetworkManager_t和etc_t所涉及的一些元素需要權限,需要訪問不同的文件和套接字創建。
創建type enforcement (.te)文件,擁有策略的必要權限:
- # vi my_wicd.te
- module my_wicd 1.0;
- require {
- type NetworkManager_t;
- type etc_t;
- class ipx_socket create;
- class ax25_socket { create ioctl };
- class appletalk_socket { create ioctl };
- class file setattr;
- }
- #============= NetworkManager_t ==============
- allow NetworkManager_t etc_t:file setattr;
- allow NetworkManager_t self:appletalk_socket { create ioctl };
- allow NetworkManager_t self:ax25_socket { create ioctl };
- allow NetworkManager_t self:ipx_socket create;
要編譯策略,安裝軟件包selinux-policy-devel,并生成策略軟件包:
- # make -f /usr/share/selinux/devel/Makefile my_wicd.pp
要激活剛生成的模塊,運行:
- # semodule -i my_wicd.pp
策略錯誤信息:試圖訪問我的網站時,我在日志中看到了SELinux錯誤。
為SELinux錯誤信息排查故障時常見的陷阱之一是,根據發現的所有錯誤信息創建策略。在大多數情況下,如果setroubleshoot包已安裝,同樣的提醒會給出所有可能的變通選項,按最好到最差的順序排列。
要查看今天生成的setroubleshoot提醒,運行:
- # journalctl -t setroubleshoot --since today
- Dec 08 13:08:33 lab.example.com setroubleshoot[12013]: failed to retrieve rpm info for /var/www/html/index.html
- Dec 08 13:08:34 lab.example.com setroubleshoot[12013]: SELinux is preventing /usr/sbin/httpd from getattr access on the file /var/www/html/index.html. For complete SELinux messages run: sealert -l 011df984-4eb6-4079-98ab-cba173c4342e
- Dec 08 13:08:34 lab.example.com setroubleshoot[12013]: SELinux is preventing /usr/sbin/httpd from getattr access on the file /var/www/html/index.html.
- ***** Plugin restorecon (99.5 confidence) suggests ************************
- If you want to fix the label
- /var/www/html/index.html default label should be httpd_sys_content_t.
- Then you can run restorecon. The access attempt may have been stopped due to insufficient permissions to access a parent directory, in which case try to change the following command accordingly.
- Do
- # /sbin/restorecon -v /var/www/html/index.html
- ***** Plugin catchall (1.49 confidence) suggests **************************
- If you believe that httpd should be allowed getattr access on the index.html 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 'httpd' --raw | audit2allow -M my-httpd
- # semodule -X 300 -i my-httpd.pp
在這里,最好的解決辦法就是修復文件的標簽。
小結
為SELinux排查故障可能很難,但如果運用這里介紹的幾個概念,并了解服務的組成,您就可以處理它帶來的各種難題。
切記:SELinux是一種標簽系統。
原文標題:SELinux troubleshooting and pitfalls,作者:Alex Callejas
【51CTO譯稿,合作站點轉載請注明原文譯者和出處為51CTO.com】