關於Selinux詳解

目 錄

前緒    2

一、Selinux基礎概述    2

二、什麼是Selinux?    2

三、SELinux Policy語言    3

1、安全屬性——SContext    3

2、TE簡介    4

1). 客體類別和許可:    4

2). 訪問向量規則:    5

3). AV規則    5

四、SElinux策略文件    6

1、定義性文件    7

2、其他te文件    10

五、如何配置SElinux    11

六、SElinux調試方法    12

1、selinux的編譯    12

2、如何快速確認是selinux引起?    12

3、修改/添加selinux策略    12

1).簡化方法    13

2).按需確認方法    13

3).權限放大情況處理    14

七、案例分析    15

案例一、OTA升級過程中出現/system/etc/ppp/ip-up-vpn無法添加scontext    15

案例二、recovery刪除data目錄下的文件    16

八、常用指令    17

1、文件操作    17

2、進程domain的確認    18

3、ROLE的確認和變更    18

4、模式切換    18

5、其他重要命令    19

九、參考文獻    20

 

 

Selinux梳理總結

前緒

該文檔只是將selinux中最基礎的知識點進行了整理羅列,其他還有很多高級用法及昇華拓展部分,如SElinux域轉換、角色轉換以及SElinux框架等,並未收錄,有需要了解的可以參照參考文獻部分中的《SElinux詳解》文檔,後續會繼續補充完善。

一、Selinux基礎概述

SELinux則是由美國NSA(國安局)和一些公司(RedHat、Tresys)設計的一個針對Linux的安全加強系統。

NSA最初設計的安全模型叫FLASK,全稱爲Flux Advanced Security Kernel(由Uta大學和美國國防部開發,後來由NSA將其開源),當時這套模型針對DTOS系統。後來,NSA覺得Linux更具發展和普及前景,所以就在Linux系統上重新實現了FLASK,稱之爲SELinux。

Linux Kernel中,SELinux通過Linux Security Modules實現。在2.6之前,SElinux通過Patch方式發佈。從2.6開始,SELinux正式入駐內核,成爲標配。後來,鑑於Selinux的安全性和使用性,Google在Android 4.4上正式推出的一套以SELinux爲基礎於核心的系統安全機制,且命名爲SEandroid,自此,selinux便被"移植"到了Android上了。

 

二、什麼是Selinux?

SELinux出現之前,Linux上的安全模型叫DAC,全稱是Discretionary Access Control(自主訪問控制)。DAC的核心思想很簡單,就是:進程理論上所擁有的權限與執行它的用戶的權限相同。比如,以root用戶啓動Browser,那麼Browser就有root用戶的權限,在Linux系統上能幹任何事情。

顯然,DAC太過寬鬆了,所以各路高手想方設法都要在Android系統上搞到root權限。那麼SELinux如何解決這個問題呢?原來,它在DAC之外,設計了一個新的安全模型,叫MAC(Mandatory Access Control),翻譯爲強制訪問控制。MAC的處世哲學非常簡單:即任何進程想在SELinux系統中幹任何事情,都必須先在安全策略配置文件中賦予權限。凡是沒有出現在安全策略配置文件中的權限,進程就沒有該權限。來看一個SEAndroid中設置權限的例子:

[external/sepolicy/netd.te]

/*

允許(allow )netd域(domain)中的進程寫(write)類型爲proc的文件

*/

allow netd proc:file write

如果沒有在netd.te中使用上例中的權限配置allow語句,則netd就無法往/proc目錄下得任何文件中寫數據,即使netd具有root權限。

顯然,MAC比DAC在權限管理這一塊要複雜,要嚴格,要細緻得多。

關於DAC和MAC:

  • Linux系統先做DAC檢查。如果沒有通過DAC權限檢查,則操作直接失敗。通過DAC檢查之後,再做MAC權限檢查。
  • SELinux中也有用戶的概念,但它和Linux中原有的user概念不是同一個概念。比如,Linux中的超級用戶root在SELinux中可能就是一個沒權限,沒地位,打打醬油的"路人甲"。當然,這一切都由SELinux安全策略的制定者來決定。

這裏只是借用一個例子先對selinux做一個初步的瞭解,下面將對selinux特有的語法做簡單介紹。

三、SELinux Policy語言

在網上看到一種比喻的說法,個人感覺很有道理:Linux中有兩種東西,一種死的(Inactive),一種活的(Active)。活的東西就是進程,而死的東西就是資源(eg:文件、套接字等)。他們之間就是一種操作和被操作,或者說使用與被使用的關係。進程能發起動作,例如它能打開文件並操作它。而文件只能被進程操作。SElinux Policy語言就是將死的和活的東西都給打上"標籤",通過"標籤"將系統內的資源(包括進程)分成不同的角色(比如:用戶、客體),進而對整個系統資(包括進程)進行合理安全的管控。

1、安全屬性——SContext

