GS4 Google Play Edition != Nexus
Caveat: Everything here is based on the leaked images floating around and are not necessarilly represenative of what the final, released version will look like. That said, it is probably partially useful and my curiousity got the best of me…
As you probably know by now the GS4 Google Play Edition is not a Nexus device. It does not get updates from Google and does not have only Google provided code. It was developed by Samsung but removes all of the TouchWiz features. However, it is an updated version of Android (4.3) and has some things that the standard GS4 does not.
Since the standard GS4 SE for Android controls are Samsung-specific, and deeply embedded in the Knox libraries Google had to provide something else.
Rather than using the management system proposed by the SE for Android community they invented another, third, system.
It is a good bet that the interfaces I’ll talk about here will show up in AOSP when 4.3 is released so getting a head start can’t be a bad idea
State of SE for Android on the GS4 GPE
As you can see in screenshots released SELinux is present and set to permissive in the Settings app. The policy looks very similar to that of the standard GS4, including components that have been removed from this version:
$ cat seapp_contexts | grep samsung user=_app seinfo=samsung domain=samsung_app type=app_data_file user=_app seinfo=samsung name=com.sec.android.app.samsungapps domain=samsung_app type=app_data_file user=_app seinfo=untrusted name=com.vlingo.midas domain=samsung_app type=app_data_file user=_app seinfo=untrusted name=tv.peel.samsung.app domain=samsung_app type=app_data_file user=_app seinfo=untrusted name=tv.peel.samsung.widget domain=samsung_app type=app_data_file
So, since this is basically the same policy hopefully enforcing mode will work fine, as it does on the standard version:
# setenforce 1
Oh! The screen froze, I can’t hit any buttons or even get back to home.
# setenforce 0
Doesn’t fix it! Well… obviously this policy needs some work. Too bad the AVC messages are still removed from the kernel messages and no auditing is present… sigh
Let’s move on to the management API.
Managing SE for Android on the GS4 GPE
As I already said, the Knox components have been removed so the previous client I posted won’t work. Looking at the code there is a new interface. It is in the services framework and is triggered by an Intent:
Intent i = new Intent("android.intent.action.UPDATE_SEPOLICY"); i.putExtra("CONTENT_PATH", bundle_file_path); i.putExtra("REQUIRED_HASH", "NONE"); i.putExtra("SIGNATURE", "..."); i.putExtra("VERSION", "1");
The Intent can be triggered from anywhere, so a third party app can call it, a separate permission is not even required. The REQUIRED_HASH you see above short circuits the check against the previous policy and the VERSION must be higher than the last update (though can be 1 the first time you call it). The signature is the sticking point. The bundle (I’ll get to that in a bit) has to be signed by the update certificate. The update certificate is stored in the Settings provider, though, and with root we can update that (you need to add sqlite3 to your system partition to do this):
# cd /data/data/com.android.providers.settings/databases # sqlite3 settings.db "INSERT into secure (name, value) VALUES('config_update_certificate','<your public DER cert>');"
Once you’ve done that can you sign the bundle, put it on the system where services can read it (/cache works well) and call the intent. Viola.
Except not. After getting this to succeed (the certificate and signing stuff in here is really finicky) the policy was placed in /data/security/contexts with ‘current’ symlinked to it.. Strangely, none of the rest of the code appears to look there. Indeed the policy doesn’t appear to be loaded either when the Intent is called or at boot time. Doh!
Since this doesn’t currently work I didn’t see much value in posting code. I’ll keep it up to date and when I get a real released version I’ll post it if it works (or maybe if it doesn’t)
Enforcing mode is set with a global setting (selinux_status), and appears to be persistent, but since enforcing does not work it is not a good idea to set it.
So, Google made a new file format for bundling components of the policy, seapp_contexts, property_contexts, file_contexts, and the binary policy, in that order. Sadly mac_permissions.xml is not in the bundle, nor does there appear any way to update it.
The bundle is simple, 4 32-bit (big endian!) integers representing the size of the policy component and then the components, base64 encoded.
The signature isn’t a standard openssl signature but it can be created in Java, using the standard API’s:
Signature signer = Signature.getInstance("SHA512withRSA"); signer.initSign(privKey); signer.update(bundle); signer.update(Long.toString(version).getBytes()); signer.update(prevHash.getBytes()); byte  signature = signer.sign();
You’ll note that the signature includes the hash of the bundle itself, and also the version number and hash sent in the intent. This is likely to prevent downgrading by sending the intent with a lower version and different hash.
So, my high hopes were dashed (I didn’t really have high hopes… I’ve learned to have low expectations for these things).
Enforcing mode doesn’t work, auditing is still not present, the update API’s are non-functional and even if they were functional, they can only be used by the person with the update certificate, which is the vendor. Once again, we have a device that does not allow its owner to protect themselves using mandatory access control, nor change the policy to meet different use cases than the vendor expected. It is very unfortunate that the best technology available for protecting our mobile devices has been locked away from us.