属性与 SeLinux

这是一个介绍 Android 属性系统的系列文章:

  • Android 属性系统入门
  • 属性文件生成过程分析
  • 如何添加系统属性
  • 属性与 Selinux (本文)
  • 属性系统整体框架与启动过程分析
  • 属性读写过程源码分析

Android O 以后,属性的 Selinux 的规则变得复杂起来了,今天我们先看一个简单的例子,做基本的了解。在Hal与硬件服务的 treble 章节我们还会继续来学习属性相关的 Selinux 配置。

读写属性的示例代码

首先我们在 device/jelly/rice14 目录下创建如下的目录:

bash 复制代码
PropTest/
├── Android.bp
└── prop_test.cpp

其中 prop_test.cpp 具体内容如下:

cpp 复制代码
#include <string>
 
#include <cutils/properties.h>
#define LOG_TAG "prop_test"
#include <log/log.h>
#include <android-base/properties.h>
 

using namespace std;
 
int main(int argc, char *argv[])
{

    // 打印版本信息
    char android_version[PROPERTY_VALUE_MAX];
    property_get("ro.build.version.release", android_version, "");
 
    ALOGD("android version : %s", android_version);
 
    // 写入自定义属性
    property_set("vendor.my.prop.test", "xxx");

    // 读自定义属性
    char prop_test[PROPERTY_VALUE_MAX];
    property_get("vendor.my.prop.test", prop_test, "");
    ALOGD("prop test : %s", prop_test);
    
    while(1) {

    }
 
    return 0;
}

配套的编译文件 Android.bp 如下:

json 复制代码
cc_binary {
    name: "prop_test",
    srcs: [ "prop_test.cpp" ],
    vendor: true,
    shared_libs: [
        "libbase",
        "liblog",
        "libcutils",
        "libutils"
    ],
}

至此,整个示例程序就完成了,最后修改我们自定义 Product 的配置文件 device/jelly/rice14/rice14.mk :

Makefile 复制代码
PRODUCT_PACKAGES += 
    # ......
    prop_test \

Selinux 的配置

接着需要配置 SeLinux:

在 device/jelly/rice14 目录下创建如下的文件与目录:

bash 复制代码
sepolicy/
├── file_contexts
├── property_contexts
├── property.te
└── prop_te

不要忘了配置自定义 sepolicy 目录,在 device/jelly/rice14/rice14.mk 中添加如下内容:

bash 复制代码
BOARD_SEPOLICY_DIRS += \
    device/jelly/rice14/sepolicy

首先在 property.te 中定义属性类型

bash 复制代码
type vendor_mytest_prop, property_type;

接着在 property_contexts 中配置好我们自定义属性 vendor.my.prop.test 的安全上下文:

bash 复制代码
vendor.my.prop.test u:object_r:vendor_mytest_prop:s0

接着在 prop_test.te 中配置好可执行文件和对应进程的类型和域转换规则以及属性的读写权限:

bash 复制代码
# 可执行文件对应进程类型
type  myprop_test_dt, domain;

# 可执行文件类型
type myprop_test_dt_exec, exec_type, vendor_file_type, file_type;


# 域转换规则
init_daemon_domain(myprop_test_dt)
domain_auto_trans(shell, myprop_test_dt_exec, myprop_test_dt)


# 属性读写规则
set_prop(myprop_test_dt, vendor_mytest_prop);
get_prop(myprop_test_dt, vendor_mytest_prop);

get_prop(myprop_test_dt, exported2_default_prop);

在属性读写规则中,我们添加了对 exported2_default_prop 类型属性的读取规则,exported2_default_prop 是源码中 ro.build.version.release 属性对应的 type,我是通过如下的搜索命令查找到的:

bash 复制代码
find . -name "property_contexts" | xargs grep ro.build.version.release
./system/sepolicy/public/property_contexts:ro.build.version.release u:object_r:exported2_default_prop:s0 exact string
./system/sepolicy/prebuilts/api/29.0/public/property_contexts:ro.build.version.release u:object_r:exported2_default_prop:s0 exact string
./system/sepolicy/prebuilts/api/28.0/public/property_contexts:ro.build.version.release u:object_r:exported2_default_prop:s0 exact string

