diff options
6 files changed, 228 insertions, 0 deletions
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 21f5f899e75c..53f306bae8e5 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -822,4 +822,19 @@ public abstract class PackageManagerInternal { /** Sets the enforcement of reading external storage */ public abstract void setReadExternalStorageEnforced(boolean enforced); + + /** + * Allows the integrity component to respond to the + * {@link Intent#ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION package verification + * broadcast} to respond to the package manager. The response must include + * the {@code verificationCode} which is one of + * {@link PackageManager#VERIFICATION_ALLOW} or + * {@link PackageManager#VERIFICATION_REJECT}. + * + * @param verificationId pending package identifier as passed via the + * {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra. + * @param verificationResult either {@link PackageManager#VERIFICATION_ALLOW} + * or {@link PackageManager#VERIFICATION_REJECT}. + */ + public abstract void setIntegrityVerificationResult(int verificationId, int verificationResult); } diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerService.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerService.java new file mode 100644 index 000000000000..005fb696b089 --- /dev/null +++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerService.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.integrity; + +import android.content.Context; + +import com.android.server.SystemService; + +/** + * Service that manages app integrity rules and verifications. + * + * @hide + */ +public class AppIntegrityManagerService extends SystemService { + + private Context mContext; + private AppIntegrityManagerServiceImpl mService; + + public AppIntegrityManagerService(Context context) { + super(context); + mContext = context; + } + + @Override + public void onStart() { + mService = new AppIntegrityManagerServiceImpl(mContext); + // TODO: define and publish a binder service. + } +} diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java new file mode 100644 index 000000000000..39c1b8535565 --- /dev/null +++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.integrity; + +import static android.content.Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION; +import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; +import android.os.Handler; +import android.os.HandlerThread; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.LocalServices; + +/** Implementation of {@link AppIntegrityManagerService}. */ +class AppIntegrityManagerServiceImpl { + private static final String TAG = "AppIntegrityManagerServiceImpl"; + + private final Context mContext; + private final Handler mHandler; + private final PackageManagerInternal mPackageManagerInternal; + + AppIntegrityManagerServiceImpl(Context context) { + mContext = context; + + HandlerThread handlerThread = new HandlerThread("AppIntegrityManagerServiceHandler"); + handlerThread.start(); + mHandler = handlerThread.getThreadHandler(); + + mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); + + IntentFilter integrityVerificationFilter = new IntentFilter(); + integrityVerificationFilter.addAction(ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION); + + mContext.registerReceiver( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (!ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION.equals( + intent.getAction())) { + return; + } + mHandler.post(() -> handleIntegrityVerification(intent)); + } + }, + integrityVerificationFilter, + /* broadcastPermission= */ null, + mHandler); + } + + // protected broadcasts cannot be sent in the test. + @VisibleForTesting + void handleIntegrityVerification(Intent intent) { + int verificationId = intent.getIntExtra(EXTRA_VERIFICATION_ID, -1); + // TODO: implement this method. + Slog.i(TAG, "Received integrity verification intent " + intent.toString()); + mPackageManagerInternal.setIntegrityVerificationResult( + verificationId, PackageManager.VERIFICATION_ALLOW); + } +} diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 73ab82dc01b2..aa6c6c7a2f45 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1439,6 +1439,7 @@ public class PackageManagerService extends IPackageManager.Stub static final int ENABLE_ROLLBACK_TIMEOUT = 22; static final int DEFERRED_NO_KILL_POST_DELETE = 23; static final int DEFERRED_NO_KILL_INSTALL_OBSERVER = 24; + static final int INTEGRITY_VERIFICATION_COMPLETE = 25; static final int DEFERRED_NO_KILL_POST_DELETE_DELAY_MS = 3 * 1000; static final int DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS = 500; @@ -1763,6 +1764,10 @@ public class PackageManagerService extends IPackageManager.Stub break; } + case INTEGRITY_VERIFICATION_COMPLETE: { + // TODO: implement this case. + break; + } case START_INTENT_FILTER_VERIFICATIONS: { IFVerificationParams params = (IFVerificationParams) msg.obj; verifyIntentFiltersIfNeeded(params.userId, params.verifierUid, params.replacing, @@ -23199,6 +23204,14 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.writeLPr(); } } + + @Override + public void setIntegrityVerificationResult(int verificationId, int verificationResult) { + final Message msg = mHandler.obtainMessage(INTEGRITY_VERIFICATION_COMPLETE); + msg.arg1 = verificationId; + msg.obj = verificationResult; + mHandler.sendMessage(msg); + } } @GuardedBy("mLock") diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 21cacd45dcb5..b6e501a785ef 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -109,6 +109,7 @@ import com.android.server.input.InputManagerService; import com.android.server.inputmethod.InputMethodManagerService; import com.android.server.inputmethod.InputMethodSystemProperty; import com.android.server.inputmethod.MultiClientInputMethodManagerService; +import com.android.server.integrity.AppIntegrityManagerService; import com.android.server.lights.LightsService; import com.android.server.media.MediaResourceMonitorService; import com.android.server.media.MediaRouterService; @@ -1129,6 +1130,10 @@ public final class SystemServer { SignedConfigService.registerUpdateReceiver(mSystemContext); t.traceEnd(); + t.traceBegin("AppIntegrityService"); + mSystemServiceManager.startService(AppIntegrityManagerService.class); + t.traceEnd(); + } catch (Throwable e) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting core service"); diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java new file mode 100644 index 000000000000..37ff06a18492 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.integrity; + +import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID; + +import static org.mockito.Mockito.verify; + +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.LocalServices; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +/** Unit test for {@link com.android.server.integrity.AppIntegrityManagerServiceImpl} */ +@RunWith(AndroidJUnit4.class) +public class AppIntegrityManagerServiceImplTest { + + @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); + + @Mock PackageManagerInternal mPackageManagerInternal; + + // under test + private AppIntegrityManagerServiceImpl mService; + + @Before + public void setup() { + LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); + + mService = new AppIntegrityManagerServiceImpl(InstrumentationRegistry.getContext()); + } + + @Test + public void integrityVerification_allow() { + int verificationId = 2; + Intent integrityVerificationIntent = new Intent(); + integrityVerificationIntent.setAction(Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION); + integrityVerificationIntent.putExtra(EXTRA_VERIFICATION_ID, verificationId); + + // We cannot send the broadcast using the context since it is a protected broadcast and + // we will get a security exception. + mService.handleIntegrityVerification(integrityVerificationIntent); + + verify(mPackageManagerInternal) + .setIntegrityVerificationResult(verificationId, PackageManager.VERIFICATION_ALLOW); + } +} |