我在基于AOSP的Android 7.1.2(更准确地说是基于索尼开放设备树)上正确运行自定义selinux策略时遇到了一些问题。
我的问题是,审计日志不断告诉我,我实际添加的文件访问规则丢失了。我还将audit2allow创建的规则复制到了我的策略文件中,但即使是这些规则也无法正常工作。
因此,让我们深入了解细节:
我创建了一个名为vendor_app的自定义域。此域是根据其签名分配给应用程序的。我在mac_permissions.xml中添加了一个条目,以分配seinfo字段vendor。在seap_contexts中,我分配vendor_app域,如下所示:
user=_app seinfo=vendor domain=vendor_app type=app_data_file levelFrom=user
我的应用程序在vendor_app上下文中正确启动:
# ps -Z | grep permissiontest
u:r:vendor_app:s0:c512,c768 u0_a109 4110 508 1620732 79584 SyS_epoll_ 0000000000 S com.vendor.android.permissiontest
所以,现在对于根本不起作用的部分。在vendor_app上下文中运行的应用程序应获得对/persist/vender中文件的读/写访问权限。为了创建必要的规则,我在设备目录中的sepolicy文件夹中添加了一个名为vendor.te的文件,其中包含以下内容:
type vendor_app, domain;
type vendor_file, file_type, data_file_type;
# permissive vendor_app;
app_domain(vendor_app)
net_domain(vendor_app)
bluetooth_domain(vendor_app)
allow vendor_app persist_file:dir r_dir_perms;
allow vendor_app vendor_file:dir create_dir_perms;
allow vendor_app vendor_file:file create_file_perms;
allow vendor_app audioserver_service:service_manager find;
allow vendor_app cameraserver_service:service_manager find;
allow vendor_app drmserver_service:service_manager find;
allow vendor_app mediaserver_service:service_manager find;
allow vendor_app mediaextractor_service:service_manager find;
allow vendor_app mediacodec_service:service_manager find;
allow vendor_app mediadrmserver_service:service_manager find;
allow vendor_app persistent_data_block_service:service_manager find;
allow vendor_app radio_service:service_manager find;
allow vendor_app surfaceflinger_service:service_manager find;
allow vendor_app app_api_service:service_manager find;
allow vendor_app system_api_service:service_manager find;
allow vendor_app vr_manager_service:service_manager find;
我在file_contexts配置中添加了一个条目:
###################################
# persist files
#
/persist(/.*)? u:object_r:persist_file:s0
/persist/vendor(/.*)? u:object_r:vendor_file:s0
在/persist分区上,我创建了一些目录结构,使具有适当权限的文件夹可以在其中添加一些文件。
# ls -Zal /persist/vendor/
total 56
drwxrwxrwx 5 persist persist u:object_r:vendor_file:s0 4096 2017-08-03 22:27 .
drwxrwx--x 16 system system u:object_r:persist_file:s0 4096 2017-08-01 16:24 ..
drwxrwxrwx 2 profile profile u:object_r:vendor_file:s0 4096 2017-08-04 13:34 profile
drwxrwxrwx 2 provision provision u:object_r:vendor_file:s0 4096 2017-08-04 13:34 provisioning
drwxrwxrwx 2 updater updater u:object_r:vendor_file:s0 4096 2017-08-04 13:34 updater
我知道find-服务规则正在发挥作用,因为我可以在强制模式下启动我的应用程序,不会收到任何投诉。根据有关persist_file:dir的规则允许,我还可以访问{search}中的/persist目录。
当我尝试将一个新文件(如/strist/vendor/updater/test)写入/prist目录时,我会收到来自audited的错误消息:
08-04 16:34:29.269 4108 4108 W .permissiontest: type=1400 audit(0.0:27): avc: denied { write } for name="updater" dev="mmcblk0p44" ino=55 scontext=u:r:vendor_app:s0:c512,c768 tcontext=u:object_r:vendor_file:s0 tclass=dir permissive=0
audit2allow当然会将该错误转换为以下规则:
#============= vendor_app ==============
allow vendor_app vendor_file:dir write;
由于write是create_dir_perms的成员,所以它实际上应该在那里。我还尝试将audit2allow创建的行添加到我的供应商.te中,但没有成功。
请注意,写入更新程序还涉及在persist_file上搜索和在vendor_fileearch,这两种操作似乎都没有任何问题。
有人有什么建议吗,如何正确调试,甚至可能有任何解决这个问题的方案?我已经研究了两天了,这让我发疯了。
编辑:
啊/persistent当然是可写挂载的:
# mount | grep persist
/dev/block/bootdevice/by-name/persist on /persist type ext4 (rw,seclabel,nosuid,nodev,relatime,nodelalloc,errors=panic,data=ordered)
编辑2:
正如Paul Ratazzi所要求的,我已经扫描了sepolicy文件和实际加载到内核中的版本,以查看是否存在我的规则。
$ sesearch -A -s vendor_app -t vendor_file policy
allow vendor_app vendor_file:dir { rename search setattr read lock create reparent getattr write ioctl rmdir remove_name open add_name };
allow vendor_app vendor_file:file { rename setattr read lock create getattr write ioctl unlink open append };
因此,它们实际上被正确地部署到设备上。
好吧,经过更多的挖掘,看起来我终于找到了答案。为了挽救那些在脑损伤的日子里遇到同样问题的人,这里有一个解决方案:
除了MAC(强制访问控制),安卓系统上的SElinux也有MLS(多级安全)。
虽然MAC在安卓SELinux概念中以某种方式进行了描述,但关于MLS的信息只是非常简短和隐含地提到:
在SELinux中,标签的形式为:user:role:type:mls_level,其中类型是访问决策的主要组件,可以由组成标签的其他部分组件进行修改。
因此,我的Android应用程序运行在MLS级别(由c512、c768表示),可以读取/持久化上的文件,但不能写入这些文件。因此,需要做的是,我的应用程序获得MLS级别,以正确访问这些文件。
我(目前)已经通过将我的自定义标签更改为来存档
type vendor_app, domain, mlstrustedsubject;
这让我的应用程序值得信赖。这解决了问题,但允许我大量访问我的应用程序。因此,更好的选择是将目的地的安全级别设置为允许对我的应用程序进行读写访问的级别。
所以到目前为止,这基本上是这个问题的解决方案(虽然还没有完成)。