最后我们需要再 file_contexts 中配置可执行文件的安全上下文:

bash 复制代码
/vendor/bin/prop_test                   u:object_r:myprop_test_dt_exec:s0

接着我们就可以执行在虚拟机的 shell 中执行 prop_test 可执行文件了:

bash 复制代码
# 启动虚拟机
emulator
# 重开一个终端,进入虚拟机 shell 环境
adb shell
# root
su 
# selinux 配置为 Permissive 模式
setenforce 0
# 退出 root
exit
prop_test

接着我们查看 log:

bash 复制代码
logcat | grep prop_test                                                          
10-23 10:25:42.420  2959  2959 W prop_test: type=1400 audit(0.0:27): avc: denied { read } for name="u:object_r:vendor_mytest_prop:s0" dev="tmpfs" ino=6750 scontext=u:r:shell:s0 tcontext=u:object_r:vendor_mytest_prop:s0 tclass=file permissive=0
10-23 10:25:42.424  2959  2959 D prop_test: android version : 10
10-23 10:25:42.428  2959  2959 D prop_test: prop test : 
10-23 10:29:41.930  3704  3704 W prop_test: type=1400 audit(0.0:58): avc: denied { use } for path="/dev/pts/0" dev="devpts" ino=3 scontext=u:r:myprop_test_dt:s0 tcontext=u:r:adbd:s0 tclass=fd permissive=0
10-23 10:29:41.930  3704  3704 W prop_test: type=1400 audit(0.0:60): avc: denied { use } for path="/dev/pts/0" dev="devpts" ino=3 scontext=u:r:myprop_test_dt:s0 tcontext=u:r:adbd:s0 tclass=fd permissive=0
10-23 10:29:41.930  3704  3704 W prop_test: type=1400 audit(0.0:61): avc: denied { use } for path="/dev/goldfish_pipe" dev="tmpfs" ino=7279 scontext=u:r:myprop_test_dt:s0 tcontext=u:r:adbd:s0 tclass=fd permissive=0
10-23 10:29:41.930  3704  3704 W prop_test: type=1400 audit(0.0:62): avc: denied { use } for path="/dev/goldfish_pipe" dev="tmpfs" ino=7279 scontext=u:r:myprop_test_dt:s0 tcontext=u:r:adbd:s0 tclass=fd permissive=0
10-23 10:31:17.980  3919  3919 I prop_test: type=1400 audit(0.0:87): avc: denied { use } for path="/dev/pts/0" dev="devpts" ino=3 scontext=u:r:myprop_test_dt:s0 tcontext=u:r:adbd:s0 tclass=fd permissive=1
10-23 10:31:17.980  3919  3919 I prop_test: type=1400 audit(0.0:88): avc: denied { read write } for path="/dev/pts/0" dev="devpts" ino=3 scontext=u:r:myprop_test_dt:s0 tcontext=u:object_r:devpts:s0 tclass=chr_file permissive=1
10-23 10:31:17.980  3919  3919 I prop_test: type=1400 audit(0.0:89): avc: denied { read write } for path="socket:[9765]" dev="sockfs" ino=9765 scontext=u:r:myprop_test_dt:s0 tcontext=u:r:adbd:s0 tclass=unix_stream_socket permissive=1
10-23 10:31:17.980  3919  3919 I prop_test: type=1400 audit(0.0:90): avc: denied { use } for path="/vendor/bin/prop_test" dev="dm-1" ino=158 scontext=u:r:myprop_test_dt:s0 tcontext=u:r:shell:s0 tclass=fd permissive=1
10-23 10:31:18.000  3919  3919 D prop_test: android version : 10
10-23 10:31:18.002  3919  3919 D prop_test: prop test : xxx

发现我们的程序任然缺少一些权限,我们把权限相关的 log 拷贝下来,在源码根目录下新建一个 avc_log.txt 文件,把缺少权限相关的 log 拷贝进去:

