My custom selinux policies seem to be ignored by android system
Asked Answered
B

1

11

I have some trouble on getting custom selinux policies running properly on an AOSP based Android 7.1.2 (more precisely based on sony open devices tree).

My problem is that the audit logs keep telling me about missing file access rules that I actually added. I also copied rules that audit2allow has created to my policy files, but even those do not properly work.

So, let's dig into the details:

I created a custom domain called vendor_app. This domain is assigned to an app based on its signature. I have added an entry to the mac_permissions.xml to assign the seinfo field vendor. In seapp_contexts I assign the vendor_app domain like this:

user=_app seinfo=vendor domain=vendor_app type=app_data_file levelFrom=user

My app is properly started in the vendor_app context:

# 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

So, now for the part that does not work at all. An app running in the vendor_app context shall get read/write access to files in /persist/vendor. To create the nessesary rules, I added a file called vendor.te to the sepolicy folder in the device directory with the followin content:

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;

And I have added one entry in the file_contexts configuration:

###################################
# persist files
#
/persist(/.*)?                                                      u:object_r:persist_file:s0
/persist/vendor(/.*)?                                               u:object_r:vendor_file:s0

On the /persist partition, I created some directory structure to have folders with appropriate permissions to add some files there.

# 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

I know that the find-rules for the services are working, as I am able to start my app in enforcing mode and do not get any complaints about that. I am also able to access the /persist directory for { search } as allowed by the rule regarding persist_file:dir.

As soon as I try writing a new file like /persist/vendor/updater/test to the /persist directory, I get error messages from auditd:

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

That error is of course converted by audit2allow to the following rule:

#============= vendor_app ==============
allow vendor_app vendor_file:dir write;

As write is a member of create_dir_perms, it actually should be there. I have also tried adding the line created by audit2allow to my vendor.te without any success.

Please notice that writing to updater also involves search on persist_file and search on vendor_file which both seem to work without any problems.

Has anyone any advice, how to debug that properly or maybe even any solution for this problem? I have been digging on this for two days now and it's driving me nuts.

EDIT:

Ah. /persist is of course mounted writable:

# mount | grep persist
/dev/block/bootdevice/by-name/persist on /persist type ext4 (rw,seclabel,nosuid,nodev,relatime,nodelalloc,errors=panic,data=ordered)

EDIT 2:

As Paul Ratazzi has asked, I have scanned the sepolicy file and the version actually loaded into the kernel for the presence of my rules as well.

$ 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 };

So they are infact deployed to the device properly.

Bassorilievo answered 4/8, 2017 at 14:42 Comment(2)
If you haven't already, try pulling '/sepolicy' from your running device, load it into 'apol' and check that all of your rules are in fact getting compiled into the policy binary and showing up as you expect. That might help narrow this down to a build vs. run-time issue.Cowboy
Thank's for hinting. As a matter of fact, apol does (afaik) not work with selinux policies for android, as google is using a custom version (v30) of policy files that is not supported by setools. But they provide their own tools to parse and search the policy files. Those tools show that the rules are present on the device. I'll edit the post and put the output there.Bassorilievo
B
9

Well, after some more digging, it looks like I finally found the answer. To maybe save someone running into the same problem some brain-hurting days, here is the solution:

Besides MAC (Mandatory Access Control) SElinux on android also MLS (Multi-Level Security).

While MAC is somehow described in the Android SELinux concepts, the information about MLS is only mentioned very brief and implicitly:

In SELinux, a label takes the form: user:role:type:mls_level, where the type is the primary component of the access decisions, which may be modified by the other sections components which make up the label.

So, what happens is that my Android app runs in a MLS level (indicated by c512,c768) that can read files on /persist but not write them. So what needs to happen is that my app gets an MLS level to properly access those files.

I have (for now) archived this by changing my custom label to

type vendor_app, domain, mlstrustedsubject;

which makes my app trusted. This fixes the problem but grants a whole lot of access to my app. Thus a better option would be to lover the security level of the destination to a level that grants read and write access to my app.

So this is basically the solution for this problem up to now (while still not yet complete).

Bassorilievo answered 7/8, 2017 at 16:2 Comment(3)
Were you able to reduce the security level to the app instead of using mlstrustedobject?Caroche
I think I removed "levelFrom=user" from seapp_contexts, but I finally have been able to eliminate mlstrustedobject, yes.Bassorilievo
Thank you for this answer. Spend a night trying to figure out why my i2c_device:chr_file write was getting denied. No errors whatsoever but it would just deny that even though specifically allowed. It turned out to need mlstrustedsubjectUnification

© 2022 - 2024 — McMap. All rights reserved.