frameworks/base
Revision | c6fd63a7a80f06a89b34aa1894694922c3af9f20 (tree) |
---|---|
Time | 2020-03-13 05:34:25 |
Author | Christopher Tate <ctate@goog...> |
Commiter | Anis Assi |
DO NOT MERGE - Kill apps outright for API contract violations
...rather than relying on in-app code to perform the shutdown.
Backport of security fix.
Bug: 128649910
Bug: 140108616
Test: manual
Test: atest OsHostTests#testForegroundServiceBadNotification
Change-Id: I94d9de50bb03c33666471e3dbd9c721e9278f7cb
Merged-In: I94d9de50bb03c33666471e3dbd9c721e9278f7cb
(cherry picked from commit 874c974f73839da761177a4e0a53b7f4a7d29288)
@@ -266,7 +266,8 @@ interface IActivityManager { | ||
266 | 266 | boolean isImmersive(in IBinder token); |
267 | 267 | void setImmersive(in IBinder token, boolean immersive); |
268 | 268 | boolean isTopActivityImmersive(); |
269 | - void crashApplication(int uid, int initialPid, in String packageName, int userId, in String message); | |
269 | + void crashApplication(int uid, int initialPid, in String packageName, int userId, | |
270 | + in String message, boolean force); | |
270 | 271 | String getProviderMimeType(in Uri uri, int userId); |
271 | 272 | IBinder newUriPermissionOwner(in String name); |
272 | 273 | void grantUriPermissionFromOwner(in IBinder owner, int fromUid, in String targetPkg, |
@@ -653,6 +653,15 @@ public final class ActiveServices { | ||
653 | 653 | } |
654 | 654 | } |
655 | 655 | |
656 | + void killMisbehavingService(ServiceRecord r, | |
657 | + int appUid, int appPid, String localPackageName) { | |
658 | + synchronized (mAm) { | |
659 | + stopServiceLocked(r); | |
660 | + mAm.crashApplication(appUid, appPid, localPackageName, -1, | |
661 | + "Bad notification for startForeground", true /*force*/); | |
662 | + } | |
663 | + } | |
664 | + | |
656 | 665 | IBinder peekServiceLocked(Intent service, String resolvedType, String callingPackage) { |
657 | 666 | ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, callingPackage, |
658 | 667 | Binder.getCallingPid(), Binder.getCallingUid(), |
@@ -3391,7 +3400,8 @@ public final class ActiveServices { | ||
3391 | 3400 | |
3392 | 3401 | void serviceForegroundCrash(ProcessRecord app) { |
3393 | 3402 | mAm.crashApplication(app.uid, app.pid, app.info.packageName, app.userId, |
3394 | - "Context.startForegroundService() did not then call Service.startForeground()"); | |
3403 | + "Context.startForegroundService() did not then call Service.startForeground()", | |
3404 | + false /*force*/); | |
3395 | 3405 | } |
3396 | 3406 | |
3397 | 3407 | void scheduleServiceTimeoutLocked(ProcessRecord proc) { |
@@ -5141,7 +5141,7 @@ public class ActivityManagerService extends IActivityManager.Stub | ||
5141 | 5141 | |
5142 | 5142 | @Override |
5143 | 5143 | public void crashApplication(int uid, int initialPid, String packageName, int userId, |
5144 | - String message) { | |
5144 | + String message, boolean force) { | |
5145 | 5145 | if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) |
5146 | 5146 | != PackageManager.PERMISSION_GRANTED) { |
5147 | 5147 | String msg = "Permission Denial: crashApplication() from pid=" |
@@ -5153,7 +5153,8 @@ public class ActivityManagerService extends IActivityManager.Stub | ||
5153 | 5153 | } |
5154 | 5154 | |
5155 | 5155 | synchronized(this) { |
5156 | - mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId, message); | |
5156 | + mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId, | |
5157 | + message, force); | |
5157 | 5158 | } |
5158 | 5159 | } |
5159 | 5160 |
@@ -921,7 +921,7 @@ final class ActivityManagerShellCommand extends ShellCommand { | ||
921 | 921 | } catch (NumberFormatException e) { |
922 | 922 | packageName = arg; |
923 | 923 | } |
924 | - mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash"); | |
924 | + mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash", false); | |
925 | 925 | return 0; |
926 | 926 | } |
927 | 927 |
@@ -243,20 +243,24 @@ class AppErrors { | ||
243 | 243 | } |
244 | 244 | |
245 | 245 | void killAppAtUserRequestLocked(ProcessRecord app, Dialog fromDialog) { |
246 | - app.crashing = false; | |
247 | - app.crashingReport = null; | |
248 | - app.notResponding = false; | |
249 | - app.notRespondingReport = null; | |
250 | 246 | if (app.anrDialog == fromDialog) { |
251 | 247 | app.anrDialog = null; |
252 | 248 | } |
253 | 249 | if (app.waitDialog == fromDialog) { |
254 | 250 | app.waitDialog = null; |
255 | 251 | } |
252 | + killAppImmediateLocked(app, "user-terminated", "user request after error"); | |
253 | + } | |
254 | + | |
255 | + private void killAppImmediateLocked(ProcessRecord app, String reason, String killReason) { | |
256 | + app.crashing = false; | |
257 | + app.crashingReport = null; | |
258 | + app.notResponding = false; | |
259 | + app.notRespondingReport = null; | |
256 | 260 | if (app.pid > 0 && app.pid != MY_PID) { |
257 | - handleAppCrashLocked(app, "user-terminated" /*reason*/, | |
261 | + handleAppCrashLocked(app, reason, | |
258 | 262 | null /*shortMsg*/, null /*longMsg*/, null /*stackTrace*/, null /*data*/); |
259 | - app.kill("user request after error", true); | |
263 | + app.kill(killReason, true); | |
260 | 264 | } |
261 | 265 | } |
262 | 266 |
@@ -270,7 +274,7 @@ class AppErrors { | ||
270 | 274 | * @param message |
271 | 275 | */ |
272 | 276 | void scheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId, |
273 | - String message) { | |
277 | + String message, boolean force) { | |
274 | 278 | ProcessRecord proc = null; |
275 | 279 | |
276 | 280 | // Figure out which process to kill. We don't trust that initialPid |
@@ -303,6 +307,14 @@ class AppErrors { | ||
303 | 307 | } |
304 | 308 | |
305 | 309 | proc.scheduleCrash(message); |
310 | + if (force) { | |
311 | + // If the app is responsive, the scheduled crash will happen as expected | |
312 | + // and then the delayed summary kill will be a no-op. | |
313 | + final ProcessRecord p = proc; | |
314 | + mService.mHandler.postDelayed( | |
315 | + () -> killAppImmediateLocked(p, "forced", "killed for invalid state"), | |
316 | + 5000L); | |
317 | + } | |
306 | 318 | } |
307 | 319 | |
308 | 320 | /** |
@@ -453,6 +453,7 @@ final class ServiceRecord extends Binder { | ||
453 | 453 | final String localPackageName = packageName; |
454 | 454 | final int localForegroundId = foregroundId; |
455 | 455 | final Notification _foregroundNoti = foregroundNoti; |
456 | + final ServiceRecord record = this; | |
456 | 457 | ams.mHandler.post(new Runnable() { |
457 | 458 | public void run() { |
458 | 459 | NotificationManagerInternal nm = LocalServices.getService( |
@@ -551,10 +552,8 @@ final class ServiceRecord extends Binder { | ||
551 | 552 | Slog.w(TAG, "Error showing notification for service", e); |
552 | 553 | // If it gave us a garbage notification, it doesn't |
553 | 554 | // get to be foreground. |
554 | - ams.setServiceForeground(name, ServiceRecord.this, | |
555 | - 0, null, 0); | |
556 | - ams.crashApplication(appUid, appPid, localPackageName, -1, | |
557 | - "Bad notification for startForeground: " + e); | |
555 | + ams.mServices.killMisbehavingService(record, | |
556 | + appUid, appPid, localPackageName); | |
558 | 557 | } |
559 | 558 | } |
560 | 559 | }); |
@@ -714,18 +714,23 @@ public class NotificationManagerService extends SystemService { | ||
714 | 714 | @Override |
715 | 715 | public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, |
716 | 716 | int uid, int initialPid, String message, int userId) { |
717 | - Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id | |
718 | - + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")"); | |
717 | + final boolean fgService; | |
718 | + synchronized (mNotificationLock) { | |
719 | + NotificationRecord r = findNotificationLocked(pkg, tag, id, userId); | |
720 | + fgService = r != null | |
721 | + && (r.getNotification().flags&Notification.FLAG_FOREGROUND_SERVICE) != 0; | |
722 | + } | |
719 | 723 | cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, |
720 | 724 | REASON_ERROR, null); |
721 | - long ident = Binder.clearCallingIdentity(); | |
722 | - try { | |
723 | - ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1, | |
724 | - "Bad notification posted from package " + pkg | |
725 | - + ": " + message); | |
726 | - } catch (RemoteException e) { | |
725 | + if (fgService) { | |
726 | + // Still crash for foreground services, preventing the not-crash behaviour abused | |
727 | + // by apps to give us a garbage notification and silently start a fg service. | |
728 | + Binder.withCleanCallingIdentity( | |
729 | + () -> mAm.crashApplication(uid, initialPid, pkg, -1, | |
730 | + "Bad notification(tag=" + tag + ", id=" + id + ") posted from package " | |
731 | + + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): " | |
732 | + + message, true /* force */)); | |
727 | 733 | } |
728 | - Binder.restoreCallingIdentity(ident); | |
729 | 734 | } |
730 | 735 | |
731 | 736 | @Override |