Signed App seapp_contexts

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 _app user (e.g. not system user), with a signature that translates to the modemconfigapp seinfo value, with the name com.sony.opentelephony.modemconfig, which is a privileged app.

Assign that app the modemconfig_app domain and for its data directory under /data/, use the app_data_file label.

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.

Published by

Edit source on Github