Android SELinux 编写 SELinux 政策(转自官网)

Android 开放源代码项目 (AOSP) 针对所有 Android 设备中常用的应用和服务提供了一个可靠实用的基本政策。AOSP 的贡献者会定期完善该政策。核心政策应占设备上最终政策的 90-95%,而剩下的 5-10% 则为设备专用自定义政策。本文重点介绍这些设备专用自定义政策、编写设备专用政策的方法,以及在编写此类政策时要避免的一些陷阱。

<devsite-heading text="设备启动" for="device_bringup" level="h2" link="" toc="" class="" back-to-top="">## 设备启动</devsite-heading> <devsite-heading text="设备启动" for="device_bringup" level="h2" link="" toc="" class="" back-to-top=""></devsite-heading>

在编写设备专用政策时,请按照下列步骤操作。

<devsite-heading text="在宽容模式下运行" for="run_in_permissive_mode" level="h3" link="" toc="" class="">### 在宽容模式下运行</devsite-heading>

当设备处于宽容模式时,拒绝事件会被记录下来,但不会被强制执行。宽容模式非常重要,原因有以下两点:

  • 宽容模式可确保政策启用不会延误其他早期设备启动任务。
  • 被强制执行的拒绝事件可能会掩盖其他拒绝事件。例如,文件访问通常会涉及目录搜索、文件打开和文件读取操作。在强制模式下,只会发生目录搜索拒绝事件。宽容模式可确保所有拒绝事件都会显示出来。

要使设备进入宽容模式,最简单的方法是使用内核命令行来实现。相应命令可以添加到设备的 BoardConfig.mk 文件中:platform/device/<vendor>/<target>/BoardConfig.mk。修改命令行之后,执行 make clean,接着执行 make bootimage,然后刷写新的启动映像。

在此之后,通过以下命令确认宽容模式:

<devsite-code><pre class="devsite-terminal" is-upgraded="">adb shell getenforce
</pre></devsite-code>

将处于全局宽容模式的时间设为两周比较合理。在解决大多数拒绝事件之后,返回到强制模式,并在出现错误时加以解决。对于仍然不断出现拒绝事件的域或仍处于密集开发阶段的服务,可以暂时使其进入宽容模式,但要尽快使其返回到强制模式。

<devsite-heading text="提早采用强制模式" for="enforce_early" level="h3" link="" toc="" class="">### 提早采用强制模式</devsite-heading>

在强制模式下,拒绝事件会被记录下来,并且会被强制执行。最佳做法是尽早使您的设备进入强制模式。如果花时间等待创建和强制执行设备专用政策,通常会导致有问题的产品和糟糕的用户体验。要提前足够长的时间开始参与 dogfooding,确保对实际使用中涉及的功能进行全面测试。提早开始有助于确保安全问题能够在相关人员做出设计决策时被考虑在内。相反,仅根据观察到的拒绝事件来授予权限是一种不安全的做法。可以利用这段时间对设备进行安全审核,并针对不应被允许的行为提出错误。

<devsite-heading text="移除或删除现有政策" for="remove_or_delete_existing_policy" level="h3" link="" toc="" class="">### 移除或删除现有政策</devsite-heading>

之所以要在新设备上从头开始创建设备专用政策,有很多合理的理由,其中包括:

<devsite-heading text="解决核心服务生成的拒绝事件" for="address_denials_of_core_services" level="h3" link="" toc="" class="">### 解决核心服务生成的拒绝事件</devsite-heading>

核心服务生成的拒绝事件通常是通过为文件添加标签来解决的。例如:

<devsite-code><pre is-upgraded="">avc: denied { open } for pid=1003 comm=”mediaserver” path="/dev/kgsl-3d0”
dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0
tclass=chr_file permissive=1
avc: denied { read write } for pid=1003 name="kgsl-3d0" dev="tmpfs"
scontext=u:r:mediaserver:s0
tcontext=u:object_r:device:s0 tclass=chr_file permissive=1
</pre></devsite-code>

是完全通过为 /dev/kgsl-3d0 添加适当的标签来解决的。在此示例中,tcontextdevice。这表示默认环境,在该环境中,/dev 中的内容都会获得 device 标签(被分配了更具体的标签的内容除外)。直接在此处接受来自 audit2allow 的输出会导致不正确且过度宽容的规则。

要解决这种问题,可以为文件添加更具体的标签,在此示例中为 gpu_device。由于 mediaserver 在核心政策中已有访问 gpu_device 所需的必要权限,因此不再需要更多权限。

其他需要以核心政策中预定义的类型作为标签的设备专用文件:

一般情况下,向默认标签授予权限的做法是错误的。其中许多权限都是 neverallow 规则所不允许的,但即使该规则并未明确禁止这些权限,也最好是提供具体标签。

<devsite-heading text="为新服务添加标签并解决拒绝事件" for="label_new_services_and_address_denials" level="h3" link="" toc="" class="">### 为新服务添加标签并解决拒绝事件</devsite-heading>

通过 init 启动的服务需要在各自的 SELinux 域中运行。以下示例会将服务“foo”放入它自己的 SELinux 域中并为其授予权限。

