版權說明:本文為 開開向前沖 原創文章,轉載請注明出處;
注:限于作者水平有限,文中有不對的地方還請指教
1. SContext 安全上下文
根據SELinux規范,標準的SContext字符串格式為:
user:role:type[:range]
- 查看進程的SContext :ps -Z,
ps -Z.png
android 中進程的user 為 u,u在/external/sepolicy/users中定義;
android 中進程的role 為 r,r在/external/sepolicy/roles中定義;
type 是進程的domain type,一般是在進程對應的te中指定,例如進程/system/bin/sh對應的te文件在/external/sepolicy/shell.te中有 type shell, domain, mlstrustedsubject; ;
[:range]代表可選,這里是s0;這里不做詳解;
------> /external/sepolicy/users
user u roles { r } level s0 range s0 - mls_systemhigh;
------> /external/sepolicy/roles
role r;
role r types domain;
------> /external/sepolicy/shell.te
# Domain for shell processes spawned by ADB or console service.
type shell, domain, mlstrustedsubject;#指定shell 進程屬于domain域為shell
type shell_exec, exec_type, file_type;
查看文件的SContext:ls -Z
ls -Z.png
android 中進程的user 為 u,u在/external/sepolicy/users中定義;同進程一樣
android 中文件的role 為 object_r;android 中對于"死東西"(文件)都用object_r來表示role;
type 是文件的domain type;一般定義在/external/sepolicy/file.te中,例如:type rootfs, fs_type;
[:range]代表可選,這里是s0;
SeAndroid 編譯生效檢查:修改.te文件后,(前提是先編譯過android)remake android,編譯成功后去到/out/target/product/xxxx/obj/ETC/sepolicy_intermediates/目錄下的policy.conf文件中看看你的修改是否有效;如果有效,則證明你的修改成功,再make boot img,make boot img會將上述目錄中的sepolicy打包進boot.img,這樣刷boot.img就能驗證你的修改是否有效;
Selinux核心思想就是最小權限原則,即主體對客體擁有的權限必須要通過allow語句定義才允許,否則的話,一切都是禁止的。
安全上下文中,只有 類型(Type)才是最重要的,SELinux用戶、SELinux角色和安全級別都幾乎可以忽略不計的。正因為如此,SEAndroid安全機制又稱為是基于TE(Type Enforcement)策略的安全機制 ——摘自老羅
SEAndroid中,通常將標注文件的安全上下文的類型稱為file_type,將標注進程的安全上下文的類型稱為domain,每一個用于描述文件上下文的類型都將file_type 設置為其屬性,每一個用于描述進程安全上下文的類型都將domain設置為其屬性。
可以通過 type 語句實現將一個類型設置為另一個類型的屬性:
type printerserver, domain; #### 將domain 設置為printerserver的屬性
type persist_file, file_type; #### 將file_type設置為persist_file的屬性
上述語句也表明用 printerserver描述的類型描述的是進程的安全上下文;
persist_file描述的類型描述的是文件的安全上下文;
Linux Android系統中第一個啟動的進程是init進程。Init進程啟動過程中,執行了很多的系統初始化工作,其中就包括初始化SEAndroid安全策略的工作,如下所示:init.c的main方法中會調用selinux_initialize方法初始化Selinux,可以通過修改is_enforcing的值(0或者1)來控制是否禁掉Selinux。
------>/system/core/init/init.c
static void selinux_initialize(void)
{
if (selinux_is_disabled()) {
return;
}
INFO("loading selinux policy\n");
if (selinux_android_load_policy() < 0) {
ERROR("SELinux: Failed to load policy; rebooting into recovery mode\n");
android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
while (1) { pause(); } // never reached
}
selinux_init_all_handles();
bool is_enforcing = selinux_is_enforcing();
INFO("SELinux: security_setenforce(%d)\n", is_enforcing);
security_setenforce(is_enforcing);//is_enforcing控制是否禁掉Selinux
}
下面說說/external/sepolicy/目錄下幾個重要的文件;
attritbutes:屬性文件,定義了Selinux的屬性;
------> attritbutes
######################################
# Attribute declarations
# All types used for devices.
attribute dev_type;
# All types used for processes.
attribute domain; ###是不是很熟悉,我們在定義進程 Type 時都要指定這個屬性
# All types used for filesystems.
attribute fs_type;
......
device.te:描述Linux 設備 Type
------>device.te
# Device types
type device, dev_type, fs_type;
type alarm_device, dev_type, mlstrustedobject;
type adb_device, dev_type;
type ashmem_device, dev_type, mlstrustedobject;
type audio_device, dev_type;
type binder_device, dev_type, mlstrustedobject;
type block_device, dev_type;
type camera_device, dev_type;
type dm_device, dev_type;
......
file.te:描述Linux 文件 Type
------> file.te
# Persist file types
type persist_file, file_type;
type persist_data_file, file_type;
type persist_drm_file, file_type;
......
file_contexts:文件file_contexts通過正則表達式來描述系統文件的安全上下文,Linux系統中一切皆文件,前面的device.te和file.te中都都有指定設備和文件Type,這些Type是怎么和系統中的設備和文件關聯的呢?就是通過file_contexts文件;
------> file_contexts
###################################
# data files
#
/data/connectivity(/.*)? u:object_r:cnd_data_file:s0
/data/data_test(/.*)? u:object_r:data_test_data_file:s0
/data/diag_log(/.*)? u:object_r:diag_data_file:s0
/data/hlos_rfs(/.*)? u:object_r:rfs_shared_hlos_file:s0
/data/camera(/.*)? u:object_r:camera_socket:s0
/data/system/sensors(/.*)? u:object_r:sensors_data_file:s0
/data/time/* u:object_r:time_data_file:s0
/data/nfc(/.*)? u:object_r:nfc_data_file:s0
/data/system/perfd(/.*)? u:object_r:mpctl_data_file:s0
......
根據SELinux規范,完整的 allow 相關的語句格式為:
rule_name source_type target_type : class perm_set
allow zygote shell_data_file:dir search;###這句話表示允許Zygote 進程對shell_data_file類型的 dir 進行search;
這里的 dir 和 search稱為object class和perm set,即可以在object class對象上進行perm set操作;object class定義在security_classes中,perm set定義在access_vectors中;
security_classes:定義被保護的object class對象,例如file,dir,fd等;
------> security_classes
# Define the security object classes
# file-related classes
class filesystem
class file
class dir
class fd
class lnk_file
class chr_file
class blk_file
class sock_file
class fifo_file
access_vectors:定義security_classes中object class對象具有哪些perm set;
------> access_vectors
#
# Define a common prefix for file access vectors.
#
common file
{
ioctl
read
write
create
getattr
setattr
lock
relabelfrom
relabelto
append
unlink
link
rename
execute
swapon
quotaon
mounton
}
......
上面說明了可以對被保護的 file 進行ioctl read write create等操作;
mac_permissions.xml:
<?xml version="1.0" encoding="utf-8"?>
<policy>
<!-- Platform dev key in AOSP -->
<signer signature="@PLATFORM" >
<seinfo value="platform" />
</signer>
<!-- All other keys -->
<default>
<seinfo value="default" />
</default>
</policy>
文件mac_permissions.xml給不同簽名的App分配不同的seinfo字符串,例如,在AOSP源碼環境下編譯并且使用平臺簽名的App獲得的seinfo為“platform”,使用第三方簽名安裝的App獲得的seinfo簽名為"default"。這里的setinfo并不是安全上下文的Type;但是系統會根據這個setinfo到external/sepolicy/seapp_contexts中去查找和和setinfo 對應的類型;
seapp_contexts:根據setinfo查找對應應用的安全上下文 Type;
------> seapp_contexts
# Input selectors:
# isSystemServer (boolean)
# user (string)
# seinfo (string)
# name (string)
# path (string)
# sebool (string)
# isSystemServer=true can only be used once.
# An unspecified isSystemServer defaults to false.
# An unspecified string selector will match any value.
# A user string selector that ends in * will perform a prefix match.
# user=_app will match any regular app UID.
# user=_isolated will match any isolated service UID.
# All specified input selectors in an entry must match (i.e. logical AND).
# Matching is case-insensitive.
#
# Precedence rules:
# (1) isSystemServer=true before isSystemServer=false.
# (2) Specified user= string before unspecified user= string.
# (3) Fixed user= string before user= prefix (i.e. ending in *).
# (4) Longer user= prefix before shorter user= prefix.
# (5) Specified seinfo= string before unspecified seinfo= string.
# (6) Specified name= string before unspecified name= string.
# (7) Specified path= string before unspecified path= string.
# (8) Specified sebool= string before unspecified sebool= string.
#
# Outputs:
# domain (string)
# type (string)
# levelFrom (string; one of none, all, app, or user)
# level (string)
# Only entries that specify domain= will be used for app process labeling.
# Only entries that specify type= will be used for app directory labeling.
# levelFrom=user is only supported for _app or _isolated UIDs.
# levelFrom=app or levelFrom=all is only supported for _app UIDs.
# level may be used to specify a fixed level for any UID.
#
isSystemServer=true domain=system_server
user=system domain=system_app type=system_app_data_file
user=bluetooth domain=bluetooth type=bluetooth_data_file
user=nfc domain=nfc type=nfc_data_file
user=radio domain=radio type=radio_data_file
user=shared_relro domain=shared_relro
user=shell domain=shell type=shell_data_file
user=_isolated domain=isolated_app
user=_app seinfo=platform domain=platform_app type=app_data_file
user=_app domain=untrusted_app type=app_data_file
這里我保留了文件的全部內容,文中注釋很重要;
前面mac_permisssions.xml 中指定使用平臺簽名的應用setinfo 為platform,所以在seapp_contexts中最匹配的一行為:
user=_app seinfo=platform domain=platform_app type=app_data_file
這樣就可以知道,使用平臺簽名的App進程domain為“platform_app”,它的數據文件的file_type為“app_data_file”。
第三方簽名的應用的seinfo為 "default",但是在seapp_contexts并沒有以 user=_app seinfo=default開頭的行,但是有一行最匹配:
user=_app domain=untrusted_app type=app_data_file
這樣就知道了第三方App進程的domain 為 "untrusted_app",它的數據文件的file_type為"app_data_file";
global_macros,te_macros:一些宏定義文件;
------> te_macros
# upon executing its binary.
define(`init_daemon_domain', `
domain_auto_trans(init, $1_exec, $1)
tmpfs_domain($1)
')
#####################################
# app_domain(domain)
# Allow a base set of permissions required for all apps.
define(`app_domain', `
typeattribute $1 appdomain;
# Label ashmem objects with our own unique type.
tmpfs_domain($1)
# Map with PROT_EXEC.
allow $1 $1_tmpfs:file execute;
')
......
property_contexts:和file_contexts類似,這里初始化屬性的安全上下文;
-----> property_contexts
##########################
# property service keys
#
#
net.rmnet u:object_r:net_radio_prop:s0
net.gprs u:object_r:net_radio_prop:s0
net.ppp u:object_r:net_radio_prop:s0
net.qmi u:object_r:net_radio_prop:s0
net.lte u:object_r:net_radio_prop:s0
net.cdma u:object_r:net_radio_prop:s0
net.dns u:object_r:net_radio_prop:s0
sys.usb.config u:object_r:system_radio_prop:s0
ril. u:object_r:radio_prop:s0
gsm. u:object_r:radio_prop:s0
persist.radio u:object_r:radio_prop:s0
.......
還有很多的文件,這里就不逐一分析了,遇到問題就明白了,這里舉兩個例子;
/external/sepolicy目錄下是Google 針對整個平臺的限制,一般都不會修改;自己的修改一般都在/device/qcom/sepolicy目錄;
這里針對qcom平臺:/device/qcom/sepolicy/
例1:為一個進程添加Selinux 訪問權限;
步驟如下:
1:在/device/qcom/sepolicy/common目錄下創建一個和進程名一樣的.te文件;例如hello進程對應的hello.te;在hello.te中使用type聲明該進程的 domain Type;
------> hello.te
type hello, domain; ### 聲明該進程的domain Type 為 hello
type hello_exec, exec_type, file_type; ###這里說明hello進程可執行文件的 Type為hello_exec,
#### 這里需要去file_contexts中去配置相關類型;
init_daemon_domain(hello) ###必須實現
binder_use(hello)
binder_service(hello)
allow hello hello_service:service_manager add;###hello_service需要向service.te中注冊,
allow hello system_server:binder call;
allow hello platform_app:binder call;
allow hello device:sock_file write;
allow hello untrusted_app:binder call;
allow hello system_app:dir search;
allow hello system_app:file { open read getattr };
......
因為這里注冊的是Service 還需要去service.te和service_contexts中添加對應內容,如果不需要提供跨進程服務就不需要添加;
-------> service.te
......
type hello_service, service_manager_type; ####聲明系統服務的Type 為hello_service,屬性為service_manager_type
......
------> service_contexts
......
servicePackageName u:object_r:hello_service:s0 ####servicePackageName是服務的包名,
### 這里和hello.te中的allow hello hello_service:service_manager add;有關
......
------> file_contexts
......
/system/bin/hello u:object_r:hello_exec:s0
### hello_exec用于hello.te中的type hello_exec, exec_type, file_type;中
......
2:將步驟1中的hello.te字符串添加到/device/qcom/sepolicy/下的Android.mk文件BOARD_SEPOLICY_UNION := \ 標簽中編譯;
BOARD_SEPOLICY_UNION := \
......
hello.te
......
是不是很簡單,這樣我們就添加完成了Hello進程的訪問權限;
例2:為一個文件添加訪問控制;
步驟1:由于是為文件添加訪問權限;所以我們需要聲明該文件的Type;文件Type 在需要在file.te和file_contexts中聲明;file_contexts中聲明該文件位置;
------> file.te
#Hello data files /data/hello
......
type hello_data_file, file_type, data_file_type;
......
------> file_contexts
......
/data/hello(/.*)? u:object_r:hello_data_file:s0
......
這樣我們就算是為文件添加了權限,對于這個文件,有哪些文件需要去訪問呢?這里我們不妨假定為platform app需要訪問這個文件;
接下來我們就在platform_app.te中添加相關權限;
------> platform_app.te
# allow access /data/hello/
......
allow platform_app hello_data_file:file { open getattr read };
allow platform_app hello_data_file:dir { search };
......
這樣我們就為一個文件添加了訪問控制;添加Linux 設備也是類似,對于設備配置只是去device.te和file_contexts添加類似于文件類型的東西;因為Linux 一切皆文件,設備也是文件,所以需要在file_contexts中為指定路徑配置設備 Type;
到這里初步說明了一般在Android中會用到的Selinux 場景,很多深的東西還需要進一步研究;這里只是一個皮毛;
下面幾個不錯的博客;我也是參考他們的博客學習
深入理解SELinux 之SEAndroid
修改domain.te導致CTS不過解決方案-SELinux報錯修改篇
file_contexts.bin和file_contexts轉換工具,支持7.0~8.0
老羅說Selinux
TE語言規則
TE規則