1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.sdksandbox; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.content.Context; 22 import android.provider.DeviceConfig; 23 import android.text.TextUtils; 24 import android.util.ArrayMap; 25 import android.util.ArraySet; 26 import android.util.Base64; 27 import android.util.Log; 28 29 import com.android.internal.annotations.GuardedBy; 30 import com.android.internal.annotations.VisibleForTesting; 31 import com.android.server.sdksandbox.proto.Activity.ActivityAllowlists; 32 import com.android.server.sdksandbox.proto.Activity.AllowedActivities; 33 import com.android.server.sdksandbox.proto.BroadcastReceiver.AllowedBroadcastReceivers; 34 import com.android.server.sdksandbox.proto.BroadcastReceiver.BroadcastReceiverAllowlists; 35 import com.android.server.sdksandbox.proto.ContentProvider.AllowedContentProviders; 36 import com.android.server.sdksandbox.proto.ContentProvider.ContentProviderAllowlists; 37 import com.android.server.sdksandbox.proto.Services.AllowedServices; 38 import com.android.server.sdksandbox.proto.Services.ServiceAllowlists; 39 40 import com.google.protobuf.Parser; 41 42 import java.util.Map; 43 import java.util.Objects; 44 45 class SdkSandboxSettingsListener implements DeviceConfig.OnPropertiesChangedListener { 46 47 private static final String TAG = "SdkSandboxManager"; 48 private static final String PROPERTY_DISABLE_SDK_SANDBOX = "disable_sdk_sandbox"; 49 private static final boolean DEFAULT_VALUE_DISABLE_SDK_SANDBOX = true; 50 51 // Prefix all the keys with sdksandbox_ as the namespace is shared with PPAPI 52 /** 53 * Property to enforce restrictions for SDK sandbox processes. If the value of this property is 54 * {@code true}, the restrictions will be enforced. 55 */ 56 private static final String PROPERTY_ENFORCE_RESTRICTIONS = "sdksandbox_enforce_restrictions"; 57 58 private static final boolean DEFAULT_VALUE_ENFORCE_RESTRICTIONS = true; 59 60 /** We need to keep in sync with the property used in ProcessList */ 61 private static final String PROPERTY_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS = 62 "apply_sdk_sandbox_next_restrictions"; 63 64 private static final boolean DEFAULT_VALUE_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS = false; 65 66 private static final String PROPERTY_BROADCASTRECEIVER_ALLOWLIST = 67 "sdksandbox_broadcastreceiver_allowlist_per_targetSdkVersion"; 68 69 // Property for the canary set allowlist indicating which broadcast receivers can be registered 70 // by the sandbox. 71 private static final String PROPERTY_NEXT_BROADCASTRECEIVER_ALLOWLIST = 72 "sdksandbox_next_broadcastreceiver_allowlist"; 73 74 private static final String PROPERTY_CONTENTPROVIDER_ALLOWLIST = 75 "contentprovider_allowlist_per_targetSdkVersion"; 76 77 // Property indicating the ContentProvider canary allowlist. 78 private static final String PROPERTY_NEXT_CONTENTPROVIDER_ALLOWLIST = 79 "sdksandbox_next_contentprovider_allowlist"; 80 81 private static final String PROPERTY_SERVICES_ALLOWLIST = 82 "services_allowlist_per_targetSdkVersion"; 83 84 // Property for canary set for service restrictions 85 private static final String PROPERTY_NEXT_SERVICE_ALLOWLIST = 86 "sdksandbox_next_service_allowlist"; 87 88 private static final String PROPERTY_ACTIVITY_ALLOWLIST = 89 "sdksandbox_activity_allowlist_per_targetSdkVersion"; 90 private static final String PROPERTY_NEXT_ACTIVITY_ALLOWLIST = 91 "sdksandbox_next_activity_allowlist"; 92 private final Context mContext; 93 private final Object mLock = new Object(); 94 private final SdkSandboxManagerService mSdkSandboxManagerService; 95 96 @GuardedBy("mLock") 97 private boolean mKillSwitchEnabled = 98 DeviceConfig.getBoolean( 99 DeviceConfig.NAMESPACE_ADSERVICES, 100 PROPERTY_DISABLE_SDK_SANDBOX, 101 DEFAULT_VALUE_DISABLE_SDK_SANDBOX); 102 103 @GuardedBy("mLock") 104 private boolean mEnforceRestrictions = 105 DeviceConfig.getBoolean( 106 DeviceConfig.NAMESPACE_ADSERVICES, 107 PROPERTY_ENFORCE_RESTRICTIONS, 108 DEFAULT_VALUE_ENFORCE_RESTRICTIONS); 109 110 @GuardedBy("mLock") 111 private boolean mSdkSandboxApplyRestrictionsNext = 112 DeviceConfig.getBoolean( 113 DeviceConfig.NAMESPACE_ADSERVICES, 114 PROPERTY_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS, 115 DEFAULT_VALUE_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS); 116 117 @GuardedBy("mLock") 118 private Map<Integer, AllowedServices> mServiceAllowlistPerTargetSdkVersion = 119 getServicesAllowlist( 120 DeviceConfig.getProperty( 121 DeviceConfig.NAMESPACE_ADSERVICES, PROPERTY_SERVICES_ALLOWLIST)); 122 123 @GuardedBy("mLock") 124 private AllowedServices mNextServiceAllowlist = 125 getNextServiceDeviceConfigAllowlist( 126 DeviceConfig.getProperty( 127 DeviceConfig.NAMESPACE_ADSERVICES, PROPERTY_NEXT_SERVICE_ALLOWLIST)); 128 129 @GuardedBy("mLock") 130 private ArrayMap<Integer, ArraySet<String>> mContentProviderAllowlistPerTargetSdkVersion = 131 getContentProviderDeviceConfigAllowlist( 132 DeviceConfig.getProperty( 133 DeviceConfig.NAMESPACE_ADSERVICES, PROPERTY_CONTENTPROVIDER_ALLOWLIST)); 134 135 @GuardedBy("mLock") 136 private ArraySet<String> mNextContentProviderAllowlist = 137 getNextContentProviderDeviceConfigAllowlist( 138 DeviceConfig.getProperty( 139 DeviceConfig.NAMESPACE_ADSERVICES, 140 PROPERTY_NEXT_CONTENTPROVIDER_ALLOWLIST)); 141 142 @Nullable 143 @GuardedBy("mLock") 144 private ArrayMap<Integer, ArraySet<String>> mBroadcastReceiverAllowlistPerTargetSdkVersion = 145 getBroadcastReceiverDeviceConfigAllowlist( 146 DeviceConfig.getProperty( 147 DeviceConfig.NAMESPACE_ADSERVICES, 148 PROPERTY_BROADCASTRECEIVER_ALLOWLIST)); 149 150 @GuardedBy("mLock") 151 private ArraySet<String> mNextBroadcastReceiverAllowlist = 152 getNextBroadcastReceiverDeviceConfigAllowlist( 153 DeviceConfig.getProperty( 154 DeviceConfig.NAMESPACE_ADSERVICES, 155 PROPERTY_NEXT_BROADCASTRECEIVER_ALLOWLIST)); 156 157 @Nullable 158 @GuardedBy("mLock") 159 private ArrayMap<Integer, ArraySet<String>> mActivityAllowlistPerTargetSdkVersion = 160 getActivityDeviceConfigAllowlist( 161 DeviceConfig.getProperty( 162 DeviceConfig.NAMESPACE_ADSERVICES, PROPERTY_ACTIVITY_ALLOWLIST)); 163 164 @Nullable 165 @GuardedBy("mLock") 166 private ArraySet<String> mNextActivityAllowlist = 167 getNextActivityDeviceConfigAllowlist( 168 DeviceConfig.getProperty( 169 DeviceConfig.NAMESPACE_ADSERVICES, PROPERTY_NEXT_ACTIVITY_ALLOWLIST)); 170 SdkSandboxSettingsListener(Context context, SdkSandboxManagerService sdkSandboxManagerService)171 SdkSandboxSettingsListener(Context context, SdkSandboxManagerService sdkSandboxManagerService) { 172 mContext = context; 173 mSdkSandboxManagerService = sdkSandboxManagerService; 174 DeviceConfig.addOnPropertiesChangedListener( 175 DeviceConfig.NAMESPACE_ADSERVICES, mContext.getMainExecutor(), this); 176 } 177 178 @Override onPropertiesChanged(@onNull DeviceConfig.Properties properties)179 public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { 180 synchronized (mLock) { 181 if (!properties.getNamespace().equals(DeviceConfig.NAMESPACE_ADSERVICES)) { 182 return; 183 } 184 for (String name : properties.getKeyset()) { 185 if (name == null) { 186 continue; 187 } 188 189 switch (name) { 190 case PROPERTY_DISABLE_SDK_SANDBOX: 191 boolean killSwitchPreviouslyEnabled = mKillSwitchEnabled; 192 mKillSwitchEnabled = 193 properties.getBoolean( 194 PROPERTY_DISABLE_SDK_SANDBOX, 195 DEFAULT_VALUE_DISABLE_SDK_SANDBOX); 196 if (mKillSwitchEnabled && !killSwitchPreviouslyEnabled) { 197 Log.i(TAG, "SDK sandbox killswitch has become enabled"); 198 this.mSdkSandboxManagerService.stopAllSandboxes(); 199 } 200 break; 201 case PROPERTY_ENFORCE_RESTRICTIONS: 202 mEnforceRestrictions = 203 properties.getBoolean( 204 PROPERTY_ENFORCE_RESTRICTIONS, 205 DEFAULT_VALUE_ENFORCE_RESTRICTIONS); 206 break; 207 case PROPERTY_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS: 208 mSdkSandboxApplyRestrictionsNext = 209 properties.getBoolean( 210 PROPERTY_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS, 211 DEFAULT_VALUE_APPLY_SDK_SANDBOX_NEXT_RESTRICTIONS); 212 break; 213 case PROPERTY_SERVICES_ALLOWLIST: 214 mServiceAllowlistPerTargetSdkVersion = 215 getServicesAllowlist( 216 properties.getString(PROPERTY_SERVICES_ALLOWLIST, null)); 217 break; 218 case PROPERTY_NEXT_SERVICE_ALLOWLIST: 219 mNextServiceAllowlist = 220 getNextServiceDeviceConfigAllowlist( 221 properties.getString( 222 PROPERTY_NEXT_SERVICE_ALLOWLIST, null)); 223 break; 224 case PROPERTY_CONTENTPROVIDER_ALLOWLIST: 225 mContentProviderAllowlistPerTargetSdkVersion = 226 getContentProviderDeviceConfigAllowlist( 227 properties.getString( 228 PROPERTY_CONTENTPROVIDER_ALLOWLIST, null)); 229 break; 230 case PROPERTY_NEXT_CONTENTPROVIDER_ALLOWLIST: 231 mNextContentProviderAllowlist = 232 getNextContentProviderDeviceConfigAllowlist( 233 properties.getString( 234 PROPERTY_NEXT_CONTENTPROVIDER_ALLOWLIST, null)); 235 break; 236 case PROPERTY_BROADCASTRECEIVER_ALLOWLIST: 237 mBroadcastReceiverAllowlistPerTargetSdkVersion = 238 getBroadcastReceiverDeviceConfigAllowlist( 239 properties.getString( 240 PROPERTY_BROADCASTRECEIVER_ALLOWLIST, null)); 241 break; 242 case PROPERTY_NEXT_BROADCASTRECEIVER_ALLOWLIST: 243 mNextBroadcastReceiverAllowlist = 244 getNextBroadcastReceiverDeviceConfigAllowlist( 245 properties.getString( 246 PROPERTY_NEXT_BROADCASTRECEIVER_ALLOWLIST, null)); 247 break; 248 case PROPERTY_ACTIVITY_ALLOWLIST: 249 mActivityAllowlistPerTargetSdkVersion = 250 getActivityDeviceConfigAllowlist( 251 properties.getString(PROPERTY_ACTIVITY_ALLOWLIST, null)); 252 break; 253 case PROPERTY_NEXT_ACTIVITY_ALLOWLIST: 254 mNextActivityAllowlist = 255 getNextActivityDeviceConfigAllowlist( 256 properties.getString( 257 PROPERTY_NEXT_ACTIVITY_ALLOWLIST, null)); 258 break; 259 default: 260 } 261 } 262 } 263 } 264 isKillSwitchEnabled()265 public boolean isKillSwitchEnabled() { 266 synchronized (mLock) { 267 return mKillSwitchEnabled; 268 } 269 } 270 setKillSwitchState(boolean enabled)271 void setKillSwitchState(boolean enabled) { 272 synchronized (mLock) { 273 DeviceConfig.setProperty( 274 DeviceConfig.NAMESPACE_ADSERVICES, 275 PROPERTY_DISABLE_SDK_SANDBOX, 276 Boolean.toString(enabled), 277 false); 278 mKillSwitchEnabled = enabled; 279 } 280 } 281 282 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) unregisterPropertiesListener()283 void unregisterPropertiesListener() { 284 DeviceConfig.removeOnPropertiesChangedListener(this); 285 } 286 areRestrictionsEnforced()287 public boolean areRestrictionsEnforced() { 288 synchronized (mLock) { 289 return mEnforceRestrictions; 290 } 291 } 292 applySdkSandboxRestrictionsNext()293 public boolean applySdkSandboxRestrictionsNext() { 294 synchronized (mLock) { 295 return mSdkSandboxApplyRestrictionsNext; 296 } 297 } 298 getServiceAllowlistForTargetSdkVersion(int targetSdkVersion)299 public AllowedServices getServiceAllowlistForTargetSdkVersion(int targetSdkVersion) { 300 synchronized (mLock) { 301 return mServiceAllowlistPerTargetSdkVersion.get(targetSdkVersion); 302 } 303 } 304 getNextServiceAllowlist()305 public AllowedServices getNextServiceAllowlist() { 306 synchronized (mLock) { 307 return mNextServiceAllowlist; 308 } 309 } 310 getContentProviderAllowlistPerTargetSdkVersion()311 public ArrayMap<Integer, ArraySet<String>> getContentProviderAllowlistPerTargetSdkVersion() { 312 synchronized (mLock) { 313 return mContentProviderAllowlistPerTargetSdkVersion; 314 } 315 } 316 getNextContentProviderAllowlist()317 public ArraySet<String> getNextContentProviderAllowlist() { 318 synchronized (mLock) { 319 return mNextContentProviderAllowlist; 320 } 321 } 322 323 @Nullable getBroadcastReceiverAllowlistPerTargetSdkVersion()324 public ArrayMap<Integer, ArraySet<String>> getBroadcastReceiverAllowlistPerTargetSdkVersion() { 325 synchronized (mLock) { 326 return mBroadcastReceiverAllowlistPerTargetSdkVersion; 327 } 328 } 329 330 @Nullable getNextBroadcastReceiverAllowlist()331 public ArraySet<String> getNextBroadcastReceiverAllowlist() { 332 synchronized (mLock) { 333 return mNextBroadcastReceiverAllowlist; 334 } 335 } 336 337 @Nullable getActivityAllowlistPerTargetSdkVersion()338 public ArrayMap<Integer, ArraySet<String>> getActivityAllowlistPerTargetSdkVersion() { 339 synchronized (mLock) { 340 return mActivityAllowlistPerTargetSdkVersion; 341 } 342 } 343 344 @Nullable getNextActivityAllowlist()345 public ArraySet<String> getNextActivityAllowlist() { 346 synchronized (mLock) { 347 return mNextActivityAllowlist; 348 } 349 } 350 351 /** 352 * Helper function to decode a proto property 353 * 354 * @param property The property which needs to be decoded 355 * @param base64value The base64 value of the property 356 * @return The decoded value of the property passed as the parameter 357 */ getDecodedPropertyValue( @onNull String property, @NonNull String base64value)358 private static byte[] getDecodedPropertyValue( 359 @NonNull String property, @NonNull String base64value) { 360 try { 361 return Base64.decode(base64value, Base64.NO_PADDING | Base64.NO_WRAP); 362 } catch (IllegalArgumentException e) { 363 Log.e(TAG, "Error while decoding " + property + " Error: " + e); 364 } 365 return null; 366 } 367 368 @Nullable getDeviceConfigProtoProperty( Parser<T> parser, @NonNull String property, @Nullable String value)369 private static <T> T getDeviceConfigProtoProperty( 370 Parser<T> parser, @NonNull String property, @Nullable String value) { 371 if (TextUtils.isEmpty(value)) { 372 Log.d(TAG, "Property " + property + " is empty."); 373 return null; 374 } 375 final byte[] decode = getDecodedPropertyValue(property, value); 376 if (Objects.isNull(decode)) { 377 return null; 378 } 379 380 T proto = null; 381 try { 382 proto = parser.parseFrom(decode); 383 } catch (Exception e) { 384 Log.e(TAG, "Error while parsing " + property + ". Error: ", e); 385 } 386 387 return proto; 388 } 389 390 @NonNull getServicesAllowlist(@ullable String value)391 private static Map<Integer, AllowedServices> getServicesAllowlist(@Nullable String value) { 392 final ServiceAllowlists allowedServicesProto = 393 getDeviceConfigProtoProperty( 394 ServiceAllowlists.parser(), PROPERTY_SERVICES_ALLOWLIST, value); 395 return allowedServicesProto == null 396 ? new ArrayMap<>() 397 : allowedServicesProto.getAllowlistPerTargetSdkMap(); 398 } 399 400 @Nullable getNextServiceDeviceConfigAllowlist(@ullable String value)401 private AllowedServices getNextServiceDeviceConfigAllowlist(@Nullable String value) { 402 return getDeviceConfigProtoProperty( 403 AllowedServices.parser(), PROPERTY_NEXT_SERVICE_ALLOWLIST, value); 404 } 405 406 @NonNull getContentProviderDeviceConfigAllowlist( @ullable String value)407 private static ArrayMap<Integer, ArraySet<String>> getContentProviderDeviceConfigAllowlist( 408 @Nullable String value) { 409 ContentProviderAllowlists contentProviderAllowlistsProto = 410 getDeviceConfigProtoProperty( 411 ContentProviderAllowlists.parser(), 412 PROPERTY_CONTENTPROVIDER_ALLOWLIST, 413 value); 414 // Content providers are restricted by default. If the property is not set, or it is an 415 // empty string, there are no content providers to allowlist. 416 if (contentProviderAllowlistsProto == null) { 417 return new ArrayMap<>(); 418 } 419 420 ArrayMap<Integer, ArraySet<String>> allowedContentProviders = new ArrayMap<>(); 421 422 contentProviderAllowlistsProto 423 .getAllowlistPerTargetSdkMap() 424 .forEach( 425 (sdkVersion, allowList) -> { 426 allowedContentProviders.put( 427 sdkVersion, new ArraySet<>(allowList.getAuthoritiesList())); 428 }); 429 return allowedContentProviders; 430 } 431 432 @Nullable getNextContentProviderDeviceConfigAllowlist( @ullable String value)433 private static ArraySet<String> getNextContentProviderDeviceConfigAllowlist( 434 @Nullable String value) { 435 AllowedContentProviders allowedContentProviders = 436 getDeviceConfigProtoProperty( 437 AllowedContentProviders.parser(), 438 PROPERTY_NEXT_CONTENTPROVIDER_ALLOWLIST, 439 value); 440 if (allowedContentProviders == null) { 441 return null; 442 } 443 return new ArraySet<>(allowedContentProviders.getAuthoritiesList()); 444 } 445 446 @Nullable getBroadcastReceiverDeviceConfigAllowlist( @ullable String value)447 private static ArrayMap<Integer, ArraySet<String>> getBroadcastReceiverDeviceConfigAllowlist( 448 @Nullable String value) { 449 BroadcastReceiverAllowlists broadcastReceiverAllowlistsProto = 450 getDeviceConfigProtoProperty( 451 BroadcastReceiverAllowlists.parser(), 452 PROPERTY_BROADCASTRECEIVER_ALLOWLIST, 453 value); 454 455 if (broadcastReceiverAllowlistsProto == null) { 456 return null; 457 } 458 459 ArrayMap<Integer, ArraySet<String>> allowedBroadcastReceivers = new ArrayMap<>(); 460 461 broadcastReceiverAllowlistsProto 462 .getAllowlistPerTargetSdkMap() 463 .forEach( 464 (sdkVersion, allowList) -> { 465 allowedBroadcastReceivers.put( 466 sdkVersion, new ArraySet<>(allowList.getIntentActionsList())); 467 }); 468 return allowedBroadcastReceivers; 469 } 470 471 @Nullable getNextBroadcastReceiverDeviceConfigAllowlist( @ullable String value)472 private static ArraySet<String> getNextBroadcastReceiverDeviceConfigAllowlist( 473 @Nullable String value) { 474 AllowedBroadcastReceivers allowedBroadcastReceivers = 475 getDeviceConfigProtoProperty( 476 AllowedBroadcastReceivers.parser(), 477 PROPERTY_NEXT_BROADCASTRECEIVER_ALLOWLIST, 478 value); 479 if (allowedBroadcastReceivers == null) { 480 return null; 481 } 482 return new ArraySet<>(allowedBroadcastReceivers.getIntentActionsList()); 483 } 484 485 @Nullable getActivityDeviceConfigAllowlist( @ullable String value)486 private static ArrayMap<Integer, ArraySet<String>> getActivityDeviceConfigAllowlist( 487 @Nullable String value) { 488 ActivityAllowlists activityAllowlistsProto = 489 getDeviceConfigProtoProperty( 490 ActivityAllowlists.parser(), PROPERTY_ACTIVITY_ALLOWLIST, value); 491 492 if (activityAllowlistsProto == null) { 493 return null; 494 } 495 496 ArrayMap<Integer, ArraySet<String>> allowedActivities = new ArrayMap<>(); 497 498 activityAllowlistsProto 499 .getAllowlistPerTargetSdkMap() 500 .forEach( 501 (sdkVersion, allowList) -> { 502 allowedActivities.put( 503 sdkVersion, new ArraySet<>(allowList.getActionsList())); 504 }); 505 return allowedActivities; 506 } 507 508 @Nullable getNextActivityDeviceConfigAllowlist(@ullable String value)509 private static ArraySet<String> getNextActivityDeviceConfigAllowlist(@Nullable String value) { 510 AllowedActivities allowedActivities = 511 getDeviceConfigProtoProperty( 512 AllowedActivities.parser(), PROPERTY_NEXT_ACTIVITY_ALLOWLIST, value); 513 if (allowedActivities == null) { 514 return null; 515 } 516 return new ArraySet<>(allowedActivities.getActionsList()); 517 } 518 } 519