一.介紹
1.1百度百科
SELinux(Security-Enhanced Linux) 是美國國家安全局(NSA)對于強制通路控制的實作,是 Linux曆史上最傑出的新本機安全性授權。NSA是在Linux社群的幫助下開發了一種通路控制體系,在這種通路控制體系的限制下,程序隻能通路那些在他的任務中所需要檔案。SELinux 預設安裝在 Fedora 和 Red Hat Enterprise Linux 上,也可以作為其他發行版上容易安裝的包得到。
SELinux 是 2.6 版本的 Linux 核心中提供的強制通路控制(MAC)系統。對于可用的 Linux安全子產品來說,SELinux 是功能最全面,而且測試最充分的,它是在 20 年的 MAC 研究基礎上建立的。SELinux 在類型強制伺服器中合并了多級安全性或一種可選的多類政策,并采用了基于角色的通路控制概念。 [1]
大部分使用 SELinux 的人使用的都是 SELinux 就緒的發行版,例如 Fedora、Red Hat Enterprise Linux (RHEL)、Debian或 Centos。它們都是在核心中啟用 SELinux 的,并且提供一個可定制的安全政策,還提供很多使用者層的庫和工具,它們都可以使用 SELinux 的功能。
SELinux是一種基于 域-類型 模型(domain-type)的強制通路控制(MAC)安全系統,它由NSA編寫并設計成核心子產品包含到核心中,相應的某些安全相關的應用也被打了SELinux的更新檔,最後還有一個相應的安全政策。任何程式對其資源享有完全的控制權。假設某個程式打算把含有潛在重要資訊的檔案扔到/tmp目錄下,那麼在DAC情況下沒人能阻止他。SELinux提供了比傳統的UNIX權限更好的通路控制。
1.2概念
安全增強型 Linux(Security-Enhanced Linux)簡稱 SELinux,它是一個 Linux 核心子產品,也是 Linux 的一個本機安全性授權。
SEAndroid是Google在Android 4.4上正式推出的一套以SELinux為基礎于核心的系統安全機制。
SELinux 主要作用就是最大限度地減小系統中服務程序可通路的資源(最小權限原則)
1.3作用
SELinux 主要作用就是最大限度地減小系統中服務程序可通路的資源(最小權限原則)。
在沒有使用 SELinux 的作業系統中,決定一個資源是否能被通路的因素是:某個資源是否擁有對應使用者的權限(讀、寫、執行)。隻要通路這個資源的程序符合以上的條件就可以被通路。程序理論上所擁有的權限與執行它的使用者的權限相同。比如,以root使用者啟動Browser,那麼Browser就有root使用者的權限,在Linux系統上能幹任何事情。root 使用者不受任何管制,系統上任何資源都可以無限制地通路。
在使用了 SELinux 的作業系統中,決定一個資源是否能被通路的因素除了上述因素之外,還需要判斷每一類程序是否擁有對某一類資源的通路權限。
這樣一來,即使程序是以 root 身份運作的,也需要判斷這個程序的類型以及允許通路的資源類型才能決定是否允許通路某個資源。程序的活動空間也可以被壓縮到最小。
即使是以 root 身份運作的服務程序,一般也隻能通路到它所需要的資源。即使程式出了漏洞,影響範圍也隻有在其允許通路的資源範圍内,安全性大大增加。
二.SELinux Policy語言介紹
Linux中一切皆檔案,而操作檔案的為程序。:程序能發起動作,例如它能打開檔案并操作它。而檔案隻能被程序操作。我們這裡可以看做主體對客體進行某種動作。
1. 主體(Subject)
可以完全等同于程序。
2. 對象(Object)
被主體通路的資源。可以是檔案、目錄、端口、裝置等
3. 政策和規則(Policy & Rule)
Xx域的程序(subject)是否可以對xx類的對象(object)進行xx操作 ===>Access decisions
給檔案或者程序打上安全上下文标簽 ===>Transition decisions
4.安全上下文(Security Context)
程序安全上下文和檔案安全上下文對應上,程序才能通路檔案。它們的對應關系由政策中的規則決定。
安全上下文有四個字段,分别用冒号隔開。形如:u:object_r:init_exec:s0
•u為user的意思。SEAndroid中定義了一個SELinux使用者,值為u。
•r為role的意思。role是角色之意,它是SELinux中一種比較高層次,更友善的權限管理思路,即Role Based Access Control(基于角色的通路控制,簡稱為RBAC)。簡單點說,一個u可以屬于多個role,不同的role具有不同的權限。
•init_exec,代表該檔案所屬的type為init_exec。如果是程序,該字段通常稱為domain。MAC的基礎管理思路其實不是針對上面的RBAC,而是所謂的Type Enforcement Accesc Control(簡稱TEAC,一般用TE表示)。對程序來說,Type就是Domain。Domain有什麼權限,都需要政策和規則說明。
•S0和SELinux為了滿足軍用和教育行業而設計的Multi-Level Security(MLS)機制有關。簡單點說,MLS将系統的程序和檔案進行了分級,不同級别的資源需要對應級别的程序才能通路。
RBAC是基于TE的,而TE也是SELinux中最主要的部分。 type 是通路決定的主要組成部分。
SELinux中安全政策檔案有自己的一套文法格式:
rule_name source_type target_type : class perm_set 最常見的allow的語句,格式一般為:
allow scontext tcontext:tclass perm_set : 允許scontext域的程序對tcontext類型的tclass對象去執行perm_set操作
例如:allow netd proc:file write:允許netd域中的程序對proc類型的file進行寫操作
allow:TE的allow語句,表示授權。除了allow之外,還有allowaudit、dontaudit、neverallow等。netd:source type。也叫subject,domain。
proc:target type。它代表其後的file所對應的Type。
file:代表Object Class。它代表能夠給subject操作的一類東西。例如File、Dir、socket等。在Android系統中,有一個其他Linux系統沒有的Object Class,那就是Binder。
write:在該類Object Class中所定義的操作。
Rule Name:
rule_name一共有四種,定義如下:
1)allow:賦予某項權限;
2)allowaudit:audit含義就是記錄某項操作,預設情況下SELinux隻記錄那些權限檢查失敗的操作。allowaudit則使得權限檢查成功的操作也被記錄。注意:allowaudit隻是允許記錄,它和賦予權限沒有關系。賦予權限必須且隻能使用allow語句。
3)dontaudit:對那些權限檢查失敗的操作不做記錄;
4)neverallow:檢查安全政策檔案中是否有違反該項操作的allow語句;
Type
在任何情況下,都不應直接允許域通路以下通用标簽;而應為一個或多個對象建立一個更具體的類型:也就是需要自定義type,然後讓type繼承自這些類型,一個type可以關聯多個attribute;
socket_device
device
block_device
default_service
system_data_file
tmpfs
….
SELinux是基于Domain-Type的強制類型通路模型,Domain其實也是Type,它隻是對程序類型的習慣稱呼;它隻是對程序類型的習慣稱呼,和Type相關的指令主要由三個:
1)type:類型聲明,可以直接在定義的時候,就賦予屬性,type指令的完整格式為:
type type_id [attribute_id][attribute_id] …;
其中方括号中的内容為可選項,attribute_id表示與type_id相關聯的屬性,一個type可以關聯多個attribute;
例如下面定義了一個名為shell的type,它和一個名為domain的屬性(attribute)關聯:
type shell, domain;// shell繼承 domain,也就是說shell是一個程序
type sysfs, fs_type, sysfs_type; //sysfs 繼承fs_type, sysfs_type,也就是檔案
2)attribute:屬性,屬性其實是一個特殊的type,可以把屬性看成是type的集合,為屬性設定的政策,适用于所有與該屬性相關聯的type,如下:
attribute fs_type; # 聲明fs_type屬性
attribute sysfs_type; # 聲明sysfs_type屬性
# 允許init程序對sysfs_type類型集合的所有目錄,檔案執行relabelto操作
allow init sysfs_type:{ dir file lnk_file } relabelto;
注意:attributes檔案中定義了SEAndroid中使用的所有屬性;
3)typeattribute:單獨給type賦予屬性,在此之前需要先定義type類型,如下:
Typeattribute system mlstrustedsubject;
關鍵字 type attibute
特别注意:對于初學者而言,attribute和type的關系最難了解,因為”attribute”這個關鍵字實在沒取好名字,很容易産生誤解:
a)實際上,type和attribute位于同一個命名空間,即不能用type指令和attribute指令定義相同名字的東西;
b)其實,attribute真正的意思應該是類似typegroup這樣的概念。比如将type A和attributeB關聯起來,就是說type A屬于attributeB中的一員;
Object Class
ObjectClass聲明了程序要操作的對象類,security_classes檔案定義了SEAndroid中用到的所有class;
class關鍵字用于聲明objectclass類型:
# file-related classes
class file # 檔案
class dir # 目錄
class fd # 檔案描述符
class lnk_file # 連結檔案
class chr_file # 字元裝置檔案
class blk_file # 塊裝置檔案
… …
# network-related classes
class socket
class tcp_socket
class udp_socket
…..
Perm Set
perm_set指的是某種ObjectClass所擁有的操作,以file類而言,就包括open,read, write等操作;和Object Class一樣,SEAndroid所支援的permset的聲明在access_vectors檔案中;
SELinux規範中,定義permset有兩種方式:
1)common:其指令的格式為:
commoncommon_name { permission_name … }
以下是file類對應的權限(permset),大部分各位都能猜出來是幹什麼的:
common file {
ioctl read write create getattr setattr lock relabelfrom relabelto
append unlink link rename execute swapon quotaon mounton }
2)class:除了common外,還有一種class指令也可以設定permset,class指令可以繼承common定義的permset;
class指令的完整格式為:
class class_name [inherits common_name] {permission_name … }
inherits表示繼承某個common定義的權限,如下:
class dir inherits file {
add_name remove_name reparent search rmdir open audit_access
execmod }
三.常用指令
SELinux是經過安全強化的Linux作業系統,一些原有的指令都進行了擴充,另外還增加了一些新的指令,下面讓我們看看經常用到的幾個指令:
1)ls -Z指令檢視檔案,目錄的安全屬性:
[email protected]:/ # ls –Z
drwxr-x--x root sdcard_r u:object_r:rootfs:s0 storage
dr-xr-xr-x root root u:object_r:sysfs:s0 sys
drwxr-xr-x root root u:object_r:system_file:s0 system
… …
2)ps -Z指令檢視程序的安全屬性:
[email protected]:/ # ls -Z
u:r:rild:s0 radio 272 1 /system/bin/rild
u:r:drmserver:s0 drm 273 1 /system/bin/drmserver
u:r:mediaserver:s0 這個還是 media 274 1 /system/bin/mediaserver
u:r:installd:s0 install 283 1 /system/bin/installd
3)chcon指令更改檔案的安全屬性
A101LV:/mnt # ls -Z 1.txt
u:object_r:appdomain_tmpfs:s0 1.txt
chcon u:object_r:storage_file:s0 1.txt
A101LV:/mnt # ls -Z 1.txt
u:object_r:storage_file:s0 1.txt
4)restorecon指令當檔案的安全屬性在安全政策配置檔案裡面有定義時,使用restorecon指令,可以恢複原來的安全屬性
restorecon 1.txt
SELinux: Loaded file_contexts
5)id指令使用id指令,能确認自己的SecurityContext
A101LV:/mnt # id
uid=0(root) gid=0(root) groups=0(root),1004(input),1007(log),1011(adb),1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats),3009(readproc),3011(uhid) context=u:r:su:s0
6)getenforce指令得到目前SELinux的模式值
A101LV:/mnt # getenforce
Enforcing
7)setenforce指令更改目前的SELINUX的模式值,後面可以跟 enforcing,permissive 或者1,0。
安全增強型 Linux (SELinux) 是适用于 Linux 作業系統的強制通路控制 (MAC) 系統
A101LV:/mnt # setenforce 0
A101LV:/mnt # getenforce
Permissive
A101LV:/mnt # setenforce 1
A101LV:/mnt # getenforce
Enforcing
Enforcing:seLinux已經打開;
Permissive:seLinux已經關閉;
8)檢視selinux權限問題
adb shell dmesg -c |grep avc
audit: type=1400 audit(16149.949:4): avc: denied { write } for pid=399 comm="init" name="vendor" dev="tmpfs" ino=988 scontext=u:r:vendor_init:s0 tcontext=u:object_r:tmpfs:s0 tclass=dir permissive=0
四.添權重限
了解selinux基本概念後,這裡簡單介紹一些權限的添加方法。
程序類型定義,vendor_init.te檔案中:
type vendor_init, domain, mlstrustedsubject;
給建立對象打上label
如在file.te裡面添加:
type tmpfs, fs_type;
….
例如:
audit: type=1400 audit(16149.949:4): avc: denied { write } for pid=399 comm="init" name="vendor" dev="tmpfs" ino=988 scontext=u:r:vendor_init:s0 tcontext=u:object_r:tmpfs:s0 tclass=dir permissive=0
可以解讀為scontext=u:r:vendor_init:s0 的主體(程序)對tcontext=u:object_r:tmpfs:s0的tclass=dir對象缺少{ write } 權限。
為了解決這個權限問題,我們添加vendor_init.te檔案,内容為:
allow vendor_init tmpfs:dir { write };
注意,解決了這個問題後,可能會引入新的權限問題,我們再根據新的avc去添加。
五.快速驗證
修改之後,怎麼快速驗證?
mmm system/sepolicy && make sepolicy
生成out目錄下,注意有兩個目錄:
system/etc/sepolicy---Android 原生的,建議不動。如果修改,會影響CTS
vendor/etc/sepolicy---第三方廠家修改。
特别說明:
system/sepolicy/Android.mk中定義了一些屬性
BOARD_SEPOLICY_DIRS ##此宏涉及到的目錄,會編譯到vendor/etc/sepolicy下
PLAT_PUBLIC_POLICY ##此宏涉及到的目錄,會當成system/sepolicy/public
PLAT_PRIVATE_POLICY##此宏涉及到的目錄,會當成system/sepolicy/private
另外,單獨編譯後,會發現都會有對應的生成目錄:out/target/product/xxx/vendor/etc/selinux/
Allow語句會在vendor_sepolicy.cil檔案中,最後push到闆子/vendor/etc/selinux下
六.萬能公式
audit(1599450077.672:2048): avc: denied { open } for comm=".android.camera" path="/dev/__properties__/u:object_r:vendor_default_prop:s0" dev="tmpfs" ino=297 scontext=u:r:platform_app:s0:c512,c768 tcontext=u:object_r:vendor_default_prop:s0 tclass=file permissive=0 app=com.android.camera
某個scontext對某個tclass類型的tcontext缺乏某個權限,我們需要允許這個權限:
我們的log重新排列一下,
scontext = u:r:platform_app
tcontex t= u:object_r:vendor_default_pro:s0
tclass = file
avc: denied { open }
得到萬能套用公式如下:
在scontext所指的.te檔案(例如platform_app.te)中加入類似如下allowe内容:
allow platform_app vendor_default_pro:file open;
七.其它
1. 有時候avc denied的log不是一次性暴露所有權限問題,要等解決一個權限問題之後,才會暴露另外一個權限問題。比如提示缺少某個目錄的read權限,加入read之後,才顯示缺少write權限,要一次次一次試,一次一次加,時間成本極大。
針對dir缺少的任何權限,建議賦予create_dir_perms,基本涵蓋對dir的所有權限,比如:
{ open search write read rename create rmdir getattr }等等。
針對file缺少的任何權限,建議賦予rwx_file_perms,基本涵蓋對file的所有權限,比如:
包含{ open read write open execute getattr create ioctl }等等。
更多内容請參考external/sepolicy/global_macros來了解更多權限聲明。
2. 要加入的權限很多時,可以用中括号,比如:
allow engsetmacaddr vfat:dir { search write add_name create};
3. 修改A位置的.te檔案遇到編譯錯誤怎麼辦?
(首先請排除拼寫錯誤)說明此項權限是SELinux明确禁止的,也是Google CTS禁止的,如果産品不需要過CTS,可以修改。一般來說,編譯出錯的log會提示相關哪個檔案哪一行出錯,檔案位置一定會在B裡的.te檔案。比如B規定了以下neverallow,
neverallow system_server sdcard_type:dir { open read write };
那麼system_server是不能擁有這些權限的,如果賦予這些權限就編譯報錯,解決方法是根據編譯錯誤提示的行号,把這一句注釋掉即可。
4. ubuntu下面自動轉換avc語句為selinux語句
grep -r avc sdcard.log > avc.log ; audit2allow -i avc.log
5. genfscon的文法是:
genfscon fs_type pathprefix [-file_type] context
把/proc/mtk_demo/demo_file檔案的安全上下文設定成demo_context
genfscon proc /mtk_demo/demo_file u:object_r:demo_context:s0
6.核心子產品
最終SELinux的實作是依賴于Linux提供的Linux Security Module架構簡稱為LSM。其實LSM的名字并不是特别準确,因為他并不是Linux子產品,而是一些列的hook,同樣也不提供任何的安全機制。LSM的的重要目标是提供對linux接入控制子產品的支援。
Linux Security Module Framework
LSM 在核心資料結構中增加了安全字段,并且在重要的核心代碼(系統調用)中增加了hook。可以在hook中注冊回調函數對安全字段進行管理,以及執行接入控制。
AVC架構圖
完整的selinux架構圖