需求背景
之前介绍了App访问驱动节点所需要解决的权限问题,但只是针对某个项目,如果换一个项目,App和framework里面的节点路径都需要修改。现在需要优化一下,定义一个SystemProperty
,将节点的值存放到该Property里面,第三方app直接读写这个Property,这样换项目之后,只需要修改framework的节点路径即可,app的源码不需要修改。
定义SystemProperty
在device/qcom/msmnile_gvmq/system.prop
中新增一个属性
#usb mode
persist.vendor.usb.mode=none
persist.vendor.usb
已经在device/qcom/sepolicy_vndr/generic/vendor/common/property_contexts
中定义了域空间名为vendor_usb_prop
persist.vendor.usb. u:object_r:vendor_usb_prop:s0
ro.vendor.usb. u:object_r:vendor_usb_prop:s0
vendor_usb_prop
文件类型的定义device/qcom/sepolicy_vndr/legacy/vendor/common/property.te
type vendor_usb_prop, property_type;
adb shell中读写自定义property
image.png第三方app中读写自定义property
因为SystemProperties类是系统私有类
image.png第三方app无法直接访问此类中的方法,但是我们可以通过反射间接访问
public class SysProp {
private static Method sysPropGet;
private static Method sysPropSet;
private SysProp() {
}
static {
try {
Class<?> S = Class.forName("android.os.SystemProperties");
Method M[] = S.getMethods();
for (Method m : M) {
String n = m.getName();
if (n.equals("get")) {
sysPropGet = m;
} else if (n.equals("set")) {
sysPropSet = m;
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static String get(String name, String default_value) {
try {
return (String) sysPropGet.invoke(null, name, default_value);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return default_value;
}
public static void set(String name, String value) {
try {
sysPropSet.invoke(null, name, value);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
但此时会报avc错误
image.png在device/qcom/sepolicy_vndr/qva/vendor/common/untrusted_app.te
中添加权限
allow untrusted_app property_socket:sock_file write;
allow untrusted_app vendor_usb_prop:file read;
编译报错
编译报neverallow冲突问题
image.png不止这一个,还有很多其他的neverallow冲突问题,但最终都是根据报错信息,解除neverallow限制
image.png image.png解除限制后,仍然报上述错误
image.png查询资料得知可能跟MLS权限判断有关
mlsconstrain dir { read getattr search }
(t2 == app_data_file or t2 == privapp_data_file or l1 dom l2 or t1 == mlstrustedsubject or t2 == mlstrustedobject);
mlsconstrain { file lnk_file sock_file chr_file blk_file } { read getattr execute }
(t2 == app_data_file or t2 == privapp_data_file or t2 == appdomain_tmpfs or l1 dom l2 or t1 == mlstrustedsubject or t2 == mlstrustedobject);
于是给vendor_usb_prop
的定义加上mlstrustedobject
类型
type vendor_usb_prop, property_type, mlstrustedobject;
但仍然报上述错误。后请教同事得知,device/qcom/sepolicy_vndr/qva/vendor/common/untrusted_app.te
根本没有编译到,我在此文件中随便修改后编译不报错,不仅如此,device/qcom/sepolicy_vndr/qva/vendor/common/
和device/qcom/sepolicy_vndr/legacy/vendor/common/
路径下的te文件均没有被编译,就这个地方被坑了一个星期。
重新在device/qcom/sepolicy_vndr/generic/vendor/common/untrusted_app_25.te
中添加权限,编译生效,但仍然存在nerverallow冲突的问题,但没有具体说明跟哪条neverallow规则冲突了
正常报错如下:
image.png这个地方也琢磨了好几天,查阅了许多资料,并无收获。后经过逐步排查,跟untrusted_app、untrusted_app_all、untrusted_app_25、all_untrusted_apps这几个定义的区别有关,这几个定义不能随便使用,应该根据当前module中的定义来,尤其是untrusted_app_all和all_untrusted_apps。实际应用当中可以根据当前te文件里面来,当前te文件用的啥,我们就用啥,如果当前te文件没有用到,可以搜索当前module是如何定义的
image.png image.png也可以两个都试一下,如果使用不对编译会报错
image.png修改为正确的定义后仍然报上述错误,崩溃中......
selinux宏函数
静下心来,仔细思考问题原因,既然唯一声明vendor_usb_prop
类型的te文件没有被编译到,那vendor_usb_prop
到底在哪里声明类型的呢,再次全局搜索vendor_usb_prop
,在device/qcom/sepolicy_vndr/generic/vendor/common/property.te
中搜到了如下配置
vendor_internal_prop(vendor_usb_prop);
去研究了一下这种写法的含义,这是selinux的宏函数,表示一组selinux语法的组合,使用m4语言来写的,所以编译AOSP需要安装m4环境
sudo apt-get install m4
回到上面,vendor_internal_prop()
函数的定义为
define(`vendor_internal_prop', `
define_prop($1, vendor, internal)
treble_sysprop_neverallow(`
# init and dumpstate are in coredomain, but should be able to read all props.
neverallow { coredomain -init -dumpstate } $1:file no_rw_file_perms;
')
')
里面又引用了define_prop()
函数,其定义为
define(`define_prop', `
type $1, property_type, $2_property_type, $2_$3_property_type;
')
可以看到,vendor_usb_prop
其实是在vendor_internal_prop(vendor_usb_prop)
里面声明类型的,并且里面还声明了neverallow,之所以没有报具体冲突的代码行号,是因为neverallow定义在了宏函数里面,那么现在在宏函数里面剔除untrusted_app的限制,即加上-untrusted_app_all
define(`vendor_internal_prop', `
define_prop($1, vendor, internal)
treble_sysprop_neverallow(`
# init and dumpstate are in coredomain, but should be able to read all props.
# 剔除untrusted_app限制
neverallow { coredomain -init -dumpstate -untrusted_app_all } $1:file no_rw_file_perms;
')
')
然后在device/qcom/sepolicy_vndr/generic/vendor/common/untrusted_app_25.te
中添加该有权限配置
allow untrusted_app property_socket:sock_file write;
allow untrusted_app init:unix_stream_socket connectto;
allow untrusted_app vendor_usb_prop:file { map read write open getattr };
allow untrusted_app vendor_usb_prop:property_service set;
一个一个试,缺啥补啥,最终第三方app可以读写第三方属性了
image.png总结
写完这个工具,现在对selinux有了更加深入的了解了,以后再遇到权限相关的问题,那不是手拿把掐。
网友评论