Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d2010f1 authored by Christophe Pinelli's avatar Christophe Pinelli
Browse files

Add strict mode violation policy for safer implicit intents

If an app enables the new violation, a new callback will be
registered in ActivityManagerService,
each callback is registered with the process ID associated with the app.
When non-exported components are matched to an implicit intent
the ActivityManager and the PackageManager will send an event to the app to trigger the violation.

Test: Manual tests + atest StrictModeTest
Bug: 229362273
Change-Id: Ie01c0039362266e009e9467b124791e194e0cbf5
parent 09183fb1
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -907,4 +907,19 @@ public abstract class ActivityManagerInternal {
     * Return all client package names of a service.
     */
    public abstract ArraySet<String> getClientPackages(String servicePackageName);

    /**
     * Retrieve an IUnsafeIntentStrictModeCallback matching the given callingUid.
     * Returns null no match is found.
     * @param callingPid The PID mapped with the callback.
     * @return The callback, if it exists.
     */
    public abstract IUnsafeIntentStrictModeCallback getRegisteredStrictModeCallback(
            int callingPid);

    /**
     * Unregisters an IUnsafeIntentStrictModeCallback matching the given callingUid.
     * @param callingPid The PID mapped with the callback.
     */
    public abstract void unregisterStrictModeCallback(int callingPid);
}
+1 −0
Original line number Diff line number Diff line
@@ -331,6 +331,7 @@ interface IActivityManager {
    @UnsupportedAppUsage
    void handleApplicationStrictModeViolation(in IBinder app, int penaltyMask,
            in StrictMode.ViolationInfo crashInfo);
    void registerStrictModeCallback(in IBinder binder);
    boolean isTopActivityImmersive();
    void crashApplicationWithType(int uid, int initialPid, in String packageName, int userId,
            in String message, boolean force, int exceptionTypeId);
+28 −0
Original line number Diff line number Diff line
/*
* Copyright 2022, 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 android.app;

import android.content.Intent;

/**
 * Callback to find out when a strict mode violation occurs.
 * {@hide}
 */
oneway interface IUnsafeIntentStrictModeCallback
{
    void onImplicitIntentMatchedInternalComponent(in Intent intent);
}
+44 −6
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.annotation.TestApi;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.IActivityManager;
import android.app.IUnsafeIntentStrictModeCallback;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
@@ -1079,8 +1080,7 @@ public final class StrictMode {
            }

            /**
             * Detect when your app launches an {@link Intent} which originated
             * from outside your app.
             * Detect when your app sends an unsafe {@link Intent}.
             * <p>
             * Violations may indicate security vulnerabilities in the design of
             * your app, where a malicious app could trick you into granting
@@ -1088,10 +1088,14 @@ public final class StrictMode {
             * are some typical design patterns that can be used to safely
             * resolve these violations:
             * <ul>
             * <li>The ideal approach is to migrate to using a
             * {@link android.app.PendingIntent}, which ensures that your launch is
             * performed using the identity of the original creator, completely
             * avoiding the security issues described above.
             * <li> If you are sending an implicit intent to an unexported component, you should
             * make it an explicit intent by using {@link Intent#setPackage},
             * {@link Intent#setClassName} or {@link Intent#setComponent}.
             * </li>
             * <li> If you are unparceling and sending an intent from the intent delivered, The
             * ideal approach is to migrate to using a {@link android.app.PendingIntent}, which
             * ensures that your launch is performed using the identity of the original creator,
             * completely avoiding the security issues described above.
             * <li>If using a {@link android.app.PendingIntent} isn't feasible, an
             * alternative approach is to create a brand new {@link Intent} and
             * carefully copy only specific values from the original
@@ -2106,10 +2110,39 @@ public final class StrictMode {
                VMRuntime.setDedupeHiddenApiWarnings(true);
            }

            if ((sVmPolicy.mask & DETECT_VM_UNSAFE_INTENT_LAUNCH) != 0) {
                registerIntentMatchingRestrictionCallback();
            }

            setBlockGuardVmPolicy(sVmPolicy.mask);
        }
    }

    private static void registerIntentMatchingRestrictionCallback() {
        try {
            ActivityManager.getService().registerStrictModeCallback(
                    new UnsafeIntentStrictModeCallback());
        } catch (RemoteException e) {
            /*
            If exception is DeadObjectException it means system process is dead, so we can ignore
             */
            if (!(e instanceof DeadObjectException)) {
                Log.e(TAG, "RemoteException handling StrictMode violation", e);
            }
        }
    }

    private static final class UnsafeIntentStrictModeCallback
            extends IUnsafeIntentStrictModeCallback.Stub {
        @Override
        public void onImplicitIntentMatchedInternalComponent(Intent intent) {
            if (StrictMode.vmUnsafeIntentLaunchEnabled()) {
                StrictMode.onUnsafeIntentLaunch(intent,
                        "Launch of unsafe implicit intent: " + intent);
            }
        }
    }

    /** Gets the current VM policy. */
    public static VmPolicy getVmPolicy() {
        synchronized (StrictMode.class) {
@@ -2333,6 +2366,11 @@ public final class StrictMode {
        onVmPolicyViolation(new UnsafeIntentLaunchViolation(intent));
    }

    /** @hide */
    public static void onUnsafeIntentLaunch(Intent intent, String message) {
        onVmPolicyViolation(new UnsafeIntentLaunchViolation(intent, message));
    }

    /** Assume locked until we hear otherwise */
    private static volatile boolean sUserKeyUnlocked = false;

+6 −0
Original line number Diff line number Diff line
@@ -56,6 +56,12 @@ public final class UnsafeIntentLaunchViolation extends Violation {
        mIntent = Objects.requireNonNull(intent);
    }

    /** @hide */
    public UnsafeIntentLaunchViolation(@NonNull Intent intent, @NonNull String message) {
        super(message);
        mIntent = Objects.requireNonNull(intent);
    }

    /**
     * Return the {@link Intent} which caused this violation to be raised. Note
     * that this value is not available if this violation has been serialized
Loading