该服务是在设备的 init.<var>device</var>.rc 文件中启动的,如下所示:

<devsite-code><pre class="" is-upgraded="">service foo /system/bin/foo
class core
</pre></devsite-code>

  1. 创建一个新域“foo”

    创建包含以下内容的文件 device/<var>manufacturer</var>/<var>device-name</var>/sepolicy/foo.te

    <devsite-code><pre class="" is-upgraded=""># foo service
    type foo, domain;
    type foo_exec, exec_type, file_type;

    init_daemon_domain(foo)
    </pre></devsite-code>

  • 这是 foo SELinux 域的初始模板,您可以根据该可执行文件执行的具体操作为该模板添加规则。

    • /system/bin/foo 添加标签

    将以下内容添加到 device/<var>manufacturer</var>/<var>device-name</var>/sepolicy/file_contexts

    <devsite-code><pre class="" is-upgraded="">/system/bin/foo u:object_r:foo_exec:s0
    </pre></devsite-code>

  1. 这可确保为该可执行文件添加适当的标签,以便 SELinux 在适当的域中运行相应服务。

  2. 编译并刷写启动映像和系统映像。

  3. 优化相应域的 SELinux 规则。

    根据拒绝事件确定所需的权限。audit2allow 工具提供了一些实用的指南,但该工具仅适用于提供编写政策时所需的信息。切勿只是复制输出内容。

<devsite-heading text="切换回强制模式" for="enforcing_mode" level="h3" link="" toc="" class="">### 切换回强制模式</devsite-heading>

可以在宽容模式下进行问题排查,但要尽早切换回强制模式,并尽量保持该模式。

<devsite-heading text="常见错误" for="common_mistakes" level="h2" link="" toc="" class="" back-to-top="">## 常见错误</devsite-heading> <devsite-heading text="常见错误" for="common_mistakes" level="h2" link="" toc="" class="" back-to-top=""></devsite-heading>

下面介绍了在编写设备专用政策时发生的常见错误的一些解决方法。

<devsite-heading text="过度使用否定" for="overuse_of_negation" level="h3" link="" toc="" class="">### 过度使用否定</devsite-heading>

以下示例规则类似于锁着前门,但开着窗户:

<devsite-code><pre is-upgraded="">allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms</pre></devsite-code>

该规则的意图很明确:除了第三方应用之外,其他所有应用都可以访问调试设备。

该规则存在几个方面的缺陷。排除 untrusted_app 所起到的效果微不足道,因为所有应用都可以选择在 isolated_app 网域中运行服务。同样,如果第三方应用的新域被添加到了 AOSP,它们也可以访问 scary_debug_device。该规则过于宽容。对于大多数域来说,能够访问该调试工具并不能使它们获益。该规则应编写为仅允许需要访问该调试工具的域。

<devsite-heading text="正式版中的调试功能" for="debugging_features_in_production" level="h3" link="" toc="" class="">### 正式版中的调试功能</devsite-heading>

调试功能及其政策不应存在于正式版中。

最简单的替代方案是,仅当 eng/userdebug 版本中停用了 SELinux 时,才允许使用调试功能,例如 adb rootadb shell setenforce 0

另一种安全的替代方案是在 userdebug_or_eng 声明中包含调试权限。

<devsite-heading text="政策规模扩张" for="policy_size_explosion" level="h3" link="" toc="" class="">### 政策规模扩张</devsite-heading>

在 Wild 中描述 SEAndroid 政策中介绍了一个令人关注的设备政策自定义发展趋势。设备专用政策应占设备上运行的所有政策的 5-10%。如果自定义政策所占的比例超过 20%,则几乎肯定会包含超特权域和 Dead 政策。

过大的政策:

  • 由于此类政策位于 ramdisk 中,并且还会加载到内核内存中,因此会占据两倍的内存。
  • 需要较大的启动映像,浪费磁盘空间。
  • 影响运行时政策查询次数。

以下示例显示了制造商专用政策分别占设备上政策 50% 和 40% 的两种设备。重写政策大幅提高了安全性,而且功能方面没有任何损失,如下所示。(AOSP 设备 Shamu 和 Flounder 也包含在了该示例中,以便进行比较。)


图片.png

在两种设备中,政策的规模和权限数量都大大减小了。政策规模的减小几乎完全是因为移除了不必要的权限,其中许多权限可能是由 audit2allow 生成且被随意添加到政策中的规则。对于这两种设备来说,Dead 域也是一个问题。

<devsite-heading text="授予 dac_override 权限" for="granting_the_dac_override_capability" level="h3" link="" toc="" class="">### 授予 dac_override 权限</devsite-heading>

dac_override 拒绝事件意味着违规进程正在尝试使用错误的 unix user/group/world 权限访问某个文件。正确的解决方案几乎从不授予 dac_override 权限,而是更改相应文件或进程的 unix 权限。有些域(例如 initvoldinstalld)确实需要能够替换 unix 文件权限才能访问其他进程的文件。要查看更深入的讲解,请访问 Dan Walsh 的博客

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容