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

Commit f928c1e4 authored by Benedict Wong's avatar Benedict Wong Committed by Gerrit Code Review
Browse files

Merge changes from topic "xfrmi-support"

* changes:
  Cleanup and update comments SA mark disabling comments
  Add XFRM-I support to IpSecService
  Disable attempted updating of SA marks
parents 1c66fd2d b2920572
Loading
Loading
Loading
Loading
+32 −4
Original line number Diff line number Diff line
@@ -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
     *
     * <p>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
     *
     * <p>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);
    }
}
+70 −29
Original line number Diff line number Diff line
@@ -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,14 +1760,35 @@ 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.
                // 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()
@@ -1755,12 +1796,12 @@ public class IpSecService extends IIpSecService.Stub {
                                callingUid,
                                selAddrFamily,
                                direction,
                                    tunnelInterfaceInfo.getLocalAddress(),
                                    tunnelInterfaceInfo.getRemoteAddress(),
                                    transformInfo.getSpiRecord().getSpi(),
                                    mark,
                                    0xffffffff);
                }
                                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)
+2 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ public class IpSecConfigTest {
        assertNull(c.getEncryption());
        assertNull(c.getAuthentication());
        assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getSpiResourceId());
        assertEquals(0, c.getXfrmInterfaceId());
    }

    private IpSecConfig getSampleConfig() {
@@ -77,6 +78,7 @@ public class IpSecConfigTest {
        c.setNattKeepaliveInterval(42);
        c.setMarkValue(12);
        c.setMarkMask(23);
        c.setXfrmInterfaceId(34);

        return c;
    }
+50 −4
Original line number Diff line number Diff line
@@ -71,6 +71,9 @@ public class IpSecServiceParameterizedTest {
    private final LinkAddress mLocalInnerAddress;
    private final int mFamily;

    private static final int[] ADDRESS_FAMILIES =
            new int[] {AF_INET, AF_INET6};

    @Parameterized.Parameters
    public static Collection ipSecConfigs() {
        return Arrays.asList(
@@ -196,6 +199,7 @@ public class IpSecServiceParameterizedTest {
                        anyString(),
                        eq(TEST_SPI),
                        anyInt(),
                        anyInt(),
                        anyInt());

        // Verify quota and RefcountedResource objects cleaned up
@@ -231,6 +235,7 @@ public class IpSecServiceParameterizedTest {
                        anyString(),
                        eq(TEST_SPI),
                        anyInt(),
                        anyInt(),
                        anyInt());

        // Verify quota and RefcountedResource objects cleaned up
@@ -304,7 +309,8 @@ public class IpSecServiceParameterizedTest {
                        eq((authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0),
                        eq(config.getEncapType()),
                        eq(encapSocketPort),
                        eq(config.getEncapRemotePort()));
                        eq(config.getEncapRemotePort()),
                        eq(config.getXfrmInterfaceId()));
    }

    @Test
@@ -430,6 +436,7 @@ public class IpSecServiceParameterizedTest {
                        anyString(),
                        eq(TEST_SPI),
                        anyInt(),
                        anyInt(),
                        anyInt());
        // quota is not released until the SPI is released by the Transform
        assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
@@ -452,6 +459,7 @@ public class IpSecServiceParameterizedTest {
                        anyString(),
                        eq(TEST_SPI),
                        anyInt(),
                        anyInt(),
                        anyInt());

        // Verify quota and RefcountedResource objects cleaned up
@@ -469,6 +477,7 @@ public class IpSecServiceParameterizedTest {
                        anyString(),
                        anyInt(),
                        anyInt(),
                        anyInt(),
                        anyInt());
        assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);

@@ -504,6 +513,7 @@ public class IpSecServiceParameterizedTest {
                        anyString(),
                        eq(TEST_SPI),
                        anyInt(),
                        anyInt(),
                        anyInt());

        // Verify quota and RefcountedResource objects cleaned up
@@ -572,11 +582,12 @@ public class IpSecServiceParameterizedTest {

        assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
        verify(mMockNetd)
                .addVirtualTunnelInterface(
                .ipSecAddTunnelInterface(
                        eq(createTunnelResp.interfaceName),
                        eq(mSourceAddr),
                        eq(mDestinationAddr),
                        anyInt(),
                        anyInt(),
                        anyInt());
    }

@@ -591,7 +602,7 @@ public class IpSecServiceParameterizedTest {

        // Verify quota and RefcountedResource objects cleaned up
        assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
        verify(mMockNetd).removeVirtualTunnelInterface(eq(createTunnelResp.interfaceName));
        verify(mMockNetd).ipSecRemoveTunnelInterface(eq(createTunnelResp.interfaceName));
        try {
            userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
                    createTunnelResp.resourceId);
@@ -614,7 +625,7 @@ public class IpSecServiceParameterizedTest {

        // Verify quota and RefcountedResource objects cleaned up
        assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
        verify(mMockNetd).removeVirtualTunnelInterface(eq(createTunnelResp.interfaceName));
        verify(mMockNetd).ipSecRemoveTunnelInterface(eq(createTunnelResp.interfaceName));
        try {
            userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
                    createTunnelResp.resourceId);
@@ -623,6 +634,41 @@ public class IpSecServiceParameterizedTest {
        }
    }

    @Test
    public void testApplyTunnelModeTransform() throws Exception {
        IpSecConfig ipSecConfig = new IpSecConfig();
        ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
        addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
        addAuthAndCryptToIpSecConfig(ipSecConfig);

        IpSecTransformResponse createTransformResp =
                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
        IpSecTunnelInterfaceResponse createTunnelResp =
                createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");

        int transformResourceId = createTransformResp.resourceId;
        int tunnelResourceId = createTunnelResp.resourceId;
        mIpSecService.applyTunnelModeTransform(tunnelResourceId, IpSecManager.DIRECTION_OUT,
                transformResourceId, "blessedPackage");

        for (int selAddrFamily : ADDRESS_FAMILIES) {
            verify(mMockNetd)
                    .ipSecUpdateSecurityPolicy(
                            eq(mUid),
                            eq(selAddrFamily),
                            eq(IpSecManager.DIRECTION_OUT),
                            anyString(),
                            anyString(),
                            eq(TEST_SPI),
                            anyInt(), // iKey/oKey
                            anyInt(), // mask
                            eq(tunnelResourceId));
        }

        ipSecConfig.setXfrmInterfaceId(tunnelResourceId);
        verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
    }

    @Test
    public void testAddRemoveAddressFromTunnelInterface() throws Exception {
        for (String pkgName : new String[]{"blessedPackage", "systemPackage"}) {