Merge tag 'android-security-10.0.0_r56' into int/10/fp2
Android security 10.0.0 release 56
* tag 'android-security-10.0.0_r56':
Fix the security issue that preloaded apps can get SSID & BSSID
Change-Id: Ia1e877871ebe842d908633cd4baed47c12b07082
diff --git a/Android.bp b/Android.bp
index c013b8c..1e583e1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -49,6 +49,7 @@
"captiveportal-lib",
],
manifest: "AndroidManifestBase.xml",
+ plugins: ["java_api_finder"],
}
cc_library_shared {
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 250feee..5dcf27e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -19,7 +19,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.networkstack"
android:sharedUserId="android.uid.networkstack"
- android:versionCode="290000000"
+ android:versionCode="299900000"
android:versionName="2019-09"
>
diff --git a/src/android/net/dhcp/DhcpClient.java b/src/android/net/dhcp/DhcpClient.java
index ca6c17a..c45fc82 100644
--- a/src/android/net/dhcp/DhcpClient.java
+++ b/src/android/net/dhcp/DhcpClient.java
@@ -28,6 +28,7 @@
import static android.net.dhcp.DhcpPacket.DHCP_VENDOR_INFO;
import static android.net.dhcp.DhcpPacket.INADDR_ANY;
import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST;
+import static android.net.dhcp.DhcpPacket.INFINITE_LEASE;
import static android.net.util.NetworkStackUtils.closeSocketQuietly;
import static android.net.util.SocketUtils.makePacketSocketAddress;
import static android.system.OsConstants.AF_INET;
@@ -43,11 +44,16 @@
import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
+import android.annotation.NonNull;
import android.content.Context;
import android.net.DhcpResults;
import android.net.InetAddresses;
+import android.net.NetworkStackIpMemoryStore;
import android.net.TrafficStats;
import android.net.ip.IpClient;
+import android.net.ipmemorystore.NetworkAttributes;
+import android.net.ipmemorystore.OnNetworkAttributesRetrievedListener;
+import android.net.ipmemorystore.OnStatusListener;
import android.net.metrics.DhcpClientEvent;
import android.net.metrics.DhcpErrorEvent;
import android.net.metrics.IpConnectivityLog;
@@ -62,6 +68,7 @@
import android.util.Log;
import android.util.SparseArray;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.HexDump;
import com.android.internal.util.MessageUtils;
import com.android.internal.util.State;
@@ -118,8 +125,9 @@
// Timers and timeouts.
private static final int SECONDS = 1000;
- private static final int FIRST_TIMEOUT_MS = 2 * SECONDS;
- private static final int MAX_TIMEOUT_MS = 128 * SECONDS;
+ private static final int FIRST_TIMEOUT_MS = 2 * SECONDS;
+ private static final int MAX_TIMEOUT_MS = 128 * SECONDS;
+ private static final int IPMEMORYSTORE_TIMEOUT_MS = 1 * SECONDS;
// This is not strictly needed, since the client is asynchronous and implements exponential
// backoff. It's maintained for backwards compatibility with the previous DHCP code, which was
@@ -166,6 +174,12 @@
private static final int CMD_RENEW_DHCP = PRIVATE_BASE + 4;
private static final int CMD_REBIND_DHCP = PRIVATE_BASE + 5;
private static final int CMD_EXPIRE_DHCP = PRIVATE_BASE + 6;
+ private static final int EVENT_CONFIGURATION_TIMEOUT = PRIVATE_BASE + 7;
+ private static final int EVENT_CONFIGURATION_OBTAINED = PRIVATE_BASE + 8;
+ private static final int EVENT_CONFIGURATION_INVALID = PRIVATE_BASE + 9;
+
+ // constant to represent this DHCP lease has been expired.
+ private static final long EXPIRED_LEASE = 1L;
// For message logging.
private static final Class[] sMessageClasses = { DhcpClient.class };
@@ -222,6 +236,12 @@
private DhcpResults mDhcpLease;
private long mDhcpLeaseExpiry;
private DhcpResults mOffer;
+ private String mL2Key;
+ private Inet4Address mLastAssignedIpv4Address;
+ private long mLastAssignedIpv4AddressExpiry;
+ private boolean mDhcpLeaseCacheEnabled;
+ @NonNull
+ private final NetworkStackIpMemoryStore mIpMemoryStore;
// Milliseconds SystemClock timestamps used to record transition times to DhcpBoundState.
private long mLastInitEnterTime;
@@ -240,8 +260,11 @@
private State mDhcpRebindingState = new DhcpRebindingState();
private State mDhcpInitRebootState = new DhcpInitRebootState();
private State mDhcpRebootingState = new DhcpRebootingState();
+ private State mObtainingConfigurationState = new ObtainingConfigurationState();
private State mWaitBeforeStartState = new WaitBeforeStartState(mDhcpInitState);
private State mWaitBeforeRenewalState = new WaitBeforeRenewalState(mDhcpRenewingState);
+ private State mWaitBeforeObtainingConfigurationState =
+ new WaitBeforeObtainingConfigurationState(mObtainingConfigurationState);
private WakeupMessage makeWakeupMessage(String cmdName, int cmd) {
cmdName = DhcpClient.class.getSimpleName() + "." + mIfaceName + "." + cmdName;
@@ -249,17 +272,22 @@
}
// TODO: Take an InterfaceParams instance instead of an interface name String.
- private DhcpClient(Context context, StateMachine controller, String iface) {
+ private DhcpClient(Context context, StateMachine controller, String iface,
+ NetworkStackIpMemoryStore ipMemoryStore) {
super(TAG, controller.getHandler());
mContext = context;
mController = controller;
mIfaceName = iface;
+ mIpMemoryStore = ipMemoryStore;
+ // CHECKSTYLE:OFF IndentationCheck
addState(mStoppedState);
addState(mDhcpState);
addState(mDhcpInitState, mDhcpState);
addState(mWaitBeforeStartState, mDhcpState);
+ addState(mWaitBeforeObtainingConfigurationState, mDhcpState);
+ addState(mObtainingConfigurationState, mDhcpState);
addState(mDhcpSelectingState, mDhcpState);
addState(mDhcpRequestingState, mDhcpState);
addState(mDhcpHaveLeaseState, mDhcpState);
@@ -270,6 +298,7 @@
addState(mDhcpRebindingState, mDhcpHaveLeaseState);
addState(mDhcpInitRebootState, mDhcpState);
addState(mDhcpRebootingState, mDhcpState);
+ // CHECKSTYLE:ON IndentationCheck
setInitialState(mStoppedState);
@@ -290,13 +319,34 @@
}
public static DhcpClient makeDhcpClient(
- Context context, StateMachine controller, InterfaceParams ifParams) {
- DhcpClient client = new DhcpClient(context, controller, ifParams.name);
+ Context context, StateMachine controller, InterfaceParams ifParams,
+ NetworkStackIpMemoryStore ipMemoryStore) {
+ DhcpClient client = new DhcpClient(context, controller, ifParams.name, ipMemoryStore);
client.mIface = ifParams;
client.start();
return client;
}
+ /**
+ * check whether or not to support caching the last lease info and INIT-REBOOT state.
+ *
+ */
+ public boolean isDhcpLeaseCacheEnabled() {
+ mDhcpLeaseCacheEnabled = Boolean.parseBoolean(NetworkStackUtils.getDeviceConfigProperty(
+ NetworkStackUtils.NAMESPACE_CONNECTIVITY,
+ NetworkStackUtils.DHCP_INIT_REBOOT_ENABLED, "false"));
+ return mDhcpLeaseCacheEnabled;
+ }
+
+ /**
+ * set DHCP lease cached enabled experiment flag.
+ *
+ */
+ @VisibleForTesting
+ public void setDhcpLeaseCacheEnabled(final boolean enabled) {
+ mDhcpLeaseCacheEnabled = enabled;
+ }
+
private boolean initInterface() {
if (mIface == null) mIface = InterfaceParams.getByName(mIfaceName);
if (mIface == null) {
@@ -491,12 +541,48 @@
Log.d(TAG, "Scheduling expiry in " + (remainingDelay / 1000) + "s");
}
+ private void setLeaseExpiredToIpMemoryStore() {
+ final String l2Key = mL2Key;
+ if (l2Key == null) return;
+ final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
+ // TODO: clear out the address and lease instead of storing an expired lease
+ na.setAssignedV4AddressExpiry(EXPIRED_LEASE);
+
+ final OnStatusListener listener = status -> {
+ if (!status.isSuccess()) Log.e(TAG, "Failed to set lease expiry, status: " + status);
+ };
+ mIpMemoryStore.storeNetworkAttributes(l2Key, na.build(), listener);
+ }
+
+ private void maybeSaveLeaseToIpMemoryStore() {
+ final String l2Key = mL2Key;
+ if (l2Key == null || mDhcpLease == null || mDhcpLease.ipAddress == null) return;
+ final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
+ na.setAssignedV4Address((Inet4Address) mDhcpLease.ipAddress.getAddress());
+ na.setAssignedV4AddressExpiry((mDhcpLease.leaseDuration == INFINITE_LEASE)
+ ? Long.MAX_VALUE
+ : mDhcpLease.leaseDuration * 1000 + System.currentTimeMillis());
+ na.setDnsAddresses(mDhcpLease.dnsServers);
+ na.setMtu(mDhcpLease.mtu);
+
+ final OnStatusListener listener = status -> {
+ if (!status.isSuccess()) Log.e(TAG, "Failed to store network attrs, status: " + status);
+ };
+ mIpMemoryStore.storeNetworkAttributes(l2Key, na.build(), listener);
+ }
+
private void notifySuccess() {
+ if (isDhcpLeaseCacheEnabled()) {
+ maybeSaveLeaseToIpMemoryStore();
+ }
mController.sendMessage(
CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, new DhcpResults(mDhcpLease));
}
private void notifyFailure() {
+ if (isDhcpLeaseCacheEnabled()) {
+ setLeaseExpiredToIpMemoryStore();
+ }
mController.sendMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0, null);
}
@@ -616,10 +702,13 @@
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_START_DHCP:
+ mL2Key = (String) message.obj;
if (mRegisteredForPreDhcpNotification) {
- transitionTo(mWaitBeforeStartState);
+ transitionTo(isDhcpLeaseCacheEnabled()
+ ? mWaitBeforeObtainingConfigurationState : mWaitBeforeStartState);
} else {
- transitionTo(mDhcpInitState);
+ transitionTo(isDhcpLeaseCacheEnabled()
+ ? mObtainingConfigurationState : mDhcpInitState);
}
return HANDLED;
default:
@@ -629,14 +718,21 @@
}
class WaitBeforeStartState extends WaitBeforeOtherState {
- public WaitBeforeStartState(State otherState) {
+ WaitBeforeStartState(State otherState) {
super();
mOtherState = otherState;
}
}
class WaitBeforeRenewalState extends WaitBeforeOtherState {
- public WaitBeforeRenewalState(State otherState) {
+ WaitBeforeRenewalState(State otherState) {
+ super();
+ mOtherState = otherState;
+ }
+ }
+
+ class WaitBeforeObtainingConfigurationState extends WaitBeforeOtherState {
+ WaitBeforeObtainingConfigurationState(State otherState) {
super();
mOtherState = otherState;
}
@@ -782,6 +878,69 @@
}
}
+ class ObtainingConfigurationState extends LoggingState {
+ @Override
+ public void enter() {
+ super.enter();
+
+ // Set a timeout for retrieving network attributes operation
+ sendMessageDelayed(EVENT_CONFIGURATION_TIMEOUT, IPMEMORYSTORE_TIMEOUT_MS);
+
+ final OnNetworkAttributesRetrievedListener listener = (status, l2Key, attributes) -> {
+ if (null == attributes || null == attributes.assignedV4Address) {
+ if (!status.isSuccess()) {
+ Log.e(TAG, "Error retrieving network attributes: " + status);
+ }
+ sendMessage(EVENT_CONFIGURATION_INVALID);
+ return;
+ }
+ sendMessage(EVENT_CONFIGURATION_OBTAINED, attributes);
+ };
+ mIpMemoryStore.retrieveNetworkAttributes(mL2Key, listener);
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ super.processMessage(message);
+ switch (message.what) {
+ case EVENT_CONFIGURATION_INVALID:
+ case EVENT_CONFIGURATION_TIMEOUT:
+ transitionTo(mDhcpInitState);
+ return HANDLED;
+
+ case EVENT_CONFIGURATION_OBTAINED:
+ final long currentTime = System.currentTimeMillis();
+ NetworkAttributes attributes = (NetworkAttributes) message.obj;
+ if (DBG) {
+ Log.d(TAG, "l2key: " + mL2Key
+ + " lease address: " + attributes.assignedV4Address
+ + " lease expiry: " + attributes.assignedV4AddressExpiry
+ + " current time: " + currentTime);
+ }
+ if (currentTime >= attributes.assignedV4AddressExpiry) {
+ // Lease has expired.
+ transitionTo(mDhcpInitState);
+ return HANDLED;
+ }
+ mLastAssignedIpv4Address = attributes.assignedV4Address;
+ mLastAssignedIpv4AddressExpiry = attributes.assignedV4AddressExpiry;
+ transitionTo(mDhcpInitRebootState);
+ return HANDLED;
+
+ default:
+ deferMessage(message);
+ return HANDLED;
+ }
+ }
+
+ @Override
+ public void exit() {
+ removeMessages(EVENT_CONFIGURATION_INVALID);
+ removeMessages(EVENT_CONFIGURATION_TIMEOUT);
+ removeMessages(EVENT_CONFIGURATION_OBTAINED);
+ }
+ }
+
class DhcpInitState extends PacketRetransmittingState {
public DhcpInitState() {
super();
@@ -1050,7 +1209,35 @@
}
}
- class DhcpInitRebootState extends LoggingState {
+ class DhcpInitRebootState extends DhcpRequestingState {
+ @Override
+ public void enter() {
+ super.enter();
+ startNewTransaction();
+ }
+
+ // RFC 2131 4.3.2 describes generated DHCPREQUEST message during
+ // INIT-REBOOT state:
+ // 'server identifier' MUST NOT be filled in, 'requested IP address'
+ // option MUST be filled in with client's notion of its previously
+ // assigned address. 'ciaddr' MUST be zero. The client is seeking to
+ // verify a previously allocated, cached configuration. Server SHOULD
+ // send a DHCPNAK message to the client if the 'requested IP address'
+ // is incorrect, or is on the wrong network.
+ @Override
+ protected boolean sendPacket() {
+ return sendRequestPacket(
+ INADDR_ANY, // ciaddr
+ mLastAssignedIpv4Address, // DHCP_REQUESTED_IP
+ null, // DHCP_SERVER_IDENTIFIER
+ INADDR_BROADCAST); // packet destination address
+ }
+
+ @Override
+ public void exit() {
+ mLastAssignedIpv4Address = null;
+ mLastAssignedIpv4AddressExpiry = 0;
+ }
}
class DhcpRebootingState extends LoggingState {
diff --git a/src/android/net/ip/IpClient.java b/src/android/net/ip/IpClient.java
index 266b1b0..e1b5e9f 100644
--- a/src/android/net/ip/IpClient.java
+++ b/src/android/net/ip/IpClient.java
@@ -78,7 +78,6 @@
import java.util.function.Predicate;
import java.util.stream.Collectors;
-
/**
* IpClient
*
@@ -394,6 +393,14 @@
public INetd getNetd(Context context) {
return INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE));
}
+
+ /**
+ * Get a IpMemoryStore instance.
+ */
+ public NetworkStackIpMemoryStore getIpMemoryStore(Context context,
+ NetworkStackServiceManager nssManager) {
+ return new NetworkStackIpMemoryStore(context, nssManager.getIpMemoryStoreService());
+ }
}
public IpClient(Context context, String ifName, IIpClientCallbacks callback,
@@ -418,8 +425,7 @@
mShutdownLatch = new CountDownLatch(1);
mCm = mContext.getSystemService(ConnectivityManager.class);
mObserverRegistry = observerRegistry;
- mIpMemoryStore =
- new NetworkStackIpMemoryStore(context, nssManager.getIpMemoryStoreService());
+ mIpMemoryStore = deps.getIpMemoryStore(context, nssManager);
sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag));
mLog = sSmLogs.get(mInterfaceName);
@@ -934,7 +940,7 @@
// accompanying code in IpReachabilityMonitor) is unreachable.
final boolean ignoreIPv6ProvisioningLoss =
mConfiguration != null && mConfiguration.mUsingMultinetworkPolicyTracker
- && mCm.shouldAvoidBadWifi();
+ && !mCm.shouldAvoidBadWifi();
// Additionally:
//
@@ -1124,6 +1130,7 @@
}
mCallback.onNewDhcpResults(dhcpResults);
maybeSaveNetworkToIpMemoryStore();
+
dispatchCallback(delta, newLp);
}
@@ -1182,9 +1189,10 @@
}
} else {
// Start DHCPv4.
- mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceParams);
+ mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceParams,
+ mIpMemoryStore);
mDhcpClient.registerForPreDhcpNotification();
- mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP);
+ mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP, mL2Key);
}
return true;
@@ -1369,7 +1377,6 @@
@Override
public void enter() {
mStartTimeMillis = SystemClock.elapsedRealtime();
-
if (mConfiguration.mProvisioningTimeoutMs > 0) {
final long alarmTime = SystemClock.elapsedRealtime()
+ mConfiguration.mProvisioningTimeoutMs;
@@ -1426,7 +1433,6 @@
case EVENT_PROVISIONING_TIMEOUT:
handleProvisioningFailure();
break;
-
default:
// It's safe to process messages out of order because the
// only message that can both
diff --git a/src/android/net/ip/IpNeighborMonitor.java b/src/android/net/ip/IpNeighborMonitor.java
index 6ae9a2b..803f2e6 100644
--- a/src/android/net/ip/IpNeighborMonitor.java
+++ b/src/android/net/ip/IpNeighborMonitor.java
@@ -185,12 +185,6 @@
break;
}
- final int srcPortId = nlMsg.getHeader().nlmsg_pid;
- if (srcPortId != 0) {
- mLog.e("non-kernel source portId: " + Integer.toUnsignedLong(srcPortId));
- break;
- }
-
if (nlMsg instanceof NetlinkErrorMessage) {
mLog.e("netlink error: " + nlMsg);
continue;
diff --git a/src/android/net/util/NetworkStackUtils.java b/src/android/net/util/NetworkStackUtils.java
index 9bf1b96..978cedb 100644
--- a/src/android/net/util/NetworkStackUtils.java
+++ b/src/android/net/util/NetworkStackUtils.java
@@ -108,6 +108,11 @@
*/
public static final int CAPTIVE_PORTAL_MODE_AVOID = 2;
+ /**
+ * Experiment flag to enable DHCP INIT-REBOOT state, default value is false.
+ */
+ public static final String DHCP_INIT_REBOOT_ENABLED = "dhcp_init_reboot_enabled";
+
static {
System.loadLibrary("networkstackutilsjni");
}
diff --git a/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java b/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
index a538a5b..4896ef2 100644
--- a/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
+++ b/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
@@ -73,7 +73,8 @@
public static final String COLTYPE_ASSIGNEDV4ADDRESS = "INTEGER";
public static final String COLNAME_ASSIGNEDV4ADDRESSEXPIRY = "assignedV4AddressExpiry";
- // The lease expiry timestamp in uint of milliseconds
+ // The lease expiry timestamp in uint of milliseconds since the Epoch. Long.MAX_VALUE
+ // is used to represent "infinite lease".
public static final String COLTYPE_ASSIGNEDV4ADDRESSEXPIRY = "BIGINT";
// Please note that the group hint is only a *hint*, hence its name. The client can offer
diff --git a/tests/unit/src/android/net/ip/IpClientTest.java b/tests/unit/src/android/net/ip/IpClientTest.java
index 5f80006..1d6ce6e 100644
--- a/tests/unit/src/android/net/ip/IpClientTest.java
+++ b/tests/unit/src/android/net/ip/IpClientTest.java
@@ -55,6 +55,7 @@
import com.android.server.NetworkObserver;
import com.android.server.NetworkObserverRegistry;
import com.android.server.NetworkStackService;
+import com.android.server.connectivity.ipmemorystore.IpMemoryStoreService;
import org.junit.Before;
import org.junit.Test;
@@ -69,6 +70,7 @@
import java.util.List;
import java.util.Set;
+
/**
* Tests for IpClient.
*/
@@ -98,6 +100,8 @@
@Mock private ContentResolver mContentResolver;
@Mock private NetworkStackService.NetworkStackServiceManager mNetworkStackServiceManager;
@Mock private NetworkStackIpMemoryStore mIpMemoryStore;
+ @Mock private IpMemoryStoreService mIpMemoryStoreService;
+ @Mock private InterfaceParams mInterfaceParams;
private NetworkObserver mObserver;
private InterfaceParams mIfParams;
@@ -113,6 +117,11 @@
when(mResources.getInteger(R.integer.config_networkAvoidBadWifi))
.thenReturn(DEFAULT_AVOIDBADWIFI_CONFIG_VALUE);
when(mContext.getContentResolver()).thenReturn(mContentResolver);
+ when(mNetworkStackServiceManager.getIpMemoryStoreService())
+ .thenReturn(mIpMemoryStoreService);
+ when(mDependencies.getInterfaceParams(any())).thenReturn(mInterfaceParams);
+ when(mDependencies.getIpMemoryStore(mContext, mNetworkStackServiceManager))
+ .thenReturn(mIpMemoryStore);
mIfParams = null;
}
diff --git a/tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java b/tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
index 64fe3a6..ba86fcf 100644
--- a/tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
+++ b/tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -224,7 +224,7 @@
};
}
- /** Helper method to make an IOnSameNetworkResponseListener */
+ /** Helper method to make an IOnSameL3NetworkResponseListener */
private interface OnSameL3NetworkResponseListener {
void onSameL3NetworkResponse(Status status, SameL3NetworkResponse answer);
}