Platform specific SecurityException, mostly on Android 7.0 Devices

1,105 views
Skip to first unread message

David Ozersky

unread,
May 8, 2017, 8:23:31 PM5/8/17
to android-platform
Hello, 

I'm developing a large scale messaging application, and have recently run into a various strange issue.  The issue is reproducible on multiple devices, on version 5+, but is about 80% prevalent on 7.0.  When trying to make a query to the Calendar content provider we get this security exception --> 

Permission Denial: checkContentProviderPermissionLocked com.android.calendar asks to run as user 0 but is calling from user 999; 
this requires android.permission.INTERACT_ACROSS_USERS_FULL or android.permission.INTERACT_ACROSS_USERS

After searching on Stack Overflow, I found that this message means that you are trying to access a resource which requires the client app to have the same permission signature as the resource.  In most cases this is for system.  Looking at the following code from ActivityManagerService -- --> 




boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
        cpi
.name, cpi.flags)
       
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
if (singleton) {
    userId
= UserHandle.USER_SYSTEM;
}
cpi
.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
checkTime
(startTime, "getContentProviderImpl: got app info for user");

String msg;
checkTime
(startTime, "getContentProviderImpl: before checkContentProviderPermission");
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
       
!= null) {
   
throw new SecurityException(msg);
}
checkTime
(startTime, "getContentProviderImpl: after checkContentProviderPermission");

.
.
.
.



/**
 * Check if {@link ProcessRecord} has a possible chance at accessing the
 * given {@link ProviderInfo}. Final permission checking is always done
 * in {@link ContentProvider}.
 */
private final String checkContentProviderPermissionLocked(
       
ProviderInfo cpi, ProcessRecord r, int userId, boolean checkUser) {
   
final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
   
final int callingUid = (r != null) ? r.uid : Binder.getCallingUid();
   
boolean checkedGrants = false;
   
if (checkUser) {
       
// Looking for cross-user grants before enforcing the typical cross-users permissions
        int tmpTargetUserId = mUserController.unsafeConvertIncomingUserLocked(userId);
       
if (tmpTargetUserId != UserHandle.getUserId(callingUid)) {
           
if (checkAuthorityGrants(callingUid, cpi, tmpTargetUserId, checkUser)) {
               
return null;
           
}
            checkedGrants
= true;
       
}
        userId
= mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
               
ALLOW_NON_FULL, "checkContentProviderPermissionLocked " + cpi.authority, null);
       
if (userId != tmpTargetUserId) {
           
// When we actually went to determine the final targer user ID, this ended
            // up different than our initial check for the authority.  This is because
            // they had asked for USER_CURRENT_OR_SELF and we ended up switching to
            // SELF.  So we need to re-check the grants again.
            checkedGrants = false;
       
}
   
}
   
if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
            cpi
.applicationInfo.uid, cpi.exported)
           
== PackageManager.PERMISSION_GRANTED) {
       
return null;
   
}
   
if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
            cpi
.applicationInfo.uid, cpi.exported)
           
== PackageManager.PERMISSION_GRANTED) {
       
return null;
   
}

   
PathPermission[] pps = cpi.pathPermissions;
   
if (pps != null) {
       
int i = pps.length;
       
while (i > 0) {
            i
--;
           
PathPermission pp = pps[i];
           
String pprperm = pp.getReadPermission();
           
if (pprperm != null && checkComponentPermission(pprperm, callingPid, callingUid,
                    cpi
.applicationInfo.uid, cpi.exported)
                   
== PackageManager.PERMISSION_GRANTED) {
               
return null;
           
}
           
String ppwperm = pp.getWritePermission();
           
if (ppwperm != null && checkComponentPermission(ppwperm, callingPid, callingUid,
                    cpi
.applicationInfo.uid, cpi.exported)
                   
== PackageManager.PERMISSION_GRANTED) {
               
return null;
           
}
       
}
   
}
   
if (!checkedGrants && checkAuthorityGrants(callingUid, cpi, userId, checkUser)) {
       
return null;
   
}

   
String msg;
   
if (!cpi.exported) {
        msg
= "Permission Denial: opening provider " + cpi.name
                + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
               
+ ", uid=" + callingUid + ") that is not exported from uid "
                + cpi.applicationInfo.uid;
   
} else {
        msg
= "Permission Denial: opening provider " + cpi.name
                + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
               
+ ", uid=" + callingUid + ") requires "
                + cpi.readPermission + " or " + cpi.writePermission;
   
}
   
Slog.w(TAG, msg);
   
return msg;
}


It looks like the issue is the calendar content provider for this device was not configured to accept requests from third party developers.  That is to say, only applications that are bundled with the OS will be able to access these resources.  

I see that WhatsApp has the same problem --> http://xiaomi.hk/thread-184449-1-0.html

What exactly is the significance of this exception in this context?  (I've made a post to Xiaomi directly, which I will add to this post once that post is approved.)

Thank you in advance!
David
Reply all
Reply to author
Forward
0 new messages