2

I am working on an application that needs root access and I have a device which is rooted but not with Magisk. This device has only adb shell root available. So, I need an alternative to call the required functionality without the use of Magisk or other tools. I did it by placing my executable inside system directory and run it as a daemon. This daemon required access on some location which is restricted by SELinux policies.

I have injected the required policy with following commands:

    sepolicy-inject -s init -t su -c process -p transition -l
    sepolicy-inject -s su -t system_file -c file -p entrypoint -l
    sepolicy-inject -s init -t su -c process -p rlimitinh -l
    sepolicy-inject -s init -t su -c process -p siginh -l
    sepolicy-inject -s su -t shell_exec -c file -p read -l
    sepolicy-inject -s su -t shell_exec -c file -p execute -l
    sepolicy-inject -s su -t shell_exec -c file -p getattr  -l
    sepolicy-inject -s su -t vendor_toolbox_exec -c file -p execute_no_trans -l
    sepolicy-inject -s init -t su -c process -p noatsecure -l
    sepolicy-inject -s su -t toolbox_exec -c file -p getattr -l
    sepolicy-inject -s su -t toolbox_exec -c file -p execute -l
    sepolicy-inject -s su -t system_file -c file -p execute_no_trans -l
    sepolicy-inject -s su -t storage_file -c dir -p search -l
    sepolicy-inject -s su -t storage_file -c lnk_file -p read -l
    sepolicy-inject -s su -t tmpfs -c dir -p search -l
    sepolicy-inject -s su -t mnt_user_file -c dir -p search -l
    sepolicy-inject -s su -t mnt_user_file -c lnk_file -p read -l
    sepolicy-inject -s su -t sdcardfs -c dir -p search -l
    sepolicy-inject -s su -t sdcardfs -c file -p append -l
    sepolicy-inject -s su -t toolbox_exec -c file -p read -l
    sepolicy-inject -s su -t toolbox_exec -c file -p open -l
    sepolicy-inject -s su -t sdcardfs -c file -p read -l
    sepolicy-inject -s su -t sdcardfs -c file -p write -l
    sepolicy-inject -s su -t sdcardfs -c file -p open -l
    sepolicy-inject -s su -t media_rw_data_file -c file -p read -l
    sepolicy-inject -s su -t media_rw_data_file -c file -p write -l
    sepolicy-inject -s su -t media_rw_data_file -c file -p open -l
    sepolicy-inject -s su -t media_rw_data_file -c file -p append -l

The problem is that they are not persistent after reboot. I know I can extract boot.img and ramdisk, replace /sepolicy with new policy file copied from /sys/fs/selinux/policy, repack boot.img and flash back.

I want to do it without reflashing boot.img. Is there any way with which I can execute above commands after Android finishes with generating SELinux files?

I have tried following rc files:

#/etc/init/custom.rc

# define service, use executable here if script not needed
service custom /system/bin/custom.sh

    # don't start unless explicitly asked to
    disabled

    # Use `seclabel u:r:magisk:s0` to run with unrestricted SELinux context to avoid avc denials
    # can also use "u:r:su:s0" on userdebug / eng builds if no Magisk
    # it's required if SELinux is enforcing and service needs access
    # to some system resources not allowed by default sepolicy
    seclabel u:r:su:s0