bash 复制代码
# avc_log.txt
10-23 10:38:05.670  2910  2910 W prop_test: type=1400 audit(0.0:28): avc: denied { use } for path="/dev/pts/0" dev="devpts" ino=3 scontext=u:r:myprop_test_dt:s0 tcontext=u:r:adbd:s0 tclass=fd permissive=0
10-23 10:38:05.670  2910  2910 W prop_test: type=1400 audit(0.0:30): avc: denied { use } for path="/dev/pts/0" dev="devpts" ino=3 scontext=u:r:myprop_test_dt:s0 tcontext=u:r:adbd:s0 tclass=fd permissive=0
10-23 10:38:05.670  2910  2910 W prop_test: type=1400 audit(0.0:31): avc: denied { use } for path="socket:[10955]" dev="sockfs" ino=10955 scontext=u:r:myprop_test_dt:s0 tcontext=u:r:adbd:s0 tclass=fd permissive=0
10-23 10:38:05.670  2910  2910 W prop_test: type=1400 audit(0.0:32): avc: denied { use } for path="/dev/goldfish_pipe" dev="tmpfs" ino=7343 scontext=u:r:myprop_test_dt:s0 tcontext=u:r:adbd:s0 tclass=fd permissive=0
10-23 10:38:57.400  3034  3034 I prop_test: type=1400 audit(0.0:39): avc: denied { use } for path="/dev/pts/0" dev="devpts" ino=3 scontext=u:r:myprop_test_dt:s0 tcontext=u:r:adbd:s0 tclass=fd permissive=1
10-23 10:38:57.400  3034  3034 I prop_test: type=1400 audit(0.0:40): avc: denied { read write } for path="/dev/pts/0" dev="devpts" ino=3 scontext=u:r:myprop_test_dt:s0 tcontext=u:object_r:devpts:s0 tclass=chr_file permissive=1
10-23 10:38:57.400  3034  3034 I prop_test: type=1400 audit(0.0:41): avc: denied { read write } for path="socket:[10955]" dev="sockfs" ino=10955 scontext=u:r:myprop_test_dt:s0 tcontext=u:r:adbd:s0 tclass=unix_stream_socket permissive=1
10-23 10:38:57.410  3034  3034 I prop_test: type=1400 audit(0.0:42): avc: denied { use } for path="/vendor/bin/prop_test" dev="dm-1" ino=158 scontext=u:r:myprop_test_dt:s0 tcontext=u:r:shell:s0 tclass=fd permissive=1

接着执行命令 audit2allow -i avc_log.txt 生成缺失的权限配置:

bash 复制代码
allow myprop_test_dt adbd:fd use;
allow myprop_test_dt adbd:unix_stream_socket { read write };
allow myprop_test_dt devpts:chr_file { read write };
allow myprop_test_dt shell:fd use;

把这些权限配置加入到 prop_test.te 后,重新编译系统,启动虚拟机,程序即可正常运行。

相关推荐
疯华整猫16 小时前
把二十七个 init 从首帧前面搬走:用 Trae 把启动优化钉进 CI
android·性能优化·ai编程
传奇开心果16 小时前
【探秘 Jetpack Compose 框架深水区】 第8课:rememberSaveable 的边界在哪里?——Bundle、Saver 与什么值得跨进程存活
android·kotlin
Frankie_stand18 小时前
测试自动化实战指南:从脚本化、自动判据到 CI 集成的完整落地路径
android·ci/cd·自动化
恋猫de小郭18 小时前
Flutter 大小核优化又被回滚,然后又开新提案?
android·前端·flutter
Kapaseker19 小时前
领导问我 Kotlin 的 Nothing 是什么?
android·kotlin
韩曙亮19 小时前
【错误记录】安卓 adb 调试 5037 端口占用排查 ( adb 的三层结构 | 找出本机占用 5037 的进程 )
android·数据库·adb·安卓·错误记录
三少爷的鞋20 小时前
不改变异步本质,只改变代码组织:Telegram 项目的 Kotlin 协程实践
android
好的佩奇1 天前
蓝牙之广播与扫描
android·flutter·蓝牙
传奇开心果编程1 天前
【Jetpack Compose娓娓道来】第36课:焦点管理与键盘输入——让遥控器、键盘和输入法都“找得到北”
android·kotlin·移动开发·交互·android jetpack·ui框架·声明式ui
hai_android1 天前
AudioTrack 深度解析:从原理到实战
android·java·kotlin