diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index 8599f47c62..3552655983 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -65,10 +65,13 @@ public final class IpSecConfig implements Parcelable { // An interval, in seconds between the NattKeepalive packets private int mNattKeepaliveInterval; - // XFRM mark and mask + // XFRM mark and mask; defaults to 0 (no mark/mask) private int mMarkValue; private int mMarkMask; + // XFRM interface id + private int mXfrmInterfaceId; + /** Set the mode for this IPsec transform */ public void setMode(int mode) { mMode = mode; @@ -125,14 +128,30 @@ public final class IpSecConfig implements Parcelable { mNattKeepaliveInterval = interval; } + /** + * Sets the mark value + * + *

Internal (System server) use only. Marks passed in by users will be overwritten or + * ignored. + */ public void setMarkValue(int mark) { mMarkValue = mark; } + /** + * Sets the mark mask + * + *

Internal (System server) use only. Marks passed in by users will be overwritten or + * ignored. + */ public void setMarkMask(int mask) { mMarkMask = mask; } + public void setXfrmInterfaceId(int xfrmInterfaceId) { + mXfrmInterfaceId = xfrmInterfaceId; + } + // Transport or Tunnel public int getMode() { return mMode; @@ -190,6 +209,10 @@ public final class IpSecConfig implements Parcelable { return mMarkMask; } + public int getXfrmInterfaceId() { + return mXfrmInterfaceId; + } + // Parcelable Methods @Override @@ -213,6 +236,7 @@ public final class IpSecConfig implements Parcelable { out.writeInt(mNattKeepaliveInterval); out.writeInt(mMarkValue); out.writeInt(mMarkMask); + out.writeInt(mXfrmInterfaceId); } @VisibleForTesting @@ -235,6 +259,7 @@ public final class IpSecConfig implements Parcelable { mNattKeepaliveInterval = c.mNattKeepaliveInterval; mMarkValue = c.mMarkValue; mMarkMask = c.mMarkMask; + mXfrmInterfaceId = c.mXfrmInterfaceId; } private IpSecConfig(Parcel in) { @@ -255,6 +280,7 @@ public final class IpSecConfig implements Parcelable { mNattKeepaliveInterval = in.readInt(); mMarkValue = in.readInt(); mMarkMask = in.readInt(); + mXfrmInterfaceId = in.readInt(); } @Override @@ -289,6 +315,8 @@ public final class IpSecConfig implements Parcelable { .append(mMarkValue) .append(", mMarkMask=") .append(mMarkMask) + .append(", mXfrmInterfaceId=") + .append(mXfrmInterfaceId) .append("}"); return strBuilder.toString(); @@ -320,10 +348,10 @@ public final class IpSecConfig implements Parcelable { && lhs.mNattKeepaliveInterval == rhs.mNattKeepaliveInterval && lhs.mSpiResourceId == rhs.mSpiResourceId && IpSecAlgorithm.equals(lhs.mEncryption, rhs.mEncryption) - && IpSecAlgorithm.equals( - lhs.mAuthenticatedEncryption, rhs.mAuthenticatedEncryption) + && IpSecAlgorithm.equals(lhs.mAuthenticatedEncryption, rhs.mAuthenticatedEncryption) && IpSecAlgorithm.equals(lhs.mAuthentication, rhs.mAuthentication) && lhs.mMarkValue == rhs.mMarkValue - && lhs.mMarkMask == rhs.mMarkMask); + && lhs.mMarkMask == rhs.mMarkMask + && lhs.mXfrmInterfaceId == rhs.mXfrmInterfaceId); } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 8c25917c74..7ee3d3b3bd 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -24,6 +24,7 @@ import static android.system.OsConstants.AF_UNSPEC; import static android.system.OsConstants.EINVAL; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; + import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; @@ -62,6 +63,8 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; +import libcore.io.IoUtils; + import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; @@ -73,8 +76,6 @@ import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; -import libcore.io.IoUtils; - /** * A service to manage multiple clients that want to access the IpSec API. The service is * responsible for maintaining a list of clients and managing the resources (and related quotas) @@ -621,7 +622,8 @@ public class IpSecService extends IIpSecService.Stub { mConfig.getDestinationAddress(), spi, mConfig.getMarkValue(), - mConfig.getMarkMask()); + mConfig.getMarkMask(), + mConfig.getXfrmInterfaceId()); } catch (RemoteException | ServiceSpecificException e) { Log.e(TAG, "Failed to delete SA with ID: " + mResourceId, e); } @@ -683,7 +685,8 @@ public class IpSecService extends IIpSecService.Stub { mSrvConfig .getNetdInstance() .ipSecDeleteSecurityAssociation( - uid, mSourceAddress, mDestinationAddress, mSpi, 0, 0); + uid, mSourceAddress, mDestinationAddress, mSpi, 0 /* mark */, + 0 /* mask */, 0 /* if_id */); } } catch (ServiceSpecificException | RemoteException e) { Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e); @@ -795,6 +798,8 @@ public class IpSecService extends IIpSecService.Stub { private final int mIkey; private final int mOkey; + private final int mIfId; + TunnelInterfaceRecord( int resourceId, String interfaceName, @@ -802,7 +807,8 @@ public class IpSecService extends IIpSecService.Stub { String localAddr, String remoteAddr, int ikey, - int okey) { + int okey, + int intfId) { super(resourceId); mInterfaceName = interfaceName; @@ -811,6 +817,7 @@ public class IpSecService extends IIpSecService.Stub { mRemoteAddress = remoteAddr; mIkey = ikey; mOkey = okey; + mIfId = intfId; } /** always guarded by IpSecService#this */ @@ -821,7 +828,7 @@ public class IpSecService extends IIpSecService.Stub { // Delete global policies try { final INetd netd = mSrvConfig.getNetdInstance(); - netd.removeVirtualTunnelInterface(mInterfaceName); + netd.ipSecRemoveTunnelInterface(mInterfaceName); for (int selAddrFamily : ADDRESS_FAMILIES) { netd.ipSecDeleteSecurityPolicy( @@ -829,13 +836,15 @@ public class IpSecService extends IIpSecService.Stub { selAddrFamily, IpSecManager.DIRECTION_OUT, mOkey, - 0xffffffff); + 0xffffffff, + mIfId); netd.ipSecDeleteSecurityPolicy( uid, selAddrFamily, IpSecManager.DIRECTION_IN, mIkey, - 0xffffffff); + 0xffffffff, + mIfId); } } catch (ServiceSpecificException | RemoteException e) { Log.e( @@ -877,6 +886,10 @@ public class IpSecService extends IIpSecService.Stub { return mOkey; } + public int getIfId() { + return mIfId; + } + @Override protected ResourceTracker getResourceTracker() { return getUserRecord().mTunnelQuotaTracker; @@ -1286,7 +1299,7 @@ public class IpSecService extends IIpSecService.Stub { // Add inbound/outbound global policies // (use reqid = 0) final INetd netd = mSrvConfig.getNetdInstance(); - netd.addVirtualTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey); + netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId); for (int selAddrFamily : ADDRESS_FAMILIES) { // Always send down correct local/remote addresses for template. @@ -1298,7 +1311,8 @@ public class IpSecService extends IIpSecService.Stub { remoteAddr, 0, okey, - 0xffffffff); + 0xffffffff, + resourceId); netd.ipSecAddSecurityPolicy( callerUid, selAddrFamily, @@ -1307,7 +1321,8 @@ public class IpSecService extends IIpSecService.Stub { localAddr, 0, ikey, - 0xffffffff); + 0xffffffff, + resourceId); } userRecord.mTunnelInterfaceRecords.put( @@ -1320,7 +1335,8 @@ public class IpSecService extends IIpSecService.Stub { localAddr, remoteAddr, ikey, - okey), + okey, + resourceId), binder)); return new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName); } catch (RemoteException e) { @@ -1523,6 +1539,9 @@ public class IpSecService extends IIpSecService.Stub { throw new IllegalArgumentException( "Invalid IpSecTransform.mode: " + config.getMode()); } + + config.setMarkValue(0); + config.setMarkMask(0); } private static final String TUNNEL_OP = AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS; @@ -1584,7 +1603,8 @@ public class IpSecService extends IIpSecService.Stub { (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0, encapType, encapLocalPort, - encapRemotePort); + encapRemotePort, + c.getXfrmInterfaceId()); } /** @@ -1740,27 +1760,48 @@ public class IpSecService extends IIpSecService.Stub { : tunnelInterfaceInfo.getIkey(); try { - c.setMarkValue(mark); - c.setMarkMask(0xffffffff); + // Default to using the invalid SPI of 0 for inbound SAs. This allows policies to skip + // SPI matching as part of the template resolution. + int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; + c.setXfrmInterfaceId(tunnelInterfaceInfo.getIfId()); + + // TODO: enable this when UPDSA supports updating marks. Adding kernel support upstream + // (and backporting) would allow us to narrow the mark space, and ensure that the SA + // and SPs have matching marks (as VTI are meant to be built). + // Currently update does nothing with marks. Leave empty (defaulting to 0) to ensure the + // config matches the actual allocated resources in the kernel. + // All SAs will have zero marks (from creation time), and any policy that matches the + // same src/dst could match these SAs. Non-IpSecService governed processes that + // establish floating policies with the same src/dst may result in undefined + // behavior. This is generally limited to vendor code due to the permissions + // (CAP_NET_ADMIN) required. + // + // c.setMarkValue(mark); + // c.setMarkMask(0xffffffff); if (direction == IpSecManager.DIRECTION_OUT) { // Set output mark via underlying network (output only) c.setNetwork(tunnelInterfaceInfo.getUnderlyingNetwork()); - // If outbound, also add SPI to the policy. - for (int selAddrFamily : ADDRESS_FAMILIES) { - mSrvConfig - .getNetdInstance() - .ipSecUpdateSecurityPolicy( - callingUid, - selAddrFamily, - direction, - tunnelInterfaceInfo.getLocalAddress(), - tunnelInterfaceInfo.getRemoteAddress(), - transformInfo.getSpiRecord().getSpi(), - mark, - 0xffffffff); - } + // Set outbound SPI only. We want inbound to use any valid SA (old, new) on rekeys, + // but want to guarantee outbound packets are sent over the new SA. + spi = transformInfo.getSpiRecord().getSpi(); + } + + // Always update the policy with the relevant XFRM_IF_ID + for (int selAddrFamily : ADDRESS_FAMILIES) { + mSrvConfig + .getNetdInstance() + .ipSecUpdateSecurityPolicy( + callingUid, + selAddrFamily, + direction, + transformInfo.getConfig().getSourceAddress(), + transformInfo.getConfig().getDestinationAddress(), + spi, // If outbound, also add SPI to the policy. + mark, // Must always set policy mark; ikey/okey for VTIs + 0xffffffff, + c.getXfrmInterfaceId()); } // Update SA with tunnel mark (ikey or okey based on direction)