diff --git a/src/openvpn/networking_sitnl.c b/src/openvpn/networking_sitnl.c index f53f5ee9ebf..6b750e86816 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 @@ sitnl_addattr(struct nlmsghdr *n, int maxlen, int type, const void *data, return -EMSGSIZE; } - rta = NLMSG_TAIL(n); + rta = sitnl_nlmsg_tail(n); rta->rta_type = type; rta->rta_len = len;