Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android custom permissions - Marshmallow

Background

Historically, Android Custom permissions have been a mess and were install order dependent, which was known to expose vulnerabilities.

Prior to API 21, there was an unsettling workaround whereby declaring the custom permission of another application in your Manifest, granted the permission... However, since API 21, only one application can declare a custom permission and the installation of a further application declaring this same permission, will be prevented.

The alternatives are to reinstall the application requiring the permission, so they are detected by the System, but that is not a good user experience. Or check at runtime for the permissions of the calling application, but that is not without its theoretical flaws.

Problem

As of Android Marshmallow (6.0 - API 23) an application needs to request permission from the user, to use its own custom permission. A declared custom permission is not automatically granted.

This seems peculiar, given that only one application can now declare it.

To replicate

Declare the custom permission and a BroadcastReceiver in the Manifest.

<permission
    android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"
    android:description="@string/control_description"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/control_label"
    android:protectionLevel="normal or dangerous"/>

<uses-permission
    android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>

// etc

<receiver
    android:name="com.example.app.MyBroadcastReceiver"
    android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">
    <intent-filter android:priority="999">
        <action android:name="com.example.app.REQUEST_RECEIVER"/>
    </intent-filter>
</receiver>

From a third-party application, declare that it uses the custom permission in the Manifest (and accept it via a dialog or the settings) and call:

    final Intent intent = new Intent("com.example.app.REQUEST_RECEIVER");

    context.sendOrderedBroadcast(intent, "com.example.app.permission.CONTROL_EXAMPLE_APP", new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, final Intent intent) {

        // getResultCode();

        }
    }, null, Activity.RESULT_CANCELED, null, null);

The result will return CANCELED and the log will show:

system_process W/BroadcastQueue: Permission Denial: receiving Intent { act=com.example.app.REQUEST_RECEIVER flg=0x10 (has extras) } to com.example.app/.MyBroadcastReceiver requires com.example.app.permission.CONTROL_EXAMPLE_APP due to sender com.example.thirdparty

If I use the standard ActivityCompat.requestPermissions() dialog to allow the user to accept the permission, the receiver, as you would expect, works correctly.

Question

Is this expected behaviour? Or have I somehow overlooked something?

It would seem ridiculous to raise a dialog saying

The application Example App wants permission to use Example App

And it may indeed concern the user, providing them with such a nonsensical request.

I can of course change the permission description and name, to something that they would accept, such as 'communicate with other installed applications', but before I sigh and take that approach, I thought I'd ask this question.

Note

The example of the ordered broadcast is to replicate the problem. My application does use other implementations of content providers and a bound service. It is not an alternative implementation I require, it's confirmation of the issue.

Thank you for reading this far.

Edit: To clarify, for other implementations, such as declaring a permmission on a Service (which would be most simple to replicate) the declared custom permission is automatically granted.

like image 252
brandall Avatar asked Jul 06 '16 21:07

brandall


People also ask

How do I set custom permissions in Android?

You can use the sharedUserId attribute in the AndroidManifest. xml 's manifest tag of each package to have them assigned the same user ID. By doing this, for purposes of security the two packages are then treated as being the same app, with the same user ID and file permissions.

How do I set custom permissions in Android dialog?

requestPermissions(thisActivity, new String[]{Manifest. permission. READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS); Android system creates a popup dialog to request permission.

How do I set permissions in Android programmatically?

You need to declare the permissions in the manifest file first before you request for them programmatically. refer this for more information. declaring the permission in the manifest file is static type declaration by which your os know what kind of permission your app might require.


1 Answers

As I understood you tried to do next thing (At least, that's how I was able to reproduce your problem):

  1. You declare your new custom permission in first (lets call it F) application

    <permission
        android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"
        android:description="@string/control_description"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/control_label"
        android:protectionLevel="normal or dangerous"/>
    
  2. You define that your F app uses com.example.app.permission.CONTROL_EXAMPLE_APP permission. That is right as the guideline says.

    <uses-permission
        android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>
    
  3. You declare your custom broadcast receiver in your F app. To communicate with that broadcast your app (it's no matter which one, F or other app) must obtain your custom permission

    <receiver
        android:name="com.example.app.MyBroadcastReceiver"
        android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">
        <intent-filter android:priority="999">
            <action android:name="com.example.app.REQUEST_RECEIVER"/>
        </intent-filter>
    </receiver>
    
  4. You define that you second (lets call it S) application uses com.example.app.permission.CONTROL_EXAMPLE_APP permission. Because you want to allow S app to send broadcast messages to F app receiver.

    <uses-permission
        android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>
    
  5. Finally you try to send broadcast message from your S app using this code.

    final Intent intent = new Intent("com.example.app.REQUEST_RECEIVER");
    context.sendOrderedBroadcast(intent, "com.example.app.permission.CONTROL_EXAMPLE_APP", new BroadcastReceiver() {
            @Override
            public void onReceive(final Context context, final Intent intent) {
                // getResultCode();
            }
        }, null, Activity.RESULT_CANCELED, null, null);
    

    And, this is important, you granted permission to your S app, but you didn't grant permission to your F app.

    As result your broadcast receiver declared in F app didn't receive anything.

  6. After you granted permission to your F app (Note that now S and F granted your custom permission) everything works fine. Broadcast receiver declared in F app received message from S app.

I guess that is correct behaviour, because this doc says us:

Note that, in this example, the DEBIT_ACCT permission is not only declared with the element, its use is also requested with the element. You must request its use in order for other components of the application to launch the protected activity, even though the protection is imposed by the application itself.

And app which declare permission also must request the same permission to communicate with itself.

As result, android API 23 should to get access to use your permission form user first. And we must to get 2 granted permissions, first from F app (because guidline says as that) and second from S app (because we just need to get access).

But I didn't catch your next point:

It would seem ridiculous to raise a dialog saying

The application Example App wants permission to use Example App

My native Android API 23 displays me something like that:

The application Example App wants

like image 59
Igor Tyulkanov Avatar answered Sep 25 '22 12:09

Igor Tyulkanov