From 647cb6a6d82e3bb22eca0e5a27810e99084e2d5b Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Fri, 20 May 2016 15:29:31 -0700 Subject: [PATCH] DO NOT MERGE : backport of backup transport whitelist Sysconfig define a whitelist of permitted backup transports Previously any apk bundled in priv-app could insert a backup transport. Reduce risk surface by giving the OEM explicit control over who is allowed to handle backup data. Bug 28406080 Backport of 494df791728f4d42d67e935c327910975993ad29 from N Change-Id: I405b49daee8c576584575c3e46877cc97632d8c6 --- .../server/backup/BackupManagerService.java | 31 +++++++++++++++---- .../java/com/android/server/SystemConfig.java | 28 +++++++++++++++++ 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index fea1a7ae6829f..dc4b89f1f3413 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -79,7 +79,9 @@ import android.os.storage.StorageManager; import android.provider.Settings; import android.system.ErrnoException; import android.system.Os; +import android.text.TextUtils; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.AtomicFile; import android.util.EventLog; import android.util.Log; @@ -91,6 +93,7 @@ import com.android.internal.backup.IBackupTransport; import com.android.internal.backup.IObbBackupService; import com.android.server.AppWidgetBackupBridge; import com.android.server.EventLogTags; +import com.android.server.SystemConfig; import com.android.server.SystemService; import com.android.server.backup.PackageManagerBackupAgent.Metadata; @@ -309,6 +312,7 @@ public class BackupManagerService extends IBackupManager.Stub { volatile boolean mClearingData; // Transport bookkeeping + final ArraySet mTransportWhitelist; final Intent mTransportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST); final ArrayMap mTransportNames = new ArrayMap(); // component name -> registration name @@ -1058,11 +1062,15 @@ public class BackupManagerService extends IBackupManager.Stub { // Set up our transport options and initialize the default transport // TODO: Don't create transports that we don't need to? - mCurrentTransport = Settings.Secure.getString(context.getContentResolver(), + SystemConfig systemConfig = SystemConfig.getInstance(); + mTransportWhitelist = systemConfig.getBackupTransportWhitelist(); + + String transport = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT); - if ("".equals(mCurrentTransport)) { - mCurrentTransport = null; + if (TextUtils.isEmpty(transport)) { + transport = null; } + mCurrentTransport = transport; if (DEBUG) Slog.v(TAG, "Starting with transport " + mCurrentTransport); // Find all transport hosts and bind to their services @@ -1073,11 +1081,11 @@ public class BackupManagerService extends IBackupManager.Stub { } if (hosts != null) { for (int i = 0; i < hosts.size(); i++) { - final ServiceInfo transport = hosts.get(i).serviceInfo; + final ServiceInfo transportService = hosts.get(i).serviceInfo; if (MORE_DEBUG) { - Slog.v(TAG, " " + transport.packageName + "/" + transport.name); + Slog.v(TAG, " " + transportService.packageName + "/" + transportService.name); } - tryBindTransport(transport); + tryBindTransport(transportService); } } @@ -1869,6 +1877,11 @@ public class BackupManagerService extends IBackupManager.Stub { // Actually bind; presumes that we have already validated the transport service boolean bindTransport(ServiceInfo transport) { ComponentName svcName = new ComponentName(transport.packageName, transport.name); + if (!mTransportWhitelist.contains(svcName)) { + Slog.w(TAG, "Proposed transport " + svcName + " not whitelisted; ignoring"); + return false; + } + if (DEBUG) { Slog.i(TAG, "Binding to transport host " + svcName); } @@ -9193,6 +9206,12 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF + " (now = " + System.currentTimeMillis() + ')'); pw.println(" next scheduled: " + mNextBackupPass); + pw.println("Transport whitelist:"); + for (ComponentName transport : mTransportWhitelist) { + pw.print(" "); + pw.println(transport.flattenToShortString()); + } + pw.println("Available transports:"); final String[] transports = listAllTransports(); if (transports != null) { diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java index cf2a49f922e2f..a4199877a1b03 100644 --- a/services/core/java/com/android/server/SystemConfig.java +++ b/services/core/java/com/android/server/SystemConfig.java @@ -16,6 +16,7 @@ package com.android.server; +import android.content.ComponentName; import android.content.pm.FeatureInfo; import android.os.*; import android.os.Process; @@ -24,7 +25,9 @@ import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; import android.util.Xml; + import com.android.internal.util.XmlUtils; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -81,6 +84,9 @@ public class SystemConfig { // These are the app package names that should not allow IME switching. final ArraySet mFixedImeApps = new ArraySet<>(); + // These are the permitted backup transport service components + final ArraySet mBackupTransportWhitelist = new ArraySet<>(); + public static SystemConfig getInstance() { synchronized (SystemConfig.class) { if (sInstance == null) { @@ -118,6 +124,10 @@ public class SystemConfig { return mFixedImeApps; } + public ArraySet getBackupTransportWhitelist() { + return mBackupTransportWhitelist; + } + SystemConfig() { // Read configuration from system readPermissions(Environment.buildPath( @@ -312,6 +322,24 @@ public class SystemConfig { XmlUtils.skipCurrentTag(parser); continue; + } else if ("backup-transport-whitelisted-service".equals(name)) { + String serviceName = parser.getAttributeValue(null, "service"); + if (serviceName == null) { + Slog.w(TAG, " without service in " + + permFile + " at " + parser.getPositionDescription()); + } else { + ComponentName cn = ComponentName.unflattenFromString(serviceName); + if (cn == null) { + Slog.w(TAG, + " with invalid service name " + + serviceName + " in "+ permFile + + " at " + parser.getPositionDescription()); + } else { + mBackupTransportWhitelist.add(cn); + } + } + XmlUtils.skipCurrentTag(parser); + } else { XmlUtils.skipCurrentTag(parser); continue;