summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYan Yan <evitayan@google.com>2022-12-21 20:12:34 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-12-21 20:12:34 +0000
commit5fe4e44df09875ca5ee4ae41394870f8ffb3f8c4 (patch)
treed24527eed0e933ad34a60cdbe0a9f3daef971b1b
parent978b847fff1a97477a79ae3a65530a39d972f85a (diff)
parent4b58a6c59ba35f51a31e0b4d5432b42759b13e55 (diff)
downloadnetd-5fe4e44df09875ca5ee4ae41394870f8ffb3f8c4.tar.gz
Add XFRM_MIGRATE support in NetdNativeService am: f9c4679e6a am: 4b58a6c59b
Original change: https://android-review.googlesource.com/c/platform/system/netd/+/1582463 Change-Id: Ib9fac5eb14bddf61b5745033744aca2d9cd791a9 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--server/NetdNativeService.cpp10
-rw-r--r--server/NetdNativeService.h2
-rw-r--r--server/XfrmController.h2
-rw-r--r--tests/Android.bp1
-rw-r--r--tests/binder_test.cpp146
5 files changed, 161 insertions, 0 deletions
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index 63c004d2..2c0d7bce 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -689,6 +689,16 @@ binder::Status NetdNativeService::ipSecRemoveTunnelInterface(const std::string&
return asBinderStatus(gCtls->xfrmCtrl.ipSecRemoveTunnelInterface(deviceName));
}
+binder::Status NetdNativeService::ipSecMigrate(const IpSecMigrateInfoParcel& migrateInfo) {
+ // Necessary locking done in IpSecService and kernel
+ ENFORCE_NETWORK_STACK_PERMISSIONS();
+ return asBinderStatus(gCtls->xfrmCtrl.ipSecMigrate(
+ migrateInfo.requestId, migrateInfo.selAddrFamily, migrateInfo.direction,
+ migrateInfo.oldSourceAddress, migrateInfo.oldDestinationAddress,
+ migrateInfo.newSourceAddress, migrateInfo.newDestinationAddress,
+ migrateInfo.interfaceId));
+}
+
binder::Status NetdNativeService::setIPv6AddrGenMode(const std::string& ifName,
int32_t mode) {
ENFORCE_NETWORK_STACK_PERMISSIONS();
diff --git a/server/NetdNativeService.h b/server/NetdNativeService.h
index 9779f368..b2571221 100644
--- a/server/NetdNativeService.h
+++ b/server/NetdNativeService.h
@@ -231,6 +231,8 @@ class NetdNativeService : public BinderService<NetdNativeService>, public BnNetd
binder::Status ipSecRemoveTunnelInterface(const std::string& deviceName);
+ binder::Status ipSecMigrate(const IpSecMigrateInfoParcel& migrateInfo);
+
// Idletimer-related commands
binder::Status idletimerAddInterface(const std::string& ifName, int32_t timeout,
const std::string& classLabel) override;
diff --git a/server/XfrmController.h b/server/XfrmController.h
index 6da0c68a..781bc5e5 100644
--- a/server/XfrmController.h
+++ b/server/XfrmController.h
@@ -115,6 +115,8 @@ struct XfrmEndpointPair {
// minimally sufficient structure to match either an SA or a Policy
struct XfrmCommonInfo : XfrmEndpointPair {
+ // TODO: b/259298885 rename "transformId" to "requestId" and update
+ // all the related methods/fields/logs
int transformId; // requestId
int spi;
xfrm_mark mark;
diff --git a/tests/Android.bp b/tests/Android.bp
index e0426a29..b046b198 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -90,6 +90,7 @@ cc_test {
"netd_test.cpp",
],
include_dirs: ["system/netd/server"],
+ header_libs: ["bpf_headers"],
shared_libs: [
"libbase",
"libbinder",
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index f1d34945..bd9841ad 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -53,6 +53,7 @@
#include <android-base/test_utils.h>
#include <android/multinetwork.h>
#include <binder/IPCThreadState.h>
+#include <bpf/BpfUtils.h>
#include <com/android/internal/net/BnOemNetdUnsolicitedEventListener.h>
#include <com/android/internal/net/IOemNetd.h>
#include <cutils/multiuser.h>
@@ -108,6 +109,7 @@ using android::base::StringPrintf;
using android::base::Trim;
using android::base::unique_fd;
using android::binder::Status;
+using android::bpf::isAtLeastKernelVersion;
using android::net::INetd;
using android::net::InterfaceConfigurationParcel;
using android::net::InterfaceController;
@@ -510,6 +512,150 @@ TEST_F(NetdBinderTest, XfrmControllerInit) {
ASSERT_TRUE(XfrmController::ipSecRemoveTunnelInterface("ipsec_test").ok());
}
+// Two kernel fixes have been added in 5.17 to allow XFRM_MIGRATE to work correctly
+// when (1) there are multiple tunnels with the same selectors; and (2) addresses
+// are updated to a different IP family. These two fixes were pulled into upstream
+// LTS releases 4.14.273, 4.19.236, 5.4.186, 5.10.107 and 5.15.30, from whence they
+// flowed into the Android Common Kernel (via standard LTS merges).
+// As such we require 4.14.273+, 4.19.236+, 5.4.186+, 5.10.107+, 5.15.30+ and 5.17+
+// to have these fixes.
+bool hasXfrmMigrateKernelFixes() {
+ return (isAtLeastKernelVersion(4, 14, 273) && !isAtLeastKernelVersion(4, 19, 0)) ||
+ (isAtLeastKernelVersion(4, 19, 236) && !isAtLeastKernelVersion(5, 4, 0)) ||
+ (isAtLeastKernelVersion(5, 4, 186) && !isAtLeastKernelVersion(5, 10, 0)) ||
+ (isAtLeastKernelVersion(5, 10, 107) && !isAtLeastKernelVersion(5, 15, 0)) ||
+ isAtLeastKernelVersion(5, 15, 30);
+}
+
+// Does the kernel support CONFIG_XFRM_MIGRATE and include the kernel fixes?
+bool supportsXfrmMigrate() {
+ if (!hasXfrmMigrateKernelFixes()) return false;
+
+ // 5.10+ VINTF requires CONFIG_XFRM_MIGRATE enabled
+ if (isAtLeastKernelVersion(5, 10, 0)) return true;
+
+ const std::string wildcardAddr = "::";
+
+ // Expect migration to fail with EINVAL because it is trying to migrate a
+ // non-existent SA.
+ auto status = XfrmController::ipSecMigrate(
+ 0 /* resourceId */, AF_INET6, 0 /* direction == out */,
+ wildcardAddr /* sourceAddress */, wildcardAddr /* destinationAddress */,
+ wildcardAddr /* newSourceAddress */, wildcardAddr /* newDestinationAddress */,
+ 0 /* xfrmInterfaceId */);
+
+ if (android::netdutils::equalToErrno(status, EINVAL)) {
+ return true;
+ } else if (android::netdutils::equalToErrno(status, ENOPROTOOPT)) {
+ return false;
+ } else {
+ GTEST_LOG_(WARNING) << "Unexpected migration result: "
+ << android::netdutils::toString(status)
+ << "Assuming XFRM_MIGRATE is enabled.";
+ return true;
+ }
+}
+
+#define SKIP_IF_XFRM_MIGRATE_NOT_SUPPORTED \
+ do { \
+ if (!supportsXfrmMigrate()) \
+ GTEST_SKIP() << "This test is skipped since xfrm migrate feature " \
+ << "not supported\n"; \
+ } while (0)
+
+TEST_F(NetdBinderTest, XfrmMigrate) {
+ SKIP_IF_XFRM_MIGRATE_NOT_SUPPORTED;
+
+ static const struct TestData {
+ const int32_t addrFamily;
+ const int32_t newAddrFamily;
+ const std::string srcAddr;
+ const std::string dstAddr;
+ const std::string newSrcAddr;
+ const std::string newDstAddr;
+ } kTestData[] = {
+ {AF_INET, AF_INET, "192.0.2.1", "192.0.2.2", "192.0.2.101", "192.0.2.102"},
+ {AF_INET, AF_INET6, "192.0.2.1", "192.0.2.2", "2001:db8::101", "2001:db8::102"},
+ {AF_INET6, AF_INET6, "2001:db8::1", "2001:db8::2", "2001:db8::101", "2001:db8::102"},
+ {AF_INET6, AF_INET, "2001:db8::1", "2001:db8::2", "192.0.2.101", "192.0.2.102"},
+ };
+
+ const int32_t xfrmInterfaceId = 0xFFFE;
+ const std::string tunnelDeviceName = "ipsec_test";
+
+ auto status = mNetd->ipSecAddTunnelInterface(tunnelDeviceName, "2001:db8::fe", "2001:db8::ff",
+ 0x1234 + 50 /* iKey */, 0x1234 + 50 /* oKey */,
+ xfrmInterfaceId);
+
+ SCOPED_TRACE(status);
+ ASSERT_TRUE(status.isOk());
+
+ for (auto& td : kTestData) {
+ const int32_t direction = static_cast<int>(android::net::XfrmDirection::OUT);
+ const int32_t resourceId = 0;
+ const int32_t spiReq = 123;
+ int32_t spi = 0;
+
+ status = mNetd->ipSecAllocateSpi(resourceId, td.srcAddr, td.dstAddr, spiReq, &spi);
+ SCOPED_TRACE(status);
+ ASSERT_TRUE(status.isOk());
+
+ status = mNetd->ipSecAddSecurityAssociation(
+ resourceId, static_cast<int32_t>(android::net::XfrmMode::TUNNEL), td.srcAddr,
+ td.dstAddr, 100 /* underlyingNetid */, spiReq, 0 /* markValue */, 0 /* markMask */,
+ "digest_null" /* authAlgo */, {} /* authKey */, 0 /* authTruncBits */,
+ "ecb(cipher_null)" /* cryptAlgo */, {} /* cryptKey */, 0 /* cryptTruncBits */,
+ "" /* aeadAlgo */, {} /* aeadKey */, 0 /* aeadIcvBits */,
+ 0 /* encapType == ENCAP_NONE */, 0 /* encapLocalPort */, 0 /* encapRemotePort */,
+ xfrmInterfaceId);
+ SCOPED_TRACE(status);
+ ASSERT_TRUE(status.isOk());
+
+ for (int addrFamily : ADDRESS_FAMILIES) {
+ // Add a policy
+ status = mNetd->ipSecAddSecurityPolicy(resourceId, addrFamily, direction, td.srcAddr,
+ td.dstAddr, spiReq, 0 /* markValue */,
+ 0 /* markMask */, xfrmInterfaceId);
+ SCOPED_TRACE(status);
+ ASSERT_TRUE(status.isOk());
+
+ // Migrate tunnel mode SA
+ android::net::IpSecMigrateInfoParcel parcel;
+ parcel.requestId = resourceId;
+ parcel.selAddrFamily = addrFamily;
+ parcel.direction = direction;
+ parcel.oldSourceAddress = td.srcAddr;
+ parcel.oldDestinationAddress = td.dstAddr;
+ parcel.newSourceAddress = td.newSrcAddr;
+ parcel.newDestinationAddress = td.newDstAddr;
+ parcel.interfaceId = xfrmInterfaceId;
+
+ status = mNetd->ipSecMigrate(parcel);
+ SCOPED_TRACE(status);
+ ASSERT_TRUE(status.isOk());
+ }
+
+ // Clean up
+ status = mNetd->ipSecDeleteSecurityAssociation(resourceId, td.newSrcAddr, td.newDstAddr,
+ spiReq, 0 /* markValue */, 0 /* markMask */,
+ xfrmInterfaceId);
+ SCOPED_TRACE(status);
+ ASSERT_TRUE(status.isOk());
+
+ for (int addrFamily : ADDRESS_FAMILIES) {
+ status = mNetd->ipSecDeleteSecurityPolicy(resourceId, addrFamily, direction,
+ 0 /* markValue */, 0 /* markMask */,
+ xfrmInterfaceId);
+ SCOPED_TRACE(status);
+ ASSERT_TRUE(status.isOk());
+ }
+ }
+
+ // Remove Tunnel Interface.
+ status = mNetd->ipSecRemoveTunnelInterface(tunnelDeviceName);
+ SCOPED_TRACE(status);
+ EXPECT_TRUE(status.isOk());
+}
#endif // INTPTR_MAX != INT32_MAX
static int bandwidthDataSaverEnabled(const char *binary) {