# start the service when boot is completed
on property:sys.boot_completed=1
    sepolicy-inject -s init -t su -c process -p transition -l
    sepolicy-inject -s su -t system_file -c file -p entrypoint -l
    sepolicy-inject -s init -t su -c process -p rlimitinh -l
    sepolicy-inject -s init -t su -c process -p siginh -l
    sepolicy-inject -s su -t shell_exec -c file -p read -l
    sepolicy-inject -s su -t shell_exec -c file -p execute -l
    sepolicy-inject -s su -t shell_exec -c file -p getattr  -l
    sepolicy-inject -s su -t vendor_toolbox_exec -c file -p execute_no_trans -l
    sepolicy-inject -s init -t su -c process -p noatsecure -l
    sepolicy-inject -s su -t toolbox_exec -c file -p getattr -l
    sepolicy-inject -s su -t toolbox_exec -c file -p execute -l
    sepolicy-inject -s su -t system_file -c file -p execute_no_trans -l
    sepolicy-inject -s su -t storage_file -c dir -p search -l
    sepolicy-inject -s su -t storage_file -c lnk_file -p read -l
    sepolicy-inject -s su -t tmpfs -c dir -p search -l
    sepolicy-inject -s su -t mnt_user_file -c dir -p search -l
    sepolicy-inject -s su -t mnt_user_file -c lnk_file -p read -l
    sepolicy-inject -s su -t sdcardfs -c dir -p search -l
    sepolicy-inject -s su -t sdcardfs -c file -p append -l
    sepolicy-inject -s su -t toolbox_exec -c file -p read -l
    sepolicy-inject -s su -t toolbox_exec -c file -p open -l
    sepolicy-inject -s su -t sdcardfs -c file -p read -l
    sepolicy-inject -s su -t sdcardfs -c file -p write -l
    sepolicy-inject -s su -t sdcardfs -c file -p open -l
    sepolicy-inject -s su -t media_rw_data_file -c file -p read -l
    sepolicy-inject -s su -t media_rw_data_file -c file -p write -l
    sepolicy-inject -s su -t media_rw_data_file -c file -p open -l
    sepolicy-inject -s su -t media_rw_data_file -c file -p append -l
    start custom

but it is not working because I think Android generates SELinux files after my custom service has been triggered.

Also tried above commands on onrestart option of init service but failed.

Any suggestion?

  • if timing is your only problem i would suggest sleep command – alecxs Jul 22 at 11:34
  • I have tried to add 5 minutes sleep with sleep 300 after on property:sys.boot_completed=1 but the service is started instantly on boot complete so this command is not working as expected. – Vatish Sharma Aug 1 at 6:41
1

The init service you have defined won't inject SELinux policy rules because of two reasons:

  • The syntax of sepolicy-inject commands is incomplete; .rc files aren't shell scripts. The correct syntax would be:

    #/etc/init/custom.rc
    
    ...
    
    on property:sys.boot_completed=1
        exec - -- /system/bin/sepolicy-inject -s init -t su -c process -p transition -l
    
    ...
    
  • This will execute the statement with context u:r:init.s0. But modifying SELinux policy requires permission load_policy i.e. you need to inject rule sepolicy-inject -s init -t kernel -c security -p load_policy -l which again won't be allowed to init. Read What sepolicy context will allow any other context to access it? to know how SELinux is enforced on Android.

So you are in the same chicken or the egg situation as you were at the start of your previous question. SELinux policy can only be modified with context u:r:su:s0 which is available only through adb shell on userdebug builds of ROMs. Or root the device e.g. with Magisk, or replace /sepolicy file in boot.img.

NOTE: You don't need to define rules like sepolicy-inject -s su ... as u:r:su:s0 is already set permissive in policy.

sepolicy File Locations:

On pre-Treble Android releases, there are two possible locations defined for sepolicy file:

/sepolicy
/data/security/current/sepolicy

As stated here:

The Android initialisation / reload process will first check for this file at: /data/security/current/sepolicy. If not present then check root directory: /sepolicy.

However sepolicy is loaded by init at very early boot process when /data is not mounted. As stated here:

Since only the root filesystem is mounted, it chooses /sepolicy at this time. The other path is for dynamic runtime reloads of policy.

So initially /sepolicy is loaded for sure. But you can put modified sepolicy at other locations to see if the previous policy is (or could possibly be) overwritten at some later boot stage. You might need to copy other files as well; this post could be helpful. I never tried this.

On Oreo+ a monolithic policy is loaded from /sepolicy if the device is not a Treble device (or if Magisk patched init to force load /sepolicy). On Treble devices /system, /vendor and /odm are mounted by kernel before starting init, as configured in DTB. Here a pre-compiled split policy is loaded from /vendor/etc/selinux/precompiled_sepolicy if it matches with /system, or the policy is built from .cil files in /system/etc/selinux and /vendor/etc/selinux before loading. See details here.

In both situations things are far more complicated to try than simply replacing /sepolicy file in boot.img, which is not a big deal in my opinion. You can dd out a backup of your original boot.img to /sdcard which can be restored in a few seconds anytime. However bootloader needs to be unlocked to boot a modified boot.img.
Please note that on devices with system-as-root (A/B or others) ramdisk is moved to system.img. So all files which were previously part of boot.img (except kernel and DTB) are now part of system partition.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.