diff options
author | Nathan Harold <nharold@google.com> | 2017-04-19 11:09:11 -0700 |
---|---|---|
committer | Nathan Harold <nharold@google.com> | 2017-04-21 10:08:11 -0700 |
commit | 2fb1b127764e23bd14cd74471a4358f2b4c5b3eb (patch) | |
tree | eca7bdf301e5dfb2f5f864e2879e131e737ef27a | |
parent | 2dd1bc3476aa4ae0dab2b27b3c04cb4c780f89e0 (diff) | |
download | netd-2fb1b127764e23bd14cd74471a4358f2b4c5b3eb.tar.gz |
Fix ABI incompatibility for Netlink XFRM on Fugu
Fugu is compiled with an x86 userspace and an x86_64
kernel. This means that there is no guarantee of ABI
compatibility between the kernel and userspace. The
xfrm_usersa_info struct is one such place where the
compatibility happens to not exist due to struct
alignment differences. This CL patches the
xfrm_usersa_info struct to match the kernel's 64-bit
alignment in at least the case of x86 vs x86_64.
Bug: 37252170
Test: CTS - IpSecManagerTest passes
Merged-In: Ic08a75d543f92f7fa5e0cf8b4277de12464fd406
Change-Id: Ic08a75d543f92f7fa5e0cf8b4277de12464fd406
-rw-r--r-- | server/Android.mk | 8 | ||||
-rw-r--r-- | server/XfrmController.cpp | 2 | ||||
-rw-r--r-- | server/XfrmController.h | 40 |
3 files changed, 48 insertions, 2 deletions
diff --git a/server/Android.mk b/server/Android.mk index 0785c23d..10006940 100644 --- a/server/Android.mk +++ b/server/Android.mk @@ -52,7 +52,13 @@ LOCAL_SANITIZE := unsigned-integer-overflow LOCAL_MODULE := netd # Bug: http://b/29823425 Disable -Wvarargs for Clang update to r271374 -LOCAL_CPPFLAGS += -Wno-varargs +LOCAL_CPPFLAGS += -Wno-varargs \ + +ifeq ($(TARGET_ARCH), x86) +ifneq ($(TARGET_PRODUCT), gce_x86_phone) + LOCAL_CPPFLAGS += -D NETLINK_COMPAT32 +endif +endif LOCAL_INIT_RC := netd.rc diff --git a/server/XfrmController.cpp b/server/XfrmController.cpp index e2cef003..f1e0e239 100644 --- a/server/XfrmController.cpp +++ b/server/XfrmController.cpp @@ -209,7 +209,7 @@ public: }; iov[0].iov_base = &nlMsg; - iov[0].iov_len = sizeof(nlMsg); + iov[0].iov_len = NLMSG_HDRLEN; for (int i = 0; i < iovLen; ++i) { nlMsg.nlmsg_len += iov[i].iov_len; } diff --git a/server/XfrmController.h b/server/XfrmController.h index 6e75830d..0f2c95aa 100644 --- a/server/XfrmController.h +++ b/server/XfrmController.h @@ -121,6 +121,46 @@ private: static constexpr size_t MAX_ALGO_LENGTH = 128; +/* + * Below is a redefinition of the xfrm_usersa_info struct that is part + * of the Linux uapi <linux/xfrm.h> to align the structures to a 64-bit + * boundary. + */ +#ifdef NETLINK_COMPAT32 + // Shadow the kernel definition of xfrm_usersa_info with a 64-bit aligned version + struct xfrm_usersa_info : ::xfrm_usersa_info { + } __attribute__((aligned(8))); + // Shadow the kernel's version, using the aligned version of xfrm_usersa_info + struct xfrm_userspi_info { + struct xfrm_usersa_info info; + __u32 min; + __u32 max; + }; + + /* + * Anyone who encounters a failure when sending netlink messages should look here + * first. Hitting the static_assert() below should be a strong hint that Android + * IPsec will probably not work with your current settings. + * + * Again, experimentally determined, the "flags" field should be the first byte in + * the final word of the xfrm_usersa_info struct. The check validates the size of + * the padding to be 7. + * + * This padding is verified to be correct on gcc/x86_64 kernel, and clang/x86 userspace. + */ + static_assert(sizeof(::xfrm_usersa_info) % 8 != 0, "struct xfrm_usersa_info has changed " + "alignment. Please consider whether this " + "patch is needed."); + static_assert(sizeof(xfrm_usersa_info) - offsetof(xfrm_usersa_info, flags) == 8, + "struct xfrm_usersa_info probably misaligned with kernel struct."); + static_assert(sizeof(xfrm_usersa_info) % 8 == 0, "struct xfrm_usersa_info_t is not 64-bit " + "aligned. Please consider whether this patch " + "is needed."); + static_assert(sizeof(::xfrm_userspi_info) - sizeof(::xfrm_usersa_info) == + sizeof(xfrm_userspi_info) - sizeof(xfrm_usersa_info), + "struct xfrm_userspi_info has changed and does not match the kernel struct."); +#endif + struct nlattr_algo_crypt { nlattr hdr; xfrm_algo crypt; |