Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0be33285 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge "DO NOT MERGE: Check provider access for content changes." into mnc-dr1.5-dev

parents cfa18212 956bc433
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -25,6 +25,11 @@ import android.content.ComponentName;
 * @hide Only for use within the system server.
 * @hide Only for use within the system server.
 */
 */
public abstract class ActivityManagerInternal {
public abstract class ActivityManagerInternal {
    /**
     * Verify that calling app has access to the given provider.
     */
    public abstract String checkContentProviderAccess(String authority, int userId);

    // Called by the power manager.
    // Called by the power manager.
    public abstract void onWakefulnessChanged(int wakefulness);
    public abstract void onWakefulnessChanged(int wakefulness);


+42 −0
Original line number Original line Diff line number Diff line
@@ -9314,6 +9314,43 @@ public final class ActivityManagerService extends ActivityManagerNative
        return providers;
        return providers;
    }
    }
    /**
     * Check if the calling UID has a possible chance at accessing the provider
     * at the given authority and user.
     */
    public String checkContentProviderAccess(String authority, int userId) {
        if (userId == UserHandle.USER_ALL) {
            mContext.enforceCallingOrSelfPermission(
                    Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
            userId = UserHandle.getCallingUserId();
        }
        ProviderInfo cpi = null;
        try {
            cpi = AppGlobals.getPackageManager().resolveContentProvider(authority,
                    STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
        } catch (RemoteException ignored) {
        }
        if (cpi == null) {
            // TODO: make this an outright failure in a future platform release;
            // until then anonymous content notifications are unprotected
            //return "Failed to find provider " + authority + " for user " + userId;
            return null;
        }
        ProcessRecord r = null;
        synchronized (mPidsSelfLocked) {
            r = mPidsSelfLocked.get(Binder.getCallingPid());
        }
        if (r == null) {
            return "Failed to find PID " + Binder.getCallingPid();
        }
        synchronized (this) {
            return checkContentProviderPermissionLocked(cpi, r, userId, true);
        }
    }
    /**
    /**
     * Check if {@link ProcessRecord} has a possible chance at accessing the
     * Check if {@link ProcessRecord} has a possible chance at accessing the
     * given {@link ProviderInfo}. Final permission checking is always done
     * given {@link ProviderInfo}. Final permission checking is always done
@@ -20659,6 +20696,11 @@ public final class ActivityManagerService extends ActivityManagerNative
    }
    }
    private final class LocalService extends ActivityManagerInternal {
    private final class LocalService extends ActivityManagerInternal {
        @Override
        public String checkContentProviderAccess(String authority, int userId) {
            return ActivityManagerService.this.checkContentProviderAccess(authority, userId);
        }
        @Override
        @Override
        public void onWakefulnessChanged(int wakefulness) {
        public void onWakefulnessChanged(int wakefulness) {
            ActivityManagerService.this.onWakefulnessChanged(wakefulness);
            ActivityManagerService.this.onWakefulnessChanged(wakefulness);
+48 −31
Original line number Original line Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.server.content;
import android.Manifest;
import android.Manifest;
import android.accounts.Account;
import android.accounts.Account;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerNative;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Context;
@@ -51,7 +53,6 @@ import com.android.server.LocalServices;


import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Collections;
import java.util.Comparator;
import java.util.Comparator;
@@ -190,23 +191,15 @@ public final class ContentService extends IContentService.Stub {


        final int uid = Binder.getCallingUid();
        final int uid = Binder.getCallingUid();
        final int pid = Binder.getCallingPid();
        final int pid = Binder.getCallingPid();
        final int callingUserHandle = UserHandle.getCallingUserId();
        // Registering an observer for any user other than the calling user requires uri grant or
        // cross user permission
        if (callingUserHandle != userHandle &&
                mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
                        != PackageManager.PERMISSION_GRANTED) {
            enforceCrossUserPermission(userHandle,
                    "no permission to observe other users' provider view");
        }


        if (userHandle < 0) {
        userHandle = handleIncomingUser(uri, pid, uid,
            if (userHandle == UserHandle.USER_CURRENT) {
                Intent.FLAG_GRANT_READ_URI_PERMISSION, userHandle);
                userHandle = ActivityManager.getCurrentUser();

            } else if (userHandle != UserHandle.USER_ALL) {
        final String msg = LocalServices.getService(ActivityManagerInternal.class)
                throw new InvalidParameterException("Bad user handle for registerContentObserver: "
                .checkContentProviderAccess(uri.getAuthority(), userHandle);
                        + userHandle);
        if (msg != null) {
            }
            Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg);
            return;
        }
        }


        synchronized (mRootNode) {
        synchronized (mRootNode) {
@@ -253,21 +246,15 @@ public final class ContentService extends IContentService.Stub {
        final int uid = Binder.getCallingUid();
        final int uid = Binder.getCallingUid();
        final int pid = Binder.getCallingPid();
        final int pid = Binder.getCallingPid();
        final int callingUserHandle = UserHandle.getCallingUserId();
        final int callingUserHandle = UserHandle.getCallingUserId();
        // Notify for any user other than the caller requires uri grant or cross user permission
        if (callingUserHandle != userHandle &&
                mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
                        != PackageManager.PERMISSION_GRANTED) {
            enforceCrossUserPermission(userHandle, "no permission to notify other users");
        }


        // We passed the permission check; resolve pseudouser targets as appropriate
        userHandle = handleIncomingUser(uri, pid, uid,
        if (userHandle < 0) {
                Intent.FLAG_GRANT_WRITE_URI_PERMISSION, userHandle);
            if (userHandle == UserHandle.USER_CURRENT) {

                userHandle = ActivityManager.getCurrentUser();
        final String msg = LocalServices.getService(ActivityManagerInternal.class)
            } else if (userHandle != UserHandle.USER_ALL) {
                .checkContentProviderAccess(uri.getAuthority(), userHandle);
                throw new InvalidParameterException("Bad user handle for notifyChange: "
        if (msg != null) {
                        + userHandle);
            Log.w(TAG, "Ignoring notify for " + uri + " from " + uid + ": " + msg);
            }
            return;
        }
        }


        // This makes it so that future permission checks will be in the context of this
        // This makes it so that future permission checks will be in the context of this
@@ -317,6 +304,15 @@ public final class ContentService extends IContentService.Stub {
        }
        }
    }
    }


    private int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, int userHandle) {
        try {
            return ActivityManagerNative.getDefault().checkUriPermission(
                    uri, pid, uid, modeFlags, userHandle, null);
        } catch (RemoteException e) {
            return PackageManager.PERMISSION_DENIED;
        }
    }

    public void notifyChange(Uri uri, IContentObserver observer,
    public void notifyChange(Uri uri, IContentObserver observer,
            boolean observerWantsSelfNotifications, boolean syncToNetwork) {
            boolean observerWantsSelfNotifications, boolean syncToNetwork) {
        notifyChange(uri, observer, observerWantsSelfNotifications, syncToNetwork,
        notifyChange(uri, observer, observerWantsSelfNotifications, syncToNetwork,
@@ -924,6 +920,27 @@ public final class ContentService extends IContentService.Stub {
        return service;
        return service;
    }
    }


    private int handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, int userId) {
        if (userId == UserHandle.USER_CURRENT) {
            userId = ActivityManager.getCurrentUser();
        }

        if (userId == UserHandle.USER_ALL) {
            mContext.enforceCallingOrSelfPermission(
                    Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
        } else if (userId < 0) {
            throw new IllegalArgumentException("Invalid user: " + userId);
        } else if (userId != UserHandle.getCallingUserId()) {
            if (checkUriPermission(uri, pid, uid, modeFlags,
                    userId) != PackageManager.PERMISSION_GRANTED) {
                mContext.enforceCallingOrSelfPermission(
                        Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
            }
        }

        return userId;
    }

    /**
    /**
     * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL
     * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL
     * permission, if the userHandle is not for the caller.
     * permission, if the userHandle is not for the caller.