By default, most platform developers set their apps to be signed with the
platform key by using LOCAL_CERTIFICATE := PLATFORM in make or certificate: platform in blueprints. All apps signed by the platform key get assigned the
platform_app SELinux label by default and have elevated privileges and access
to protected broadcasts and permissions.
That approach falls flat when using GSIs though, as the “platform” key is now
recognized to be the key used to sign the GSI, which might differ from the one
used to generated the /vendor parts.
A better approach is to generate separate keys for apps in the vendor image and get SELinux to recognize them.
Side note: This still leaves the issue unsolved at the framework level.
Android’s frameworks-base defines lots of permissions and broadcasts with the
protectionLevel=signature, which means only apps signed with the platform key
can utilize them. Very few permissions are set as signature|privileged, which
means they are not avilable by default, but can be granted through
privapp-permissions.xml, see Privileged Permissions Whitelisting.
This approach still only works for system applications though. For apps on
/vendor an additional vendorPrivileged clause in the protectionLevel is
needed, see for example the permission BIND_IMS_SERVICE, which is
vendor-accessible: AndroidManifest.xml.
Certs & Inclusion
./development/tools/make_key \
app_cert \
"/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com"
Generates app_cert.pk8 and app_cert.x509.pem
Include the cert:
android_app_certificate {
name: "ModemConfig_app_cert",
certificate: "app_cert",
}
android_app {
name: "ModemConfig",
// Change this:
//certificate: "platform",
// To this:
certificate: ":ModemConfig_app_cert",
// [...]
}
Exotic files
First, let SELinux recognize any signature by the app_cert key, as defined
by the public key file app_cert.x509.pem, as the signer value @MODEMCONFIG.
keys.conf:
[@MODEMCONFIG]
ALL : SonyOpenTelephony/ModemConfig/app_cert.x509.pem
The ALL statement is a shorthand for USER, USERDEBUG and ENG. You could
also define this certificate to only be valid for debugging.
MAC stands for Mandatory Access Control. This file translates recognized
signer values into seinfo values that sepolicy vectors can understand and use.
mac_permissions.xml:
<policy>
<signer signature="@MODEMCONFIG" >
<seinfo value="modemconfigapp" />
</signer>
</policy>
sepolicy
Now, onto the labeling. App SELinux context recognition has a different syntax
than e.g. file_contexts or service_contexts.
seapp_contexts:
user=_app seinfo=modemconfigapp name=com.sony.opentelephony.modemconfig isPrivApp=true domain=modemconfig_app type=app_data_file
Note: For seapp_contexts, the syntax is a bit confusing. user, seinfo,
name and isPrivApp are matching selectors. domain and type are
assignments.
Thus, the previous statement reads:
Match any app running under the
_appuser (e.g. not system user), with a signature that translates to themodemconfigappseinfovalue, with the namecom.sony.opentelephony.modemconfig, which is a privileged app.
Assign that app the
modemconfig_appdomain and for its data directory under/data/, use theapp_data_filelabel.
Now we can actually write policy for the application.
modemconfig_app.te:
type modemconfig_app, domain;
app_domain(modemconfig_app)
# [...]
For more information, see the AOSP sources: keys.conf, mac_permissions.xml, seapp_contexts, post_process_mac_perms.
Thanks Luk for the inspiration, see this commit and this gist.