Merge changes Ibff278a6,If6d537a3

* changes:
  Revert "Add NATT keepalive resources and methods into IpSecService"
  Revert "[KA11] Verify fd ownership and allocate resource for NattKeepalive"
This commit is contained in:
Treehugger Robot
2019-05-10 01:42:26 +00:00
committed by Gerrit Code Review
4 changed files with 27 additions and 211 deletions

View File

@@ -27,7 +27,6 @@ import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.ConnectivityManager.isNetworkTypeValid;
import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY; import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY;
import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID; import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID;
import static android.net.IpSecManager.INVALID_RESOURCE_ID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL; import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND; import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
@@ -6859,7 +6858,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
enforceKeepalivePermission(); enforceKeepalivePermission();
mKeepaliveTracker.startNattKeepalive( mKeepaliveTracker.startNattKeepalive(
getNetworkAgentInfoForNetwork(network), null /* fd */, getNetworkAgentInfoForNetwork(network), null /* fd */,
INVALID_RESOURCE_ID /* Unused */,
intervalSeconds, cb, intervalSeconds, cb,
srcAddr, srcPort, dstAddr, NattSocketKeepalive.NATT_PORT); srcAddr, srcPort, dstAddr, NattSocketKeepalive.NATT_PORT);
} }

View File