在SELinux世界裏,每種東西都會被賦予一個安全屬性,官方說法叫Security Context,也可以理解爲上文所提到的"標籤"。通過每個資源的屬性,對他們進行歸類管理。Security Context(以後用SContext表示)是一個字符串,由四部分組成,被分爲兩類:進程SContext和資源SContext。根據SELinux規範,完整的SContext字符串爲:

user:role:type[:range]

注意,[]中的內容表示可選項。s0屬於range中的一部分,表示安全級別(這裏不做討論)。

 

首先,我們通過下面例子看下進程SContext。如SEAndroid中,進程的SContext可通過ps -Z命令查看,如圖1所示:

最左邊的那一列就是進程的SContext,以第一個進程/system/bin/logwrapper的SContext爲例,其值爲u:r:init:s0,其中:

  • u——user,用戶,SEAndroid中僅定義了一個SELinux用戶,值爲u。
  • r——role,role是角色之意,它是SELinux中一種比較高層次,更方便的權限管理思路,即Role Based Access Control(基於角色的訪問控制,簡稱爲RBAC)。簡單點說,一個u可以屬於多個role,不同的role具有不同的權限。RBAC我們到最後再討論。
  • init——tyoe,代表該進程所屬的Domain爲init。MAC的基礎管理思路其實不是針對上面的RBAC,而是所謂的Type Enforcement Accesc Control(簡稱TEAC,一般用TE表示)。對進程來說,Type就是Domain。比如init這個Domain有什麼權限,都需要通過[例子1]中allow語句來說明。
  • S0——和SELinux爲了滿足軍用和教育行業而設計的Multi-Level Security(MLS)機制有關。簡單點說,MLS將系統的進程和文件進行了分級,不同級別的資源需要對應級別的進程才能訪問。限於篇幅,這裏不做過多探討。

接着,我們看下文件的SContext,在SEandriod中,文件的SContext可以通過ls -Z查看:

如上圖所示,右邊數第二列就是所對應的SContext信息。以root目錄爲例,其對應SContext爲:u:object_r:rootfs:s0:

  • u——同樣是user之意,它代表創建這個文件的SELinux user。
  • object_r——role,這裏指文件,在SELinux中,使用object_r表示它的role。
  • rootfs——死的東西的Type,和進程的Domain其實是一個意思。它表示root目錄對應的Type是rootfs。
  • s0——MLS的級別。

2、TE簡介

有了SContext就可以對系統內所有資源進行統一管理了。SElinux的安全模型(MAC)有兩種管理機制,分別是TEAC(Type Enforcement Accesc Control,後文簡稱TE)和RBAC(Role Based Accesc Control)。RBAC是更高級的一種管理機制(由於SEandroid涉及不多,這裏不予展開談論),不過也是基於TE的。可見,TE是SElinux的管理核心,下面我們就對TE語法做詳細解讀。

在沒有介紹具體的語法之前,首先需要了解下與TE語句相關的另外幾個概念定義:

1). 客體類別和許可:

客體類別及其許可是 SELinux 中訪問控制的基礎,客體類別代表資源的範疇,如文件和
套接字,許可代表對這些資源的訪問權限,如讀或發送。一個客體類別代表某個確定類型(如文件或套接字)的所有資源,一個客體類別的實例(如某個特定的文件或套接字)被稱爲一個客體。客體類別指的是資源(文件)的所有範疇,客體指的是客體類別的某個特定實例(如: /etc/passwd)。

聲明定義方法

聲明許可有兩種方法,第一種叫做通用許可(被多個客體類別所共用),它允許我們創建與客體類別一起作爲一個組的許可,通用許可在類似的客體類別(如文件和符號連接)共享一套訪問許可時很有用;第二種方法叫做特定類別許可(由某個客體類別所獨用),它允許我們單獨爲客體類別聲明特定的許可,正如將會看到的,有一些客體類別只有特定的許可,有一些只有通用許可,還有一些是這兩者都有。客體類別和許可定義方法如下:

    聲明客體類別:class 類別名字

    通用許可:common 通用名 {許可集}

    聯合許可和客體類別:class 類別名 [inherits 通用許可集名] [{許可集}]

此外,既然有客體,肯定還有主體一說,即誰去使用、操作客體。主體和客體只是邏輯上的區別,只有放在安全控制語句中才能看出誰是主體誰是客體。但,既然是控制,主體一般來說肯定是"活的"纔有可能去控制"死的"東西,所以,在SEandriod中,主體一般指的就是進程,客體可以是文件等資源,也可以是進程(因爲進程一樣可以被進程操作)。

2). 訪問向量規則:

訪問向量規則又稱AV規則,屬於SElinux策略語言的控制部分。常用的通用AV規則有如下4個:

  • allow:表示允許主體對客體執行允許的操作
  • dontaudit:表示不記錄違反規則的決策信息,且違反規則不影響運行(允許操作且不記錄)
  • auditallow:表示允許操作並記錄訪問決策信息(允許操作且記錄)
  • neverallow:表示不允許主體對客體執行指定的操作

好了,到此,我們就可以組合成最基本的SElinux策略語句了。一般,完整的基本安全控制語句格式爲:

AV規則 主體 客體:客體類別 許可

還拿之前的例子做說明:

allow netd proc:file write

其中:

allow——AV規則

netd——主體

proc——客體

file——客體類別

write——許可

當然,後面還有很多其他策略語句,將在介紹系統文件時,一併概述。

3). AV規則

對於AV規則,前文已經有所提及,比如allow。SElinux中主要的有效規則有allow,auditallow,auditdeny,dontaudit和neverallow,下面逐一介紹。

  • 允許規則allow

    我們使用allow規則指出了所有運行時授予的許可,它們是SELinux策略中允許許可的唯一方法,注意:默認情況下,不允許任何訪問,我們指定了兩個類型列表(源和目標類型),根據列出的客體類別的許可指定訪問權,如:

    allow user_t bin_t : file { read execute }; 

這個規則允許任何安全上下文中類型具有user_t的進程對任何安全上下文中具有類型爲bin_t的普通文件所有read和execute訪問權。allow規則共享了通用AV規則的的所有語法,並且也沒有增加任何額外的語法了。

  • 審覈規則auditallow/auditdeny/dontaudit

    SELinux有大量的工具記錄日誌信息,或審覈、訪問嘗試被策略允許或拒絕的信息。審覈消息通常叫做"AVC消息",它提供了詳細了關於訪問嘗試的信息,包括是允許還是拒絕,源和目標的安全上下文,以及其它一些訪問嘗試涉及到資源信息。AVC消息與其它內核消息類似,都是存儲在/var/log目錄下的日誌文件中,它是策略開發、系統管理和系統監視不可缺少的工具。在此,我們檢查是哪一個訪問嘗試產生了審覈消息。

    默認情況下,SELinux不會記錄任何允許的訪問檢查,只會記錄被拒絕的訪問檢查。這並沒什麼奇怪的,在大多數系統上,每秒會允許成千上萬的訪問,只有很少的一部分會被拒絕,允許的訪問通常是在預料之中的,通常不需要審覈,被拒絕的訪問通常是(但不總是)非預期的訪問,對它們進行審覈便於管理員發現策略的bug和可能的入侵嘗試。策略語言允許我們取消這些默認的預料之中的拒絕審覈消息,改爲記錄允許的訪問嘗試審覈消息。

    SELinux提供兩個AV規則允許我們控制審覈哪一種訪問嘗試:dontaudit和auditallow。使用這兩條規則我們就可以改變默認的審覈類型了,最常用的是dontaudit規則,它指出哪一個訪問嘗試被拒絕時不審覈,這樣就覆蓋了SELinux默認的審覈所有拒絕的訪問嘗試的行爲。

    dontaudit httpd_t etc_t : dir search;  

注意,審覈(audit)規則讓我們覆蓋了默認的審覈設置,allow規則指出了什麼訪問是允許的,auditallow規則不允許訪問,它只審覈允許的許可。

 

  • 禁止規則neverallow

最後一個AV規則是neverallow規則,我們使用這個規則來指定永遠不會被allow規則執行的訪問,你可能會疑惑,爲什麼會有這個規則?因爲默認情況下所有的訪問都是被拒絕的,設計這個規則的主要目的是爲了幫助編寫策略時,可以明確地指出不想要的訪問許可,因此可以預防意外發生,回想一下,在一個SELinux策略中可能包含成千上萬條規則,可能不小心加入了我們本不想授予的訪問權,此時,neverallow規則就可以幫助預防這種情況發生,如:

    neverallow user_t shadow_t : file write;  

這條neverallow規則可以有效地阻止我們在策略中添加一條允許user_t對類型爲shadow_t的文件進行寫操作的規則,如果添加了這樣的規則在編譯時就會報錯,這條規則不會移除訪問權,它只是會產生編譯錯誤。我們在編寫策略時,neverallow規則往往放在allow規則前面,首先聲明哪些訪問是明確地被拒絕的,然後再聲明哪些訪問是可以接受的,這樣就可以預防我們人爲出錯了。

 neverallow規則支持一些特殊的其它AV規則不支持的語法,在neverallow規則中的源和目標類型列表中可以使用通配符(*)和求補算操作符(~),如:

    neverallow * domain : dir ~{ read getattr };  

這條規則指出沒有哪條allow可以授予任何類型對具有domain屬性的類型的目錄有任何訪問權,除了read和getattr訪問權外(即讀訪問權),這條規則的中通配符意味着所有的類型,在真實的策略中,類似這樣的規則很常見,它們用來阻止對/proc/目錄適當的訪問。

我們從前面這個例子中看出,在源類型列表中需要使用通配符,因爲我們想要指出任何類型或所有類型,包括那些還沒有創建的類型,使用通配符可以預防我們未來犯錯。

另一個常見的neverallow規則是:

    neverallow domain ~domain : process transition;  

這條neverallow規則增強了domain屬性,它指出了進程不能轉換到無domain屬性的類型,這就使得要爲一個類型無doamin屬性的進程創建一個有效的策略是不可能的。

四、SElinux策略文件

SElinux的策略文件主要集中在external\sepolicy下,這裏也是我們添加修改安全策略的主要地方。這裏所有的安全策略在編譯後最終都會彙集到out/target/product/generic/obj/ETC/sepolicy_intermediates/policy.conf文件中,然後再經過轉化load到linux kernel。下面我們就對external\sepolicy目錄下的文件進行逐一解析說明。

打開external\sepolicy目錄,我們會發現裏面有很多.te文件,這些te文件就是我們定義的策略文件,除了策略文件之外,還有很多沒有後綴的,這些沒有後綴的文件就是專門定義策略語句元素的。由於所有的te文件中的規則語句都是基於這些語句元素組成的,這裏我們先來看下這些定義性文件:

1、定義性文件

users

該文件中定義了SElinux中唯一的用戶u:

user u roles { r } level s0 range s0 - mls_systemhigh;

roles

該文件定義了SElinux中唯一的角色r:

role r;

role r types domain;

security_classes

該文件定義了所有通用客體類別:

# FLASK

 

#

# Define the security object classes

#

 

# Classes marked as userspace are classes

# for userspace object managers

 

class security

class process

class system

class capability

....

attributes

該文件定義了所有SContext中的通用type:

######################################

# Attribute declarations

#

 

# All types used for devices.

attribute dev_type;

 

# All types used for processes.

attribute domain;

 

# All types used for filesystems.

attribute fs_type;

....

access_vectors

該文件定義了資源的所有通用許可:

#

# Define common prefixes for access vectors

#

# common common_name { permission_name ... }

 

 

#

# 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.te

該文件自定義了file_contexts中的所有文件類型的type:

# Filesystem types

type labeledfs, fs_type;

type pipefs, fs_type;

type sockfs, fs_type;

type rootfs, fs_type;

type proc, fs_type;

....

device.te

該文件自定義了file_contexts中的所有設備節點的type:

# Device types

type device, dev_type, fs_type;

type alarm_device, dev_type, mlstrustedobject;

type adb_device, dev_type;

file_contexts

....

該文件定義了所有文件資源的SContext:

#/##########################################

# Root

/ u:object_r:rootfs:s0

 

# Data files

/adb_keys u:object_r:adb_keys_file:s0

/default\.prop u:object_r:rootfs:s0

/fstab\..* u:object_r:rootfs:s0

/init\..* u:object_r:rootfs:s0

/res(/.*)? u:object_r:rootfs:s0

/ueventd\..* u:object_r:rootfs:s0

....

genfs_contexts

定義了虛擬文件的SContext:

# Label inodes with the fs label.

genfscon rootfs / u:object_r:rootfs:s0

# proc labeling can be further refined (longest matching prefix).

genfscon proc / u:object_r:proc:s0

genfscon proc /net u:object_r:proc_net:s0

....

fs_use

定義了所有文件系統類型的SContext:

# Label inodes via getxattr.

fs_use_xattr yaffs2 u:object_r:labeledfs:s0;

fs_use_xattr jffs2 u:object_r:labeledfs:s0;

fs_use_xattr ext2 u:object_r:labeledfs:s0;

....

service.te

定義了所有service_contexts中SContext的type:

type bluetooth_service, service_manager_type;

type default_android_service, service_manager_type;

type drmserver_service, service_manager_type;

....

service_contexts

定義了所有所有系統service的SContext:

accessibility u:object_r:accessibility_service:s0

account u:object_r:account_service:s0

activity u:object_r:activity_service:s0

alarm u:object_r:alarm_service:s0

....

mac_permissions.xml

與seapp_contexts一起負責爲接下來安裝的不同類型的app添加SContext。

<?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>

seapp_contexts

與mac_permissions.xml一起負責爲接下來安裝的不同類型的app添加SContext。

isSystemServer=true domain=system_server

user=system seinfo=platform domain=system_app type=system_app_data_file

user=bluetooth seinfo=platform domain=bluetooth type=bluetooth_data_file

user=nfc seinfo=platform domain=nfc type=nfc_data_file

....

2、其他te文件

剩餘的.te文件中主要是各個進程的具體策略控制。這裏我們拿recovery.te來舉例說明。

recovery.te

# recovery console (used in recovery init.rc for /sbin/recovery)

 

# Declare the domain unconditionally so we can always reference it

# in neverallow rules.

type recovery, domain;

 

# But the allow rules are only included in the recovery policy.

# Otherwise recovery is only allowed the domain rules.

recovery_only(`

allow recovery self:capability { chown dac_override fowner fsetid setfcap setuid setgid sys_admin sys_tty_config };

 

# Set security contexts on files that are not known to the loaded policy.

allow recovery self:capability2 mac_admin;

 

# Run helpers from / or /system without changing domain.

allow recovery rootfs:file execute_no_trans;

allow recovery system_file:file execute_no_trans;

.....

allow recovery kernel:process setsched;

')

....

neverallow recovery data_file_type:file { no_w_file_perms no_x_file_perms };

neverallow recovery data_file_type:dir no_w_dir_perms;

這裏定義了有關recovery的所有策略控制。

首先,文件開頭定義了進程域名recovery,繼承自domain,說明這裏新定義的recovery域爲進程域。接下來在recovery_only中制定了很多策略控制。

如:allow recovery system_file:file execute_no_trans;表示允許SContext標誌爲recovery的進程不可傳遞域地去執行SContext爲system_file的文件。

最後還有neverallow檢查語句,

如:neverallow recovery data_file_type:dir no_w_dir_perms;表示不允許SContext標誌爲recovery的進程去no_w_dir_perms SContext爲data_file_type的目錄。

五、如何配置SElinux

在支持SElinux的Android版本中,有關selinux策略文件有兩處,一個是google原生的,另一個是產品平臺配置的,他們分別對應如下目錄:

google原生目錄:s912/external/sepolicy

平臺配置目錄:s912/device/amlogic/common/sepolicy

在編譯時, 系統會以合併的方式,將平臺配置目錄下的policy 附加到Google 原生的policy 上,而非替換。一般情況下,不建議修改google原生目錄下的策略控制。接下來看下如何配置平臺的selinux。

找到平臺下的BoardConfig.mk,其相關變量配置就是BOARD_SEPOLICY_DIRS,目的就是指定平臺sepolicy的目錄。

BoardConfig.mk中直接包含了sepolicy的mkfile文件:

include device/amlogic/common/sepolicy.mk

打開該sepolicy.mk文件可以看到BOARD_SEPOLICY_DIRS變量的配置:

BOARD_SEPOLICY_DIRS := \

device/amlogic/common/sepolicy

 

六、SElinux調試方法

1、selinux的編譯

首先我們關注下selinux的編譯,大家知道編譯整個Android工程是個很耗時的工作。爲了避免耗時,在我們修改或者添加了selinux策略之後,建議先獨自對sepolicy模塊進行一次編譯,如果通過了,然後再進行整個Android的編譯。具體指令如下:

如:mmm external/sepolicy

2、如何快速確認是selinux引起?

目前所有的SELinux check 失敗,在kernel log 或者android log(L版本後)中都有對應的" avc: denied"的LOG 與之對應。舉例如下:

<5>[ 17.285600].(0)[503:idmap]type=1400 audit(1356999072.320:202): avc:  denied  { create } for  pid=503 comm="idmap" name="overlays.list" scontext=u:r:zygote:s0 tcontext=u:object_r:resource_cache_data_file:s0 tclass=file

即表明idmap 這個process, 使用zygote 的source context, 訪問/data/resource_cache 目錄,並創建文件時,被SELinux 拒絕訪問。

但反過來,有此LOG,並非就會直接失敗,還需要確認當時SELinux 的模式, 是enforcing mode 還是 permissve mode.這裏需要提到的是selinux有3中模式:permissive、enforcing和disabled。

  • enforcing:強制模式,代表 SELinux 運作中,且已經正確的開始限制 domain/type 了;
  • permissive:寬容模式:代表 SELinux 運作中,不過僅會有警告訊息並不會實際限制 domain/type 的存取。這種模式可以運來作爲 SELinux 的 debug 之用;
  • disabled:關閉,SELinux 並沒有實際運作。

如果問題容易復現,我們可以先將SELinux 模式調整到Permissive mode,然後再測試確認是否與SELinux 約束相關.

指令如下:

查看selinux當前模式:

[root@python bin]# getenforce

Permissive

更改當前的SELINUX值 ,後面可以跟 enforcing,permissive 或者 1, 0。

[root@python bin]# setenforce permissive

[root@python bin]# setenforce enforcing

3、修改/添加selinux策略

首先, 務必確認對應進程訪問系統資源是否正常, 是否有必要?如果本身是異常非法訪問,那麼就要自行消除訪問。

其次,如果確認訪問是必要,並且正常的,那麼就要對對應的process/domain 增加新的policy.

具體步驟大致如下:

1).簡化方法

1.1 提取所有的avc LOG. 如 adb shell "cat /proc/kmsg | grep avc" > avc_log.txt

1.2 使用 audit2allow tool 直接生成policy. audit2allow -i avc_log.txt 即可自動輸出生成的policy

1.3 將對應的policy 添加到selinux policy 規則中,對應MTK Solution, 您可以將它們添加在KK: mediatek/custom/common/sepolicy, L: device/mediatek/common/sepolicy 下面,如

allow zygote resource_cache_data_file:dir rw_dir_perms;

allow zygote resource_cache_data_file:file create_file_perms;

===> mediatek/custom/common/sepolicy/zygote.te (KK)

===> device/mediatek/common/sepolicy/zygote.te (L)

注意audit2allow 它自動機械的幫您將LOG 轉換成policy, 而無法知道你操作的真實意圖,有可能出現權限放大問題。

2).按需確認方法

此方法需要工程人員對SELinux 基本原理,以及SELinux Policy Language 有了解.

2.1 確認是哪個進程訪問哪個資源,具體需要哪些訪問權限,read ? write ? exec ? create ? search ?

2.2 當前進程是否已經創建了policy 文件? 通常是process 的執行檔.te,如果沒有,並且它的父進程即source context 無須訪問對應的資源,則創建新的te 文件.

在L 版本上, Google 要求維護關鍵 security context 的唯一性, 比如嚴禁zygote, netd, installd, vold, ueventd 等關鍵process 與其它process 共享同一個security context.

2.3 創建文件後,關聯它的執行檔,在file_contexts 中, 關聯相關的執行檔.

比如 /system/bin/idmap 則是 /system/bin/idmap u:object_r:idmap_exec:s0

2.4 填寫policy 到相關的te 文件中

如果沿用原來父進程的te 文件,則直接添加.

如果是新的文件,那麼首先:

#==============================================

# Type Declaration

#==============================================

type idmap, domain;

type idmap_exec, exec_type, file_type;

 

#==============================================

# Android Policy Rule

#==============================================

#permissive idmap;

domain_auto_trans(zygote, idmap_exec, idmap);

然後添加新的policy

# new policy

allow idmap resource_cache_data_file:dir rw_dir_perms;

allow idmap resource_cache_data_file:file create_file_perms;

 

3).權限放大情況處理

如果直接按照avc: denied 的LOG 轉換出SELinux Policy, 往往會產生權限放大問題. 比如因爲要訪問某個device, 在這個device 沒有細化SELinux Label 的情況下, 可能出現:

<7>[11281.586780] avc: denied { read write } for pid=1217 comm="mediaserver" name="tfa9897" dev="tmpfs" ino=4385 scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=0

如果直接按照此LOG 轉換出SELinux Policy: allow mediaserver device:chr_file {read write}; 那麼就會放開mediaserver 讀寫所有device 的權限. 而Google 爲了防止這樣的情況, 使用了neverallow 語句來約束, 這樣你編譯sepolicy 時就無法編譯通過.

爲了規避這種權限放大情況, 我們需要細化訪問目標(Object) 的SELinux Label, 做到按需申請. 通常會由三步構成

3.1 定義相關的SELinux type.

比如上述案例, 在 device/mediatek/common/sepolicy/device.te 添加

type tfa9897_device, dev_type;

3.2 綁定文件與SELinux type.

比如上述案例, 在 device/mediatek/common/sepolicy/file_contexts 添加

/dev/tfa9897(/.*)? u:object_r:tfa9897_device:s0

3.3 添加對應process/domain 的訪問權限.

比如上述案例, 在 device/mediatek/common/sepolicy/mediaserver.te 添加

allow mediaserver tfa9897_device:chr_file { open read write };

 

那麼,哪些訪問對象通常會遇到此類呢?(以L 版本爲例)

*device類型

-- 類型定義: external/sepolicy/device.te;device/mediatek/common/sepolicy/device.te

-- 類型綁定: external/sepolicy/file_contexts;device/mediatek/common/sepolicy/file_contexts

 

*File類型:

-- 類型定義: external/sepolicy/file.te;device/mediatek/common/sepolicy/file.te

-- 綁定類型: external/sepolicy/file_contexts;device/mediatek/common/sepolicy/file_contexts

 

*虛擬File類型:

-- 類型定義: external/sepolicy/file.te;device/mediatek/common/sepolicy/file.te

-- 綁定類型: external/sepolicy/genfs_contexts;device/mediatek/common/sepolicy/genfs_contexts

 

*Service類型:

-- 類型定義: external/sepolicy/service.te; device/mediatek/common/sepolicy/service.te

-- 綁定類型:external/sepolicyservice_contexts;device/mediatek/common/sepolicy/service_contexts

 

*Property類型:

-- 類型定義: external/sepolicy/property.te;device/mediatek/common/sepolicy/property.te

-- 綁定類型: external/sepolicy/property_contexts;device/mediatek/common/sepolicy/property_contexts;

七、案例分析

案例一、OTA升級過程中出現/system/etc/ppp/ip-up-vpn無法添加scontext

【問題現象】

製作好的差分包在升級過程中出現如下錯誤而導致升級失敗,且重啓後一直處於recovery模式下:

Symlinks and permissions...

ApplyParsedPerms: lsetfilecon of /system/etc/ppp/ip-up-vpn to u:ppp_system_file:s0 failed:Permission denied

set_metadata:some changes failed

E:Error in /udisk/update.zip

(Status 7)

該問題與問題一的提示信息基本一致,爲何還是將本問題摘出來?這是因爲他們的改動方案有所不同。

【問題分析】

出現上述錯誤後,根據提示信息可以確定升級包校驗以及系統校驗已經完成。這裏是由於recovery中涉及selinux方面在向/system/etc/ppp/ip-up-vpn文件添加"u: ppp_system_file:s0"上下文(scontext)時因權限問題被拒絕了。

【解決方案】

方案1、3同問題一。

方案2、將META-INF\com\google\android\updater-script中的下列條目刪除:

set_metadata_recursive("/system/etc/ppp ", "uid", 0, "gid", 0, "dmode", 0755, "fmode", 0555, "capabilities", 0x0, "selabel", "u:object_r:ppp_system_file:s0");

方案4、根據方案2中所刪除的額條目中的function可以看出,該條目目的是要在system/etc/ppp目錄下進行遞歸加scontext,但不知爲何沒有生效。由於system/etc/ppp目錄下只有ip-up-vpn一個文件,該方案仿照問題一中方案4按照直接操作ip-up-vpn文件的思路進行添加修改,具體修改如下:

a、ip-up-vpn也是可執行文件,首先定義出該文件的selinux權限規則:

在device/amlogic/common/sepolicy目錄下創建ip-up-vpn.te文件,並添加如下內容:

type ip-up-vpn, domain;

type ip-up-vpn_exec, exec_type, file_type;

 

init_daemon_domain(ip-up-vpn)

 

# Third line is important

allow ip-up-vpn input_device:chr_file rw_file_perms;

allow ip-up-vpn ppp_exec:file { execute_no_trans execute getattr read open };

allow ip-up-vpn ip-up-vpn_exec:file { entrypoint read setattr execute };

並更改其傳統linux權限爲777:

chmod 777 ip-up-vpn.te

b、在file_contexts中定義ip-up-vpn上下文屬性(scontext):

/system/etc/ppp/ip-up-vpn u:object_r:ip-up-vpn_exec:s0

c、在recovery.te中添加操控ip-up-vpn的權限:

allow recovery ip-up-vpn_exec:file {create_file_perms relabelfrom relabelto create write setattr};

 

【結果確認】updater-script中該條目通過selinux操作,ota差分升級成功。

 

案例二、recovery刪除data目錄下的文件

 

在recover升級的時候,我們有個需要從服務器上下載升級包,然後放在data/download,這部分工作是放在一個systemapp中完成的。

然後重啓進入recoveyr模式,在recovery升級完之後,我們需要在recovery中刪除這個文件,這部分是在recovery中完成。

功能很簡單,但是在android6.0上碰到selinux的問題。

我們先來看recovery.te中是不允許recovery操作data下面的目錄,也就是下面這個neverallow原則

# Recovery should never touch /data.

#

# In particular, if /data is encrypted, it is not accessible

# to recovery anyway.

#

# For now, we only enforce write/execute restrictions, as domain.te

# contains a number of read-only rules that apply to all

# domains, including recovery.

#

# TODO: tighten this up further.

neverallow recovery data_file_type:file { no_w_file_perms no_x_file_perms };

neverallow recovery data_file_type:dir no_w_dir_perms;

我們再來看下system_data_file在file_contexts.te中的定義

/data(/.*)? u:object_r:system_data_file:s0

而在file.te定義了system_data_file文件屬於data_file_type類型,因此recovery也是不能操作data下面的文件

[html] view plain copy 在CODE上查看代碼片派生到我的代碼片

./file.te:56:type system_data_file, file_type, data_file_type;

在我們可以自己定義自己的file類型,我們可以定義data/download屬於download_data_file類型

/data/download(/.*)? u:object_r:download_data_file:s0

然後在file.te中定義download_data_file類型, 注意是隻屬於file_type類型的。

type download_data_file, file_type;

然後在recovery.te中增加對download_data_file的權限

allow recovery download_data_file:dir { write search remove_name };

allow recovery download_data_file:file { read getattr unlink };

另外我們還需在一個systemapp中先下載升級包,所以需要在system_app.te中增加對如下權限:

allow system_app download_data_file:dir { search write add_name getattr remove_name };

allow system_app download_data_file:file { create read write open getattr unlink };

但是最後還是失敗了,爲什麼呢,因爲一開始沒有data/download這個目錄,而是我們再app中自己下載的時候創建的目錄,所以是system_data_file類型的。那麼我們就需要在一開始就有data/download目錄,所以在init.rc中添加如下代碼:

mkdir /data/download 0771 system system

最後我們還需要在uncrypt.te中增加如下,因爲data目錄有可能需要進行加密處理。

allow uncrypt download_data_file:dir { search getattr };

allow uncrypt download_data_file:file { getattr read open };

 

八、常用指令

SELinux 是個經過安全強化的Linux操作系統,實際上,基本上原來的運用軟件沒有必要修改就能在它上面運行。真正做了特別修改的RPM包只要50多個。像文件系統EXT3都是經過了擴展。對於一些原有的命令也進行了擴展,另外還增加了一些新的命令,接下來我們就來看看這些命令。

1、文件操作

1)ls命令

在命令後加個 -Z 或者加 –context

[root@python azureus]# ls -Z

-rwxr-xr-x fu fu user_u:object_r:user_home_t azureus

-rw-r--r-- fu fu user_u:object_r:user_home_t Azureus2.jar+

-rw-r--r-- fu fu user_u:object_r:user_home_t Azureus.png

2)chcon

更改文件的標籤

[root@python tmp]# ls --context test.txt

-rw-r--r-- root root root:object_r:staff_tmp_t test.txt

[root@python tmp]# chcon -t etc_t test.txt

[root@python tmp]# ls -lZ test.txt

-rw-r--r-- root root root:object_r:etc_t test.txt

3)restorecon

當這個文件在策略裏有定義是,可以恢復原來的 文件標籤。

4)setfiles

跟chcon一樣可以更改一部分文件的標籤,不需要對整個文件系統重新設定標籤。

5)fixfiles

一般是對整個文件系統的, 後面一般跟 relabel,對整個系統 relabel後,一般我們都重新啓動。如果,在根目錄下有.autorelabel空文件的話,每次重新啓動時都調用 fixfiles relabel

6)star

就是tar在SELinux下的互換命令,能把文件的標籤也一起備份起來。

7)cp

可以跟 -Z, --context=CONTEXT 在拷貝的時候指定目的地文件的security context

8)find

可以跟 –context 查特定的type的文件。

例子:

find /home/fu/ --context fu:fu_r:amule_t -exec ls -Z {} \:

9)run_init

在sysadm_t裏手動啓動一些如Apache之類的程序,也可以讓它正常進行,domain遷移。

2、進程domain的確認

程序現在在那個domain裏運行,我們可以在ps 命令後加 -Z

[root@python /]# ps -eZ

LABEL PID TTY TIME CMD

system_u:system_r:init_t 1 ? 00:00:00 init

system_u:system_r:kernel_t 2 ? 00:00:00 ksoftirqd/0

system_u:system_r:kernel_t 3 ? 00:00:00 watchdog/0

3、ROLE的確認和變更

命令id能用來確認自己的 security context

[root@python ~]# id

uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel) context=root:staff_r:staff_t

這裏,雖然是ROOT用戶,但也只是在一般的ROLE和staff_t裏運行,如果在enforcing模式下,這時的ROOT對於系統管理工作來說什麼也幹不了。

[root@python ~]# newrole -r sysadm_r

Authenticating root.

口令:

[root@python ~]# id

uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel) context=root:sysadm_r:sysadm_t

4、模式切換

1)getenforce

得到當前的SELINUX值

[root@python bin]# getenforce

Permissive

2)setenforce

更改當前的SELINUX值 ,後面可以跟 enforcing,permissive 或者 1, 0。

[root@python bin]# setenforce permissive

3)sestatus

顯示當前的 SELinux的信息

[root@python bin]# sestatus -v

SELinux status: enabled

SELinuxfs mount: /selinux

Current mode: permissive

Mode from config file: permissive

Policy version: 20

Policy from config file: refpolicy

Process contexts:

Current context: user_u:user_r:user_t

Init context: system_u:system_r:init_t

/sbin/mingetty system_u:system_r:getty_t

/usr/sbin/sshd system_u:system_r:sshd_t

File contexts:

Controlling term: user_u:object_r:user_devpts_t

/etc/passwd system_u:object_r:etc_t

/etc/shadow system_u:object_r:shadow_t

/bin/bash system_u:object_r:shell_exec_t

/bin/login system_u:object_r:login_exec_t

/bin/sh system_u:object_r:bin_t -> system_u:object_r:shell_exec_t

/sbin/agetty system_u:object_r:getty_exec_t

/sbin/init system_u:object_r:init_exec_t

/sbin/mingetty system_u:object_r:getty_exec_t

5、其他重要命令

1)Audit2allow

很重要的一個以python寫的命令,主要用來處理日誌,把日誌中的違反策略的動作的記錄,轉換成 access vector,對開發安全策略非常有用。在refpolicy裏,它的功能比以前有了很大的擴展。

[root@python log]# cat dmesg | audit2allow -m local > local.te

2)checkmodule

編譯模塊

[root@python log]# checkmodule -m -o local.mod local.te

checkmodule: loading policy configuration from local.te

checkmodule: policy configuration loaded

checkmodule: writing binary representation (version 5) to local.mod

3)semodule_package

創建新的模塊

[root@python log]# semodule_package -o local.pp -m local.mod

4)semodule

可以顯示,加載,刪除 模塊

加載的例子:

[root@python log]# semodule -i local.pp

5)semanage

這是一個功能強大的策略管理工具,有了它即使沒有策略的源代碼,也是可以管理安全策略的。因爲我主要是介紹用源代碼來修改策略的,詳細用法大家可以參考它的man頁。

 

 

九、參考文獻

 

1. Security-Enhanced Linux in Android

https://source.android.com/security/selinux/index.html

2. 深入理解SELinux SEAndroid

http://blog.csdn.net/innost/article/details/19299937

3.SElinux詳解.pdf

4.類型強制(TE編寫規則)

http://blog.csdn.net/myarrow/article/details/10105961

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章