diff options
author | Jeff Sharkey <jsharkey@android.com> | 2015-01-16 01:11:26 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2015-01-16 01:11:27 +0000 |
commit | f24e490058bc59344f8bd10fb6cbbffa792fbc05 (patch) | |
tree | 70409e262fce33c56bd565893fcb47ca09116a80 | |
parent | a747d5e47bef27acd18afda3ed43309ad5fab87b (diff) | |
parent | 605eb79c9519307147fc1795d0eb155638a7f542 (diff) | |
download | frameworks_base-f24e490058bc59344f8bd10fb6cbbffa792fbc05.zip frameworks_base-f24e490058bc59344f8bd10fb6cbbffa792fbc05.tar.gz frameworks_base-f24e490058bc59344f8bd10fb6cbbffa792fbc05.tar.bz2 |
Merge "Offer to detect non-SSL/TLS network traffic."
-rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 22 | ||||
-rw-r--r-- | core/java/android/app/ActivityThread.java | 8 | ||||
-rw-r--r-- | core/java/android/app/ApplicationThreadNative.java | 18 | ||||
-rw-r--r-- | core/java/android/app/IActivityManager.java | 5 | ||||
-rw-r--r-- | core/java/android/app/IApplicationThread.java | 2 | ||||
-rw-r--r-- | core/java/android/os/INetworkManagementService.aidl | 2 | ||||
-rw-r--r-- | core/java/android/os/StrictMode.java | 209 | ||||
-rw-r--r-- | services/core/java/com/android/server/NetworkManagementService.java | 93 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ActivityManagerService.java | 29 |
9 files changed, 349 insertions, 39 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 20355ec..09d6c29 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2330,6 +2330,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } + + case NOTIFY_CLEARTEXT_NETWORK_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + final int uid = data.readInt(); + final byte[] firstPacket = data.createByteArray(); + notifyCleartextNetwork(uid, firstPacket); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -5381,5 +5390,18 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } + @Override + public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeInt(uid); + data.writeByteArray(firstPacket); + mRemote.transact(NOTIFY_CLEARTEXT_NETWORK_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + private IBinder mRemote; } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index d70f6ef..9d821e1 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1168,9 +1168,17 @@ public final class ActivityThread { sendMessage(H.BACKGROUND_VISIBLE_BEHIND_CHANGED, token, visible ? 1 : 0); } + @Override public void scheduleEnterAnimationComplete(IBinder token) { sendMessage(H.ENTER_ANIMATION_COMPLETE, token); } + + @Override + public void notifyCleartextNetwork(byte[] firstPacket) { + if (StrictMode.vmCleartextNetworkEnabled()) { + StrictMode.onCleartextNetworkDetected(firstPacket); + } + } } private class H extends Handler { diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index 0123e16..b2bfc13 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -667,6 +667,15 @@ public abstract class ApplicationThreadNative extends Binder reply.writeNoException(); return true; } + + case NOTIFY_CLEARTEXT_NETWORK_TRANSACTION: + { + data.enforceInterface(IApplicationThread.descriptor); + final byte[] firstPacket = data.createByteArray(); + notifyCleartextNetwork(firstPacket); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -1346,4 +1355,13 @@ class ApplicationThreadProxy implements IApplicationThread { mRemote.transact(ENTER_ANIMATION_COMPLETE_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); } + + @Override + public void notifyCleartextNetwork(byte[] firstPacket) throws RemoteException { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(IApplicationThread.descriptor); + data.writeByteArray(firstPacket); + mRemote.transact(NOTIFY_CLEARTEXT_NETWORK_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); + data.recycle(); + } } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index d1279ad..de47147 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -464,6 +464,8 @@ public interface IActivityManager extends IInterface { public void notifyLaunchTaskBehindComplete(IBinder token) throws RemoteException; public void notifyEnterAnimationComplete(IBinder token) throws RemoteException; + public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException; + /* * Private non-Binder interfaces */ @@ -782,4 +784,7 @@ public interface IActivityManager extends IInterface { int BOOT_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+237; int GET_TASK_DESCRIPTION_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+238; int LAUNCH_ASSIST_INTENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+239; + + // Start of M transactions + int NOTIFY_CLEARTEXT_NETWORK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+280; } diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index f53075c..7ff207f 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -146,6 +146,7 @@ public interface IApplicationThread extends IInterface { void scheduleCancelVisibleBehind(IBinder token) throws RemoteException; void scheduleBackgroundVisibleBehindChanged(IBinder token, boolean enabled) throws RemoteException; void scheduleEnterAnimationComplete(IBinder token) throws RemoteException; + void notifyCleartextNetwork(byte[] firstPacket) throws RemoteException; String descriptor = "android.app.IApplicationThread"; @@ -203,4 +204,5 @@ public interface IApplicationThread extends IInterface { int CANCEL_VISIBLE_BEHIND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+52; int BACKGROUND_VISIBLE_BEHIND_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+53; int ENTER_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+54; + int NOTIFY_CLEARTEXT_NETWORK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+55; } diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index 16250c7..07649e7 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -284,6 +284,8 @@ interface INetworkManagementService */ void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces); + void setUidCleartextNetworkPolicy(int uid, int policy); + /** * Return status of bandwidth control module. */ diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index 6db5f67..55ae986 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -32,14 +32,17 @@ import android.util.Slog; import android.view.IWindowManager; import com.android.internal.os.RuntimeInit; - import com.android.internal.util.FastPrintWriter; +import com.android.internal.util.HexDump; + import dalvik.system.BlockGuard; import dalvik.system.CloseGuard; import dalvik.system.VMDebug; import java.io.PrintWriter; import java.io.StringWriter; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -137,6 +140,13 @@ public final class StrictMode { */ public static final String VISUAL_PROPERTY = "persist.sys.strictmode.visual"; + /** + * Temporary property used to include {@link #DETECT_VM_CLEARTEXT_NETWORK} + * in {@link VmPolicy.Builder#detectAll()}. Apps can still always opt-into + * detection using {@link VmPolicy.Builder#detectCleartextNetwork()}. + */ + private static final String CLEARTEXT_PROPERTY = "persist.sys.strictmode.cleartext"; + // Only log a duplicate stack trace to the logs every second. private static final long MIN_LOG_INTERVAL_MS = 1000; @@ -150,7 +160,7 @@ public final class StrictMode { // of the Looper. private static final int MAX_OFFENSES_PER_LOOP = 10; - // Thread-policy: + // Byte 1: Thread-policy /** * @hide @@ -177,83 +187,91 @@ public final class StrictMode { private static final int ALL_THREAD_DETECT_BITS = DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK | DETECT_CUSTOM; - // Process-policy: + // Byte 2: Process-policy /** * Note, a "VM_" bit, not thread. * @hide */ - public static final int DETECT_VM_CURSOR_LEAKS = 0x200; // for VmPolicy + public static final int DETECT_VM_CURSOR_LEAKS = 0x01 << 8; // for VmPolicy /** * Note, a "VM_" bit, not thread. * @hide */ - public static final int DETECT_VM_CLOSABLE_LEAKS = 0x400; // for VmPolicy + public static final int DETECT_VM_CLOSABLE_LEAKS = 0x02 << 8; // for VmPolicy /** * Note, a "VM_" bit, not thread. * @hide */ - public static final int DETECT_VM_ACTIVITY_LEAKS = 0x800; // for VmPolicy + public static final int DETECT_VM_ACTIVITY_LEAKS = 0x04 << 8; // for VmPolicy + + /** + * @hide + */ + private static final int DETECT_VM_INSTANCE_LEAKS = 0x08 << 8; // for VmPolicy /** * @hide */ - private static final int DETECT_VM_INSTANCE_LEAKS = 0x1000; // for VmPolicy + public static final int DETECT_VM_REGISTRATION_LEAKS = 0x10 << 8; // for VmPolicy /** * @hide */ - public static final int DETECT_VM_REGISTRATION_LEAKS = 0x2000; // for VmPolicy + private static final int DETECT_VM_FILE_URI_EXPOSURE = 0x20 << 8; // for VmPolicy /** * @hide */ - private static final int DETECT_VM_FILE_URI_EXPOSURE = 0x4000; // for VmPolicy + private static final int DETECT_VM_CLEARTEXT_NETWORK = 0x40 << 8; // for VmPolicy private static final int ALL_VM_DETECT_BITS = DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS | DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS | - DETECT_VM_REGISTRATION_LEAKS | DETECT_VM_FILE_URI_EXPOSURE; + DETECT_VM_REGISTRATION_LEAKS | DETECT_VM_FILE_URI_EXPOSURE | + DETECT_VM_CLEARTEXT_NETWORK; + + // Byte 3: Penalty /** * @hide */ - public static final int PENALTY_LOG = 0x10; // normal android.util.Log + public static final int PENALTY_LOG = 0x01 << 16; // normal android.util.Log // Used for both process and thread policy: /** * @hide */ - public static final int PENALTY_DIALOG = 0x20; + public static final int PENALTY_DIALOG = 0x02 << 16; /** * Death on any detected violation. * * @hide */ - public static final int PENALTY_DEATH = 0x40; + public static final int PENALTY_DEATH = 0x04 << 16; /** * Death just for detected network usage. * * @hide */ - public static final int PENALTY_DEATH_ON_NETWORK = 0x200; + public static final int PENALTY_DEATH_ON_NETWORK = 0x08 << 16; /** * Flash the screen during violations. * * @hide */ - public static final int PENALTY_FLASH = 0x800; + public static final int PENALTY_FLASH = 0x10 << 16; /** * @hide */ - public static final int PENALTY_DROPBOX = 0x80; + public static final int PENALTY_DROPBOX = 0x20 << 16; /** * Non-public penalty mode which overrides all the other penalty @@ -266,7 +284,14 @@ public final class StrictMode { * * @hide */ - public static final int PENALTY_GATHER = 0x100; + public static final int PENALTY_GATHER = 0x40 << 16; + + /** + * Death when cleartext network traffic is detected. + * + * @hide + */ + public static final int PENALTY_DEATH_ON_CLEARTEXT_NETWORK = 0x80 << 16; /** * Mask of all the penalty bits valid for thread policies. @@ -275,13 +300,18 @@ public final class StrictMode { PENALTY_LOG | PENALTY_DIALOG | PENALTY_DEATH | PENALTY_DROPBOX | PENALTY_GATHER | PENALTY_DEATH_ON_NETWORK | PENALTY_FLASH; - /** * Mask of all the penalty bits valid for VM policies. */ - private static final int VM_PENALTY_MASK = - PENALTY_LOG | PENALTY_DEATH | PENALTY_DROPBOX; + private static final int VM_PENALTY_MASK = PENALTY_LOG | PENALTY_DEATH | PENALTY_DROPBOX + | PENALTY_DEATH_ON_CLEARTEXT_NETWORK; + /** {@hide} */ + public static final int NETWORK_POLICY_ACCEPT = 0; + /** {@hide} */ + public static final int NETWORK_POLICY_LOG = 1; + /** {@hide} */ + public static final int NETWORK_POLICY_REJECT = 2; // TODO: wrap in some ImmutableHashMap thing. // Note: must be before static initialization of sVmPolicy. @@ -636,9 +666,17 @@ public final class StrictMode { * but will likely expand in future releases. */ public Builder detectAll() { - return enable(DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_CURSOR_LEAKS + int flags = DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS | DETECT_VM_REGISTRATION_LEAKS - | DETECT_VM_FILE_URI_EXPOSURE); + | DETECT_VM_FILE_URI_EXPOSURE; + + // TODO: always add DETECT_VM_CLEARTEXT_NETWORK once we have facility + // for apps to mark sockets that should be ignored + if (SystemProperties.getBoolean(CLEARTEXT_PROPERTY, false)) { + flags |= DETECT_VM_CLEARTEXT_NETWORK; + } + + return enable(flags); } /** @@ -686,15 +724,49 @@ public final class StrictMode { } /** - * Crashes the whole process on violation. This penalty runs at - * the end of all enabled penalties so yo you'll still get - * your logging or other violations before the process dies. + * Detect any network traffic from the calling app which is not + * wrapped in SSL/TLS. This can help you detect places that your app + * is inadvertently sending cleartext data across the network. + * <p> + * Using {@link #penaltyDeath()} or + * {@link #penaltyDeathOnCleartextNetwork()} will block further + * traffic on that socket to prevent accidental data leakage, in + * addition to crashing your process. + * <p> + * Using {@link #penaltyDropBox()} will log the raw contents of the + * packet that triggered the violation. + * <p> + * This inspects both IPv4/IPv6 and TCP/UDP network traffic, but it + * may be subject to false positives, such as when STARTTLS + * protocols or HTTP proxies are used. + * + * @hide + */ + public Builder detectCleartextNetwork() { + return enable(DETECT_VM_CLEARTEXT_NETWORK); + } + + /** + * Crashes the whole process on violation. This penalty runs at the + * end of all enabled penalties so you'll still get your logging or + * other violations before the process dies. */ public Builder penaltyDeath() { return enable(PENALTY_DEATH); } /** + * Crashes the whole process when cleartext network traffic is + * detected. + * + * @see #detectCleartextNetwork() + * @hide + */ + public Builder penaltyDeathOnCleartextNetwork() { + return enable(PENALTY_DEATH_ON_CLEARTEXT_NETWORK); + } + + /** * Log detected violations to the system log. */ public Builder penaltyLog() { @@ -1422,7 +1494,7 @@ public final class StrictMode { } private static class AndroidCloseGuardReporter implements CloseGuard.Reporter { - public void report (String message, Throwable allocationSite) { + public void report(String message, Throwable allocationSite) { onVmPolicyViolation(message, allocationSite); } } @@ -1508,6 +1580,27 @@ public final class StrictMode { sIsIdlerRegistered = true; } } + + int networkPolicy = NETWORK_POLICY_ACCEPT; + if ((sVmPolicyMask & DETECT_VM_CLEARTEXT_NETWORK) != 0) { + if ((sVmPolicyMask & PENALTY_DEATH) != 0 + || (sVmPolicyMask & PENALTY_DEATH_ON_CLEARTEXT_NETWORK) != 0) { + networkPolicy = NETWORK_POLICY_REJECT; + } else { + networkPolicy = NETWORK_POLICY_LOG; + } + } + + final INetworkManagementService netd = INetworkManagementService.Stub.asInterface( + ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)); + if (netd != null) { + try { + netd.setUidCleartextNetworkPolicy(android.os.Process.myUid(), networkPolicy); + } catch (RemoteException ignored) { + } + } else if (networkPolicy != NETWORK_POLICY_ACCEPT) { + Log.w(TAG, "Dropping requested network policy due to missing service!"); + } } } @@ -1570,6 +1663,13 @@ public final class StrictMode { /** * @hide */ + public static boolean vmCleartextNetworkEnabled() { + return (sVmPolicyMask & DETECT_VM_CLEARTEXT_NETWORK) != 0; + } + + /** + * @hide + */ public static void onSqliteObjectLeaked(String message, Throwable originStack) { onVmPolicyViolation(message, originStack); } @@ -1600,7 +1700,39 @@ public final class StrictMode { */ public static void onFileUriExposed(String location) { final String message = "file:// Uri exposed through " + location; - onVmPolicyViolation(message, new Throwable(message)); + onVmPolicyViolation(null, new Throwable(message)); + } + + /** + * @hide + */ + public static void onCleartextNetworkDetected(byte[] firstPacket) { + byte[] rawAddr = null; + if (firstPacket != null) { + if (firstPacket.length >= 20 && (firstPacket[0] & 0xf0) == 0x40) { + // IPv4 + rawAddr = new byte[4]; + System.arraycopy(firstPacket, 16, rawAddr, 0, 4); + } else if (firstPacket.length >= 40 && (firstPacket[0] & 0xf0) == 0x60) { + // IPv6 + rawAddr = new byte[16]; + System.arraycopy(firstPacket, 24, rawAddr, 0, 16); + } + } + + final int uid = android.os.Process.myUid(); + String msg = "Detected cleartext network traffic from UID " + uid; + if (rawAddr != null) { + try { + msg = "Detected cleartext network traffic from UID " + uid + " to " + + InetAddress.getByAddress(rawAddr); + } catch (UnknownHostException ignored) { + } + } + + final boolean forceDeath = (sVmPolicyMask & PENALTY_DEATH_ON_CLEARTEXT_NETWORK) != 0; + onVmPolicyViolation(HexDump.dumpHexString(firstPacket).trim(), new Throwable(msg), + forceDeath); } // Map from VM violation fingerprint to uptime millis. @@ -1610,10 +1742,18 @@ public final class StrictMode { * @hide */ public static void onVmPolicyViolation(String message, Throwable originStack) { + onVmPolicyViolation(message, originStack, false); + } + + /** + * @hide + */ + public static void onVmPolicyViolation(String message, Throwable originStack, + boolean forceDeath) { final boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0; - final boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0; + final boolean penaltyDeath = ((sVmPolicyMask & PENALTY_DEATH) != 0) || forceDeath; final boolean penaltyLog = (sVmPolicyMask & PENALTY_LOG) != 0; - final ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask); + final ViolationInfo info = new ViolationInfo(message, originStack, sVmPolicyMask); // Erase stuff not relevant for process-wide violations info.numAnimationsRunning = 0; @@ -2057,6 +2197,8 @@ public final class StrictMode { * @hide */ public static class ViolationInfo { + public String message; + /** * Stack and other stuff info. */ @@ -2118,10 +2260,15 @@ public final class StrictMode { policy = 0; } + public ViolationInfo(Throwable tr, int policy) { + this(null, tr, policy); + } + /** * Create an instance of ViolationInfo initialized from an exception. */ - public ViolationInfo(Throwable tr, int policy) { + public ViolationInfo(String message, Throwable tr, int policy) { + this.message = message; crashInfo = new ApplicationErrorReport.CrashInfo(tr); violationUptimeMillis = SystemClock.uptimeMillis(); this.policy = policy; @@ -2184,6 +2331,7 @@ public final class StrictMode { * and the gathering penalty should be removed. */ public ViolationInfo(Parcel in, boolean unsetGatheringBit) { + message = in.readString(); crashInfo = new ApplicationErrorReport.CrashInfo(in); int rawPolicy = in.readInt(); if (unsetGatheringBit) { @@ -2204,6 +2352,7 @@ public final class StrictMode { * Save a ViolationInfo instance to a parcel. */ public void writeToParcel(Parcel dest, int flags) { + dest.writeString(message); crashInfo.writeToParcel(dest, flags); int start = dest.dataPosition(); dest.writeInt(policy); diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 020c951..967ee31 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -24,9 +24,6 @@ import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_TETHERING; -import static android.net.RouteInfo.RTN_THROW; -import static android.net.RouteInfo.RTN_UNICAST; -import static android.net.RouteInfo.RTN_UNREACHABLE; import static com.android.server.NetworkManagementService.NetdResponseCode.ClatdStatusResult; import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult; import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult; @@ -38,6 +35,7 @@ import static com.android.server.NetworkManagementService.NetdResponseCode.Tethe import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult; import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED; +import android.app.ActivityManagerNative; import android.content.Context; import android.net.ConnectivityManager; import android.net.INetworkManagementEventObserver; @@ -61,6 +59,7 @@ import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemProperties; import android.telephony.DataConnectionRealTimeInfo; @@ -70,9 +69,12 @@ import android.telephony.TelephonyManager; import android.util.Log; import android.util.Slog; import android.util.SparseBooleanArray; +import android.util.SparseIntArray; +import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IBatteryStats; import com.android.internal.net.NetworkStatsFactory; +import com.android.internal.util.HexDump; import com.android.internal.util.Preconditions; import com.android.server.NativeDaemonConnector.Command; import com.android.server.NativeDaemonConnector.SensitiveArg; @@ -87,8 +89,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; -import java.net.Inet4Address; -import java.net.Inet6Address; import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.NetworkInterface; @@ -145,6 +145,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub public static final int InterfaceAddressChange = 614; public static final int InterfaceDnsServerInfo = 615; public static final int RouteChange = 616; + public static final int StrictCleartext = 617; } static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1; @@ -174,12 +175,19 @@ public class NetworkManagementService extends INetworkManagementService.Stub private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory(); private Object mQuotaLock = new Object(); + /** Set of interfaces with active quotas. */ + @GuardedBy("mQuotaLock") private HashMap<String, Long> mActiveQuotas = Maps.newHashMap(); /** Set of interfaces with active alerts. */ + @GuardedBy("mQuotaLock") private HashMap<String, Long> mActiveAlerts = Maps.newHashMap(); /** Set of UIDs with active reject rules. */ + @GuardedBy("mQuotaLock") private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray(); + /** Set of UIDs with cleartext penalties. */ + @GuardedBy("mQuotaLock") + private SparseIntArray mUidCleartextPolicy = new SparseIntArray(); private Object mIdleTimerLock = new Object(); /** Set of interfaces with active idle timers. */ @@ -198,6 +206,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub private volatile boolean mBandwidthControlEnabled; private volatile boolean mFirewallEnabled; + private volatile boolean mStrictEnabled; private boolean mMobileActivityFromRadio = false; private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW; @@ -495,11 +504,18 @@ public class NetworkManagementService extends INetworkManagementService.Stub } } + try { + mConnector.execute("strict", "enable"); + mStrictEnabled = true; + } catch (NativeDaemonConnectorException e) { + Log.wtf(TAG, "Failed strict enable", e); + } + // push any existing quota or UID rules synchronized (mQuotaLock) { int size = mActiveQuotas.size(); if (size > 0) { - Slog.d(TAG, "pushing " + size + " active quota rules"); + Slog.d(TAG, "Pushing " + size + " active quota rules"); final HashMap<String, Long> activeQuotas = mActiveQuotas; mActiveQuotas = Maps.newHashMap(); for (Map.Entry<String, Long> entry : activeQuotas.entrySet()) { @@ -509,7 +525,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub size = mActiveAlerts.size(); if (size > 0) { - Slog.d(TAG, "pushing " + size + " active alert rules"); + Slog.d(TAG, "Pushing " + size + " active alert rules"); final HashMap<String, Long> activeAlerts = mActiveAlerts; mActiveAlerts = Maps.newHashMap(); for (Map.Entry<String, Long> entry : activeAlerts.entrySet()) { @@ -519,13 +535,23 @@ public class NetworkManagementService extends INetworkManagementService.Stub size = mUidRejectOnQuota.size(); if (size > 0) { - Slog.d(TAG, "pushing " + size + " active uid rules"); + Slog.d(TAG, "Pushing " + size + " active UID rules"); final SparseBooleanArray uidRejectOnQuota = mUidRejectOnQuota; mUidRejectOnQuota = new SparseBooleanArray(); for (int i = 0; i < uidRejectOnQuota.size(); i++) { setUidNetworkRules(uidRejectOnQuota.keyAt(i), uidRejectOnQuota.valueAt(i)); } } + + size = mUidCleartextPolicy.size(); + if (size > 0) { + Slog.d(TAG, "Pushing " + size + " active UID cleartext policies"); + final SparseIntArray local = mUidCleartextPolicy; + mUidCleartextPolicy = new SparseIntArray(); + for (int i = 0; i < local.size(); i++) { + setUidCleartextNetworkPolicy(local.keyAt(i), local.valueAt(i)); + } + } } // TODO: Push any existing firewall state @@ -792,6 +818,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub } throw new IllegalStateException(errorMessage); // break; + case NetdResponseCode.StrictCleartext: + final int uid = Integer.parseInt(cooked[1]); + final byte[] firstPacket = HexDump.hexStringToByteArray(cooked[2]); + try { + ActivityManagerNative.getDefault().notifyCleartextNetwork(uid, firstPacket); + } catch (RemoteException ignored) { + } + break; default: break; } return false; @@ -1641,6 +1675,49 @@ public class NetworkManagementService extends INetworkManagementService.Stub } @Override + public void setUidCleartextNetworkPolicy(int uid, int policy) { + if (Binder.getCallingUid() != uid) { + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + } + + synchronized (mQuotaLock) { + final int oldPolicy = mUidCleartextPolicy.get(uid, StrictMode.NETWORK_POLICY_ACCEPT); + if (oldPolicy == policy) { + return; + } + + if (!mStrictEnabled) { + // Module isn't enabled yet; stash the requested policy away to + // apply later once the daemon is connected. + mUidCleartextPolicy.put(uid, policy); + return; + } + + final String policyString; + switch (policy) { + case StrictMode.NETWORK_POLICY_ACCEPT: + policyString = "accept"; + break; + case StrictMode.NETWORK_POLICY_LOG: + policyString = "log"; + break; + case StrictMode.NETWORK_POLICY_REJECT: + policyString = "reject"; + break; + default: + throw new IllegalArgumentException("Unknown policy " + policy); + } + + try { + mConnector.execute("strict", "set_uid_cleartext_policy", uid, policyString); + mUidCleartextPolicy.put(uid, policy); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); + } + } + } + + @Override public boolean isBandwidthControlEnabled() { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); return mBandwidthControlEnabled; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 3cc27f4..668d62b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1197,6 +1197,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final int FINISH_BOOTING_MSG = 45; static final int START_USER_SWITCH_MSG = 46; static final int SEND_LOCALE_TO_MOUNT_DAEMON_MSG = 47; + static final int NOTIFY_CLEARTEXT_NETWORK_MSG = 50; static final int FIRST_ACTIVITY_STACK_MSG = 100; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -1902,6 +1903,23 @@ public final class ActivityManagerService extends ActivityManagerNative } break; } + case NOTIFY_CLEARTEXT_NETWORK_MSG: { + final int uid = msg.arg1; + final byte[] firstPacket = (byte[]) msg.obj; + + synchronized (mPidsSelfLocked) { + for (int i = 0; i < mPidsSelfLocked.size(); i++) { + final ProcessRecord p = mPidsSelfLocked.valueAt(i); + if (p.uid == uid) { + try { + p.thread.notifyCleartextNetwork(firstPacket); + } catch (RemoteException ignored) { + } + } + } + } + break; + } } } }; @@ -10106,6 +10124,11 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override + public void notifyCleartextNetwork(int uid, byte[] firstPacket) { + mHandler.obtainMessage(NOTIFY_CLEARTEXT_NETWORK_MSG, uid, 0, firstPacket).sendToTarget(); + } + + @Override public boolean shutdown(int timeout) { if (checkCallingPermission(android.Manifest.permission.SHUTDOWN) != PackageManager.PERMISSION_GRANTED) { @@ -11727,8 +11750,12 @@ public final class ActivityManagerService extends ActivityManagerNative sb.append("\n"); if (info.crashInfo != null && info.crashInfo.stackTrace != null) { sb.append(info.crashInfo.stackTrace); + sb.append("\n"); + } + if (info.message != null) { + sb.append(info.message); + sb.append("\n"); } - sb.append("\n"); // Only buffer up to ~64k. Various logging bits truncate // things at 128k. |