@@ -17,7 +17,6 @@
package com.android.server.connectivity; package com.android.server.connectivity;
import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.IpSecManager.INVALID_RESOURCE_ID;
import static android.net.NattSocketKeepalive.NATT_PORT; import static android.net.NattSocketKeepalive.NATT_PORT;
import static android.net.NetworkAgent.CMD_ADD_KEEPALIVE_PACKET_FILTER; import static android.net.NetworkAgent.CMD_ADD_KEEPALIVE_PACKET_FILTER;
import static android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER; import static android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER;
@@ -38,7 +37,6 @@ import static android.net.SocketKeepalive.SUCCESS;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.content.Context; import android.content.Context;
import android.net.IIpSecService;
import android.net.ISocketKeepaliveCallback; import android.net.ISocketKeepaliveCallback;
import android.net.KeepalivePacketData; import android.net.KeepalivePacketData;
import android.net.NattKeepalivePacketData; import android.net.NattKeepalivePacketData;
@@ -54,7 +52,6 @@ import android.os.IBinder;
import android.os.Message; import android.os.Message;
import android.os.Process; import android.os.Process;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager;
import android.system.ErrnoException; import android.system.ErrnoException;
import android.system.Os; import android.system.Os;
import android.util.Log; import android.util.Log;
@@ -92,14 +89,11 @@ public class KeepaliveTracker {
private final TcpKeepaliveController mTcpController; private final TcpKeepaliveController mTcpController;
@NonNull @NonNull
private final Context mContext; private final Context mContext;
@NonNull
private final IIpSecService mIpSec;
public KeepaliveTracker(Context context, Handler handler) { public KeepaliveTracker(Context context, Handler handler) {
mConnectivityServiceHandler = handler; mConnectivityServiceHandler = handler;
mTcpController = new TcpKeepaliveController(handler); mTcpController = new TcpKeepaliveController(handler);
mContext = context; mContext = context;
mIpSec = IIpSecService.Stub.asInterface(ServiceManager.getService(Context.IPSEC_SERVICE));
} }
/** /**
@@ -118,10 +112,6 @@ public class KeepaliveTracker {
private final int mType; private final int mType;
private final FileDescriptor mFd; private final FileDescriptor mFd;
private final int mEncapSocketResourceId;
// Stores the NATT keepalive resource ID returned by IpSecService.
private int mNattIpsecResourceId = INVALID_RESOURCE_ID;
public static final int TYPE_NATT = 1; public static final int TYPE_NATT = 1;
public static final int TYPE_TCP = 2; public static final int TYPE_TCP = 2;
@@ -150,8 +140,7 @@ public class KeepaliveTracker {
@NonNull KeepalivePacketData packet, @NonNull KeepalivePacketData packet,
int interval, int interval,
int type, int type,
@Nullable FileDescriptor fd, @Nullable FileDescriptor fd) throws InvalidSocketException {
int encapSocketResourceId) throws InvalidSocketException {
mCallback = callback; mCallback = callback;
mPid = Binder.getCallingPid(); mPid = Binder.getCallingPid();
mUid = Binder.getCallingUid(); mUid = Binder.getCallingUid();
@@ -162,9 +151,6 @@ public class KeepaliveTracker {
mInterval = interval; mInterval = interval;
mType = type; mType = type;
mEncapSocketResourceId = encapSocketResourceId;
mNattIpsecResourceId = INVALID_RESOURCE_ID;
// For SocketKeepalive, a dup of fd is kept in mFd so the source port from which the // For SocketKeepalive, a dup of fd is kept in mFd so the source port from which the
// keepalives are sent cannot be reused by another app even if the fd gets closed by // keepalives are sent cannot be reused by another app even if the fd gets closed by
// the user. A null is acceptable here for backward compatibility of PacketKeepalive // the user. A null is acceptable here for backward compatibility of PacketKeepalive
@@ -220,8 +206,6 @@ public class KeepaliveTracker {
+ IpUtils.addressAndPortToString(mPacket.dstAddress, mPacket.dstPort) + IpUtils.addressAndPortToString(mPacket.dstAddress, mPacket.dstPort)
+ " interval=" + mInterval + " interval=" + mInterval
+ " uid=" + mUid + " pid=" + mPid + " privileged=" + mPrivileged + " uid=" + mUid + " pid=" + mPid + " privileged=" + mPrivileged
+ " nattIpsecRId=" + mNattIpsecResourceId
+ " encapSocketRId=" + mEncapSocketResourceId
+ " packetData=" + HexDump.toHexString(mPacket.getPacket()) + " packetData=" + HexDump.toHexString(mPacket.getPacket())
+ " ]"; + " ]";
} }
@@ -278,51 +262,6 @@ public class KeepaliveTracker {
return SUCCESS; return SUCCESS;
} }
private int checkAndLockNattKeepaliveResource() {
// Check that apps should be either privileged or fill in an ipsec encapsulated socket
// resource id.
if (mEncapSocketResourceId == INVALID_RESOURCE_ID) {
if (mPrivileged) {
return SUCCESS;
} else {
// Invalid access.
return ERROR_INVALID_SOCKET;
}
}
// Check if the ipsec encapsulated socket resource id is registered.
final HashMap<Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(mNai);
if (networkKeepalives == null) {
return ERROR_INVALID_NETWORK;
}
for (KeepaliveInfo ki : networkKeepalives.values()) {
if (ki.mEncapSocketResourceId == mEncapSocketResourceId
&& ki.mNattIpsecResourceId != INVALID_RESOURCE_ID) {
Log.d(TAG, "Registered resource found on keepalive " + mSlot
+ " when verify NATT socket with uid=" + mUid + " rid="
+ mEncapSocketResourceId);
return ERROR_INVALID_SOCKET;
}
}
// Ensure that the socket is created by IpSecService, and lock the resource that is
// preserved by IpSecService. If succeed, a resource id is stored to keep tracking
// the resource preserved by IpSecServce and must be released when stopping keepalive.
try {
mNattIpsecResourceId =
mIpSec.lockEncapSocketForNattKeepalive(mEncapSocketResourceId, mUid);
return SUCCESS;
} catch (IllegalArgumentException e) {
// The UID specified does not own the specified UDP encapsulation socket.
Log.d(TAG, "Failed to verify NATT socket with uid=" + mUid + " rid="
+ mEncapSocketResourceId + ": " + e);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling lockEncapSocketForNattKeepalive with "
+ this.toString(), e);
}
return ERROR_INVALID_SOCKET;
}
private int isValid() { private int isValid() {
synchronized (mNai) { synchronized (mNai) {
int error = checkInterval(); int error = checkInterval();
@@ -336,13 +275,6 @@ public class KeepaliveTracker {
void start(int slot) { void start(int slot) {
mSlot = slot; mSlot = slot;
int error = isValid(); int error = isValid();
// Check and lock ipsec resource needed by natt kepalive. This should be only called
// once per keepalive.
if (error == SUCCESS && mType == TYPE_NATT) {
error = checkAndLockNattKeepaliveResource();
}
if (error == SUCCESS) { if (error == SUCCESS) {
Log.d(TAG, "Starting keepalive " + mSlot + " on " + mNai.name()); Log.d(TAG, "Starting keepalive " + mSlot + " on " + mNai.name());
switch (mType) { switch (mType) {
@@ -418,20 +350,6 @@ public class KeepaliveTracker {
} }
} }
// Release the resource held by keepalive in IpSecService.
if (mNattIpsecResourceId != INVALID_RESOURCE_ID) {
if (mType != TYPE_NATT) {
Log.wtf(TAG, "natt ipsec resource held by incorrect keepalive "
+ this.toString());
}
try {
mIpSec.releaseNattKeepalive(mNattIpsecResourceId, mUid);
} catch (RemoteException e) {
Log.wtf(TAG, "error calling releaseNattKeepalive with " + this.toString(), e);
}
mNattIpsecResourceId = INVALID_RESOURCE_ID;
}
if (reason == SUCCESS) { if (reason == SUCCESS) {
try { try {
mCallback.onStopped(); mCallback.onStopped();
@@ -621,7 +539,6 @@ public class KeepaliveTracker {
**/ **/
public void startNattKeepalive(@Nullable NetworkAgentInfo nai, public void startNattKeepalive(@Nullable NetworkAgentInfo nai,
@Nullable FileDescriptor fd, @Nullable FileDescriptor fd,
int encapSocketResourceId,
int intervalSeconds, int intervalSeconds,
@NonNull ISocketKeepaliveCallback cb, @NonNull ISocketKeepaliveCallback cb,
@NonNull String srcAddrString, @NonNull String srcAddrString,
@@ -653,7 +570,7 @@ public class KeepaliveTracker {
KeepaliveInfo ki = null; KeepaliveInfo ki = null;
try { try {
ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds, ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds,
KeepaliveInfo.TYPE_NATT, fd, encapSocketResourceId); KeepaliveInfo.TYPE_NATT, fd);
} catch (InvalidSocketException | IllegalArgumentException | SecurityException e) { } catch (InvalidSocketException | IllegalArgumentException | SecurityException e) {
Log.e(TAG, "Fail to construct keepalive", e); Log.e(TAG, "Fail to construct keepalive", e);
notifyErrorCallback(cb, ERROR_INVALID_SOCKET); notifyErrorCallback(cb, ERROR_INVALID_SOCKET);
@@ -693,7 +610,7 @@ public class KeepaliveTracker {
KeepaliveInfo ki = null; KeepaliveInfo ki = null;
try { try {
ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds, ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds,
KeepaliveInfo.TYPE_TCP, fd, INVALID_RESOURCE_ID /* Unused */); KeepaliveInfo.TYPE_TCP, fd);
} catch (InvalidSocketException | IllegalArgumentException | SecurityException e) { } catch (InvalidSocketException | IllegalArgumentException | SecurityException e) {
Log.e(TAG, "Fail to construct keepalive e=" + e); Log.e(TAG, "Fail to construct keepalive e=" + e);
notifyErrorCallback(cb, ERROR_INVALID_SOCKET); notifyErrorCallback(cb, ERROR_INVALID_SOCKET);
@@ -712,12 +629,17 @@ public class KeepaliveTracker {
**/ **/
public void startNattKeepalive(@Nullable NetworkAgentInfo nai, public void startNattKeepalive(@Nullable NetworkAgentInfo nai,
@Nullable FileDescriptor fd, @Nullable FileDescriptor fd,
int encapSocketResourceId, int resourceId,
int intervalSeconds, int intervalSeconds,
@NonNull ISocketKeepaliveCallback cb, @NonNull ISocketKeepaliveCallback cb,
@NonNull String srcAddrString, @NonNull String srcAddrString,
@NonNull String dstAddrString, @NonNull String dstAddrString,
int dstPort) { int dstPort) {
// Ensure that the socket is created by IpSecService.
if (!isNattKeepaliveSocketValid(fd, resourceId)) {
notifyErrorCallback(cb, ERROR_INVALID_SOCKET);
}
// Get src port to adopt old API. // Get src port to adopt old API.
int srcPort = 0; int srcPort = 0;
try { try {
@@ -728,8 +650,23 @@ public class KeepaliveTracker {
} }
// Forward request to old API. // Forward request to old API.
startNattKeepalive(nai, fd, encapSocketResourceId, intervalSeconds, cb, srcAddrString, startNattKeepalive(nai, fd, intervalSeconds, cb, srcAddrString, srcPort,
srcPort, dstAddrString, dstPort); dstAddrString, dstPort);
}
/**
* Verify if the IPsec NAT-T file descriptor and resource Id hold for IPsec keepalive is valid.
**/
public static boolean isNattKeepaliveSocketValid(@Nullable FileDescriptor fd, int resourceId) {
// TODO: 1. confirm whether the fd is called from system api or created by IpSecService.
// 2. If the fd is created from the system api, check that it's bounded. And
// call dup to keep the fd open.
// 3. If the fd is created from IpSecService, check if the resource ID is valid. And
// hold the resource needed in IpSecService.
if (null == fd) {
return false;
}
return true;
} }
public void dump(IndentingPrintWriter pw) { public void dump(IndentingPrintWriter pw) {

View File

@@ -4269,25 +4269,6 @@ public class ConnectivityServiceTest {
callback.expectStarted(); callback.expectStarted();
ka.stop(); ka.stop();
callback.expectStopped(); callback.expectStopped();
// Check that the same NATT socket cannot be used by 2 keepalives.
try (SocketKeepalive ka2 = mCm.createSocketKeepalive(
myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
// Check that second keepalive cannot be started if the first one is running.
ka.start(validKaInterval);
callback.expectStarted();
ka2.start(validKaInterval);
callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
ka.stop();
callback.expectStopped();
// Check that second keepalive can be started/stopped normally if the first one is
// stopped.
ka2.start(validKaInterval);
callback.expectStarted();
ka2.stop();
callback.expectStopped();
}
} }
// Check that deleting the IP address stops the keepalive. // Check that deleting the IP address stops the keepalive.
@@ -4351,10 +4332,6 @@ public class ConnectivityServiceTest {
testSocket.close(); testSocket.close();
testSocket2.close(); testSocket2.close();
} }
// Check that the closed socket cannot be used to start keepalive.
ka.start(validKaInterval);
callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
} }
// Check that there is no port leaked after all keepalives and sockets are closed. // Check that there is no port leaked after all keepalives and sockets are closed.

View File

@@ -118,7 +118,6 @@ public class IpSecServiceTest {
INetd mMockNetd; INetd mMockNetd;
IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig; IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
IpSecService mIpSecService; IpSecService mIpSecService;
int mUid = Os.getuid();
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
@@ -666,99 +665,4 @@ public class IpSecServiceTest {
mIpSecService.releaseNetId(releasedNetId); mIpSecService.releaseNetId(releasedNetId);
assertEquals(releasedNetId, mIpSecService.reserveNetId()); assertEquals(releasedNetId, mIpSecService.reserveNetId());
} }
@Test
public void testLockEncapSocketForNattKeepalive() throws Exception {
IpSecUdpEncapResponse udpEncapResp =
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
// Verify no NATT keepalive records upon startup
IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
assertEquals(0, userRecord.mNattKeepaliveRecords.size());
int nattKeepaliveResourceId =
mIpSecService.lockEncapSocketForNattKeepalive(udpEncapResp.resourceId, mUid);
// Validate response, and record was added
assertNotEquals(IpSecManager.INVALID_RESOURCE_ID, nattKeepaliveResourceId);
assertEquals(1, userRecord.mNattKeepaliveRecords.size());
// Validate keepalive can be released and removed.
mIpSecService.releaseNattKeepalive(nattKeepaliveResourceId, mUid);
assertEquals(0, userRecord.mNattKeepaliveRecords.size());
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
}
@Test
public void testLockEncapSocketForNattKeepaliveInvalidUid() throws Exception {
IpSecUdpEncapResponse udpEncapResp =
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
// Verify no NATT keepalive records upon startup
IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
assertEquals(0, userRecord.mNattKeepaliveRecords.size());
try {
int nattKeepaliveResourceId =
mIpSecService.lockEncapSocketForNattKeepalive(
udpEncapResp.resourceId, mUid + 1);
fail("Expected SecurityException for invalid user");
} catch (SecurityException expected) {
}
// Validate keepalive was not added to lists
assertEquals(0, userRecord.mNattKeepaliveRecords.size());
}
@Test
public void testLockEncapSocketForNattKeepaliveInvalidResourceId() throws Exception {
// Verify no NATT keepalive records upon startup
IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
assertEquals(0, userRecord.mNattKeepaliveRecords.size());
try {
int nattKeepaliveResourceId =
mIpSecService.lockEncapSocketForNattKeepalive(12345, mUid);
fail("Expected IllegalArgumentException for invalid resource ID");
} catch (IllegalArgumentException expected) {
}
// Validate keepalive was not added to lists
assertEquals(0, userRecord.mNattKeepaliveRecords.size());
}
@Test
public void testEncapSocketReleasedBeforeKeepaliveReleased() throws Exception {
IpSecUdpEncapResponse udpEncapResp =
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
// Get encap socket record, verify initial starting refcount.
IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
IpSecService.RefcountedResource encapSocketRefcountedRecord =
userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(
udpEncapResp.resourceId);
assertEquals(1, encapSocketRefcountedRecord.mRefCount);
// Verify that the reference was added
int nattKeepaliveResourceId =
mIpSecService.lockEncapSocketForNattKeepalive(udpEncapResp.resourceId, mUid);
assertNotEquals(IpSecManager.INVALID_RESOURCE_ID, nattKeepaliveResourceId);
assertEquals(2, encapSocketRefcountedRecord.mRefCount);
// Close UDP encap socket, but expect the refcountedRecord to still have a reference.
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
assertEquals(1, encapSocketRefcountedRecord.mRefCount);
// Verify UDP encap socket cleaned up once reference is removed. Expect -1 if cleanup
// was properly completed.
mIpSecService.releaseNattKeepalive(nattKeepaliveResourceId, mUid);
assertEquals(-1, encapSocketRefcountedRecord.mRefCount);
}
} }