[Openvpn-devel,v5] sitnl: replace NLMSG_TAIL macro with noinline function

Message ID 20241106131705.11069-1-gert@greenie.muc.de
State Accepted
Headers show
Series [Openvpn-devel,v5] sitnl: replace NLMSG_TAIL macro with noinline function | expand

Commit Message

Gert Doering Nov. 6, 2024, 1:17 p.m. UTC
From: Antonio Quartulli <antonio@mandelbit.com>

The NLMSG_TAIL macro is confusing gcc when compiling with -O3, leading
to warnings like:

networking_sitnl.c:143:9: warning: writing 4 bytes into a region of size 0 [-Wstringop-overflow=]
  143 |         memcpy(RTA_DATA(rta), data, alen);
      |         ^
networking_sitnl.c:101:21: note: at offset [72, 88] into destination object ā€˜nā€™ of size 16
  101 |     struct nlmsghdr n;
      |                     ^

Replacing the macro with a function is also not effective because gcc
will inline it and get confused again.

The only way out is to write a function that never gets inline'd and
replace the macro with it.

Tested on linux with gcc and clang.

Change-Id: I9306a590a10a7d5cba32abe06d269494fec41ba6
Signed-off-by: Antonio Quartulli <antonio@mandelbit.com>
Acked-by: Frank Lichtenheld <frank@lichtenheld.com>
---

This change was reviewed on Gerrit and approved by at least one
developer. I request to merge it to master.

Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/788
This mail reflects revision 5 of this Change.

Acked-by according to Gerrit (reflected above):
Frank Lichtenheld <frank@lichtenheld.com>

Comments

Gert Doering Nov. 9, 2024, 12:09 p.m. UTC | #1
I'm generally not very much in favour of working around compiler silliness,
but this gets in the way of testing on Linux with -Werror, so what shall
we do... - it's not time critical, so inline/noinline does not really
matter much here.  Tested on Gentoo and Ubuntu, client / server side, 
with and without DCO.  So I claim it's a working replacement :-)

Your patch has been applied to the master branch.

commit 648e1606496adc6ec37a9d862810e465dab64dc0
Author: Antonio Quartulli
Date:   Wed Nov 6 14:17:03 2024 +0100

     sitnl: replace NLMSG_TAIL macro with noinline function

     Signed-off-by: Antonio Quartulli <antonio@mandelbit.com>
     Acked-by: Frank Lichtenheld <frank@lichtenheld.com>
     Message-Id: <20241106131705.11069-1-gert@greenie.muc.de>
     URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg29710.html
     Signed-off-by: Gert Doering <gert@greenie.muc.de>


--
kind regards,

Gert Doering

Patch

diff --git a/src/openvpn/networking_sitnl.c b/src/openvpn/networking_sitnl.c
index f53f5ee..6b750e8 100644
--- a/src/openvpn/networking_sitnl.c
+++ b/src/openvpn/networking_sitnl.c
@@ -52,21 +52,34 @@ 
         }                                                           \
     }
 
-#define NLMSG_TAIL(nmsg) \
-    ((struct rtattr *)(((uint8_t *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
-
 #define SITNL_NEST(_msg, _max_size, _attr)              \
     ({                                                  \
-        struct rtattr *_nest = NLMSG_TAIL(_msg);        \
+        struct rtattr *_nest = sitnl_nlmsg_tail(_msg);  \
         SITNL_ADDATTR(_msg, _max_size, _attr, NULL, 0); \
         _nest;                                          \
     })
 
-#define SITNL_NEST_END(_msg, _nest)                                 \
-    {                                                               \
-        _nest->rta_len = (void *)NLMSG_TAIL(_msg) - (void *)_nest;  \
+#define SITNL_NEST_END(_msg, _nest)                                     \
+    {                                                                   \
+        _nest->rta_len = (void *)sitnl_nlmsg_tail(_msg) - (void *)_nest; \
     }
 
+/* This function was originally implemented as a macro, but compiling with
+ * gcc and -O3 was getting confused about the math and thus raising
+ * security warnings on subsequent memcpy() calls.
+ *
+ * Converting the macro to a function was not enough, because gcc was still
+ * inlining it and falling in the same math trap.
+ *
+ * The only way out to avoid any warning/error is to force the function to
+ * not be inline'd.
+ */
+static __attribute__ ((noinline)) void *
+sitnl_nlmsg_tail(const struct nlmsghdr *nlh)
+{
+    return (unsigned char *)nlh + NLMSG_ALIGN(nlh->nlmsg_len);
+}
+
 /**
  * Generic address data structure used to pass addresses and prefixes as
  * argument to AF family agnostic functions
@@ -130,7 +143,7 @@ 
         return -EMSGSIZE;
     }
 
-    rta = NLMSG_TAIL(n);
+    rta = sitnl_nlmsg_tail(n);
     rta->rta_type = type;
     rta->rta_len = len;