Loading media/java/android/media/flags/projection.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -64,3 +64,13 @@ flag { purpose: PURPOSE_BUGFIX } } flag { namespace: "media_projection" name: "start_uid_check" description: "Improves permission model when starting MediaProjection session" bug: "419269649" metadata { purpose: PURPOSE_BUGFIX } } services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java +33 −0 Original line number Diff line number Diff line Loading @@ -734,6 +734,35 @@ public final class MediaProjectionManagerService extends SystemService } } /** * Verifies whether the calling package name matches the calling app uid. * * @param context the context * @param callingPackage the calling application package name * @return {@code true} if the package name matches {@link Binder#getCallingUid()}, or * {@code false} otherwise */ private static boolean validateCallingPackageName(Context context, String callingPackage) { final int callingUid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { int packageUid = context.getPackageManager() .getPackageUidAsUser(callingPackage, UserHandle.getUserId(callingUid)); if (packageUid != callingUid) { Slog.e(TAG, "validatePackageName: App with package name " + callingPackage + " is UID " + packageUid + " but caller is " + callingUid); return false; } } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "validatePackageName: App with package name " + callingPackage + " does not exist"); return false; } finally { Binder.restoreCallingIdentity(token); } return true; } private void dump(final PrintWriter pw) { pw.println("MEDIA PROJECTION MANAGER (dumpsys media_projection)"); synchronized (mLock) { Loading Loading @@ -1189,6 +1218,10 @@ public final class MediaProjectionManagerService extends SystemService mCountStarts++; return; } if (Flags.startUidCheck() && validateCallingPackageName(mContext, packageName)) { throw new SecurityException( "This MediaProjection session was not granted to this application."); } if (REQUIRE_FG_SERVICE_FOR_PROJECTION && requiresForegroundService() && !hasFGS) { Loading services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java +23 −1 Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ import android.media.projection.StopReason; import android.os.Binder; import android.os.IBinder; import android.os.Looper; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.os.test.TestLooper; Loading Loading @@ -123,7 +124,7 @@ import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @SuppressLint({"UseCheckPermission", "VisibleForTests", "MissingPermission"}) public class MediaProjectionManagerServiceTest { private static final int UID = 10; private static final int UID = Process.myUid(); private static final String PACKAGE_NAME = "test.package"; private final ApplicationInfo mAppInfo = new ApplicationInfo(); private final PackageInfo mPackageInfo = new PackageInfo(); Loading Loading @@ -1347,6 +1348,27 @@ public class MediaProjectionManagerServiceTest { eq(projection.uid), anyInt()); } @Test @EnableFlags(Flags.FLAG_START_UID_CHECK) public void createProjection_cannotBeStartedFromDifferentUid() throws Exception { doReturn(mAppInfo).when(mPackageManager).getApplicationInfoAsUser(anyString(), any(ApplicationInfoFlags.class), any(UserHandle.class)); doReturn(mPackageInfo).when(mPackageManager).getPackageInfoAsUser(anyString(), anyInt(), anyInt()); int uid = 10; MediaProjectionManagerService.MediaProjection projection = mService.createProjectionInternal( uid, PACKAGE_NAME, TYPE_SCREEN_CAPTURE, /* isPermanentGrant= */ false, UserHandle.CURRENT, DEFAULT_DISPLAY); // Start MediaProjection from a different UID assertThrows(SecurityException.class, () -> projection.start(mIMediaProjectionCallback)); } private void verifySetSessionWithContent(@RecordContent int content) { verify(mWindowManagerInternal, atLeastOnce()).setContentRecordingSession( mSessionCaptor.capture()); Loading Loading
media/java/android/media/flags/projection.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -64,3 +64,13 @@ flag { purpose: PURPOSE_BUGFIX } } flag { namespace: "media_projection" name: "start_uid_check" description: "Improves permission model when starting MediaProjection session" bug: "419269649" metadata { purpose: PURPOSE_BUGFIX } }
services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java +33 −0 Original line number Diff line number Diff line Loading @@ -734,6 +734,35 @@ public final class MediaProjectionManagerService extends SystemService } } /** * Verifies whether the calling package name matches the calling app uid. * * @param context the context * @param callingPackage the calling application package name * @return {@code true} if the package name matches {@link Binder#getCallingUid()}, or * {@code false} otherwise */ private static boolean validateCallingPackageName(Context context, String callingPackage) { final int callingUid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { int packageUid = context.getPackageManager() .getPackageUidAsUser(callingPackage, UserHandle.getUserId(callingUid)); if (packageUid != callingUid) { Slog.e(TAG, "validatePackageName: App with package name " + callingPackage + " is UID " + packageUid + " but caller is " + callingUid); return false; } } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "validatePackageName: App with package name " + callingPackage + " does not exist"); return false; } finally { Binder.restoreCallingIdentity(token); } return true; } private void dump(final PrintWriter pw) { pw.println("MEDIA PROJECTION MANAGER (dumpsys media_projection)"); synchronized (mLock) { Loading Loading @@ -1189,6 +1218,10 @@ public final class MediaProjectionManagerService extends SystemService mCountStarts++; return; } if (Flags.startUidCheck() && validateCallingPackageName(mContext, packageName)) { throw new SecurityException( "This MediaProjection session was not granted to this application."); } if (REQUIRE_FG_SERVICE_FOR_PROJECTION && requiresForegroundService() && !hasFGS) { Loading
services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java +23 −1 Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ import android.media.projection.StopReason; import android.os.Binder; import android.os.IBinder; import android.os.Looper; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.os.test.TestLooper; Loading Loading @@ -123,7 +124,7 @@ import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @SuppressLint({"UseCheckPermission", "VisibleForTests", "MissingPermission"}) public class MediaProjectionManagerServiceTest { private static final int UID = 10; private static final int UID = Process.myUid(); private static final String PACKAGE_NAME = "test.package"; private final ApplicationInfo mAppInfo = new ApplicationInfo(); private final PackageInfo mPackageInfo = new PackageInfo(); Loading Loading @@ -1347,6 +1348,27 @@ public class MediaProjectionManagerServiceTest { eq(projection.uid), anyInt()); } @Test @EnableFlags(Flags.FLAG_START_UID_CHECK) public void createProjection_cannotBeStartedFromDifferentUid() throws Exception { doReturn(mAppInfo).when(mPackageManager).getApplicationInfoAsUser(anyString(), any(ApplicationInfoFlags.class), any(UserHandle.class)); doReturn(mPackageInfo).when(mPackageManager).getPackageInfoAsUser(anyString(), anyInt(), anyInt()); int uid = 10; MediaProjectionManagerService.MediaProjection projection = mService.createProjectionInternal( uid, PACKAGE_NAME, TYPE_SCREEN_CAPTURE, /* isPermanentGrant= */ false, UserHandle.CURRENT, DEFAULT_DISPLAY); // Start MediaProjection from a different UID assertThrows(SecurityException.class, () -> projection.start(mIMediaProjectionCallback)); } private void verifySetSessionWithContent(@RecordContent int content) { verify(mWindowManagerInternal, atLeastOnce()).setContentRecordingSession( mSessionCaptor.capture()); Loading