From dd428301eb6f02542015121d7b08d9997f137e50 Mon Sep 17 00:00:00 2001 From: Sebastien Bacher Date: Tue, 12 Mar 2019 15:13:33 +0100 Subject: New upstream version 1.15.91 --- src/platform/nm-netlink.h | 243 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 188 insertions(+), 55 deletions(-) (limited to 'src/platform/nm-netlink.h') diff --git a/src/platform/nm-netlink.h b/src/platform/nm-netlink.h index 84bbe27b..094a3c6f 100644 --- a/src/platform/nm-netlink.h +++ b/src/platform/nm-netlink.h @@ -25,6 +25,8 @@ #include #include +#include "nm-utils/unaligned.h" + /*****************************************************************************/ #define NLMSGERR_ATTR_UNUSED 0 @@ -87,8 +89,26 @@ struct nla_policy { /*****************************************************************************/ +/* static asserts that @tb and @policy are suitable arguments to nla_parse(). */ +#define _nl_static_assert_tb(tb, policy) \ + G_STMT_START { \ + \ + G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (tb) > 0); \ + \ + /* we allow @policy to be either NULL or a C array. */ \ + G_STATIC_ASSERT_EXPR ( sizeof (policy) == sizeof (NULL) \ + || G_N_ELEMENTS (tb) == (sizeof (policy) / sizeof (struct nla_policy))); \ + \ + /* For above check to work, we don't support policy being an array with same size as + * sizeof(NULL), otherwise, the compile time check breaks down. */ \ + G_STATIC_ASSERT_EXPR (sizeof (NULL) != G_N_ELEMENTS (tb) * sizeof (struct nla_policy)); \ + \ + } G_STMT_END + +/*****************************************************************************/ + static inline int -nla_attr_size(int payload) +nla_attr_size (int payload) { nm_assert (payload >= 0); @@ -104,7 +124,7 @@ nla_total_size (int payload) static inline int nla_padlen (int payload) { - return nla_total_size(payload) - nla_attr_size(payload); + return nla_total_size (payload) - nla_attr_size (payload); } struct nlattr *nla_reserve (struct nl_msg *msg, int attrtype, int attrlen); @@ -112,32 +132,56 @@ struct nlattr *nla_reserve (struct nl_msg *msg, int attrtype, int attrlen); static inline int nla_len (const struct nlattr *nla) { - return nla->nla_len - NLA_HDRLEN; + nm_assert (nla); + nm_assert (nla->nla_len >= NLA_HDRLEN); + + return ((int) nla->nla_len) - NLA_HDRLEN; } static inline int nla_type (const struct nlattr *nla) { + nm_assert (nla_len (nla) >= 0); + return nla->nla_type & NLA_TYPE_MASK; } static inline void * nla_data (const struct nlattr *nla) { - nm_assert (nla); - return (char *) nla + NLA_HDRLEN; + nm_assert (nla_len (nla) >= 0); + + return &(((char *) nla)[NLA_HDRLEN]); } +#define nla_data_as(type, nla) \ + ({ \ + const struct nlattr *_nla = (nla); \ + \ + nm_assert (nla_len (_nla) >= sizeof (type)); \ + \ + /* note that casting the pointer is undefined behavior in C, if + * the data has wrong alignment. Netlink data is aligned to 4 bytes, + * that means, if the alignment is larger than 4, this is invalid. */ \ + G_STATIC_ASSERT_EXPR (_nm_alignof (type) <= NLA_ALIGNTO); \ + \ + (type *) nla_data (_nla); \ + }) + static inline uint8_t nla_get_u8 (const struct nlattr *nla) { - return *(const uint8_t *) nla_data (nla); + nm_assert (nla_len (nla) >= sizeof (uint8_t)); + + return *((const uint8_t *) nla_data (nla)); } -static inline uint8_t +static inline int8_t nla_get_s8 (const struct nlattr *nla) { - return *(const int8_t *) nla_data (nla); + nm_assert (nla_len (nla) >= sizeof (int8_t)); + + return *((const int8_t *) nla_data (nla)); } static inline uint8_t @@ -152,39 +196,80 @@ nla_get_u8_cond (/*const*/ struct nlattr *const*tb, int attr, uint8_t default_va static inline uint16_t nla_get_u16 (const struct nlattr *nla) { - return *(const uint16_t *) nla_data (nla); + nm_assert (nla_len (nla) >= sizeof (uint16_t)); + + return *((const uint16_t *) nla_data (nla)); } static inline uint32_t -nla_get_u32(const struct nlattr *nla) +nla_get_u32 (const struct nlattr *nla) { - return *(const uint32_t *) nla_data (nla); + nm_assert (nla_len (nla) >= sizeof (uint32_t)); + + return *((const uint32_t *) nla_data (nla)); } static inline int32_t -nla_get_s32(const struct nlattr *nla) +nla_get_s32 (const struct nlattr *nla) { - return *(const int32_t *) nla_data (nla); + nm_assert (nla_len (nla) >= sizeof (int32_t)); + + return *((const int32_t *) nla_data (nla)); +} + +static inline uint64_t +nla_get_u64 (const struct nlattr *nla) +{ + nm_assert (nla_len (nla) >= sizeof (uint64_t)); + + return unaligned_read_ne64 (nla_data (nla)); } -uint64_t nla_get_u64 (const struct nlattr *nla); +static inline uint64_t +nla_get_be64 (const struct nlattr *nla) +{ + nm_assert (nla_len (nla) >= sizeof (uint64_t)); + + return unaligned_read_be64 (nla_data (nla)); +} static inline char * nla_get_string (const struct nlattr *nla) { + nm_assert (nla_len (nla) >= 0); + return (char *) nla_data (nla); } size_t nla_strlcpy (char *dst, const struct nlattr *nla, size_t dstsize); -int nla_memcpy (void *dest, const struct nlattr *src, int count); +size_t nla_memcpy (void *dst, const struct nlattr *nla, size_t dstsize); + +#define nla_memcpy_checked_size(dst, nla, dstsize) \ + G_STMT_START { \ + void *const _dst = (dst); \ + const struct nlattr *const _nla = (nla); \ + const size_t _dstsize = (dstsize); \ + size_t _srcsize; \ + \ + /* assert that, if @nla is given, that it has the exact expected + * size. This implies that the caller previously verified the length + * of the attribute (via minlen/maxlen at nla_parse()). */ \ + \ + if (_nla) { \ + _srcsize = nla_memcpy (_dst, _nla, _dstsize); \ + nm_assert (_srcsize == _dstsize); \ + } \ + } G_STMT_END int nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data); static inline int nla_put_string (struct nl_msg *msg, int attrtype, const char *str) { - return nla_put(msg, attrtype, strlen(str) + 1, str); + nm_assert (str); + + return nla_put (msg, attrtype, strlen (str) + 1, str); } static inline int @@ -206,55 +291,55 @@ nla_put_uint32 (struct nl_msg *msg, int attrtype, uint32_t val) } #define NLA_PUT(msg, attrtype, attrlen, data) \ - do { \ - if (nla_put(msg, attrtype, attrlen, data) < 0) \ + G_STMT_START { \ + if (nla_put (msg, attrtype, attrlen, data) < 0) \ goto nla_put_failure; \ - } while(0) + } G_STMT_END #define NLA_PUT_TYPE(msg, type, attrtype, value) \ - do { \ + G_STMT_START { \ type __nla_tmp = value; \ - NLA_PUT(msg, attrtype, sizeof(type), &__nla_tmp); \ - } while(0) + NLA_PUT (msg, attrtype, sizeof (type), &__nla_tmp); \ + } G_STMT_END #define NLA_PUT_U8(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, uint8_t, attrtype, value) + NLA_PUT_TYPE (msg, uint8_t, attrtype, value) #define NLA_PUT_S8(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, int8_t, attrtype, value) + NLA_PUT_TYPE (msg, int8_t, attrtype, value) #define NLA_PUT_U16(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, uint16_t, attrtype, value) + NLA_PUT_TYPE (msg, uint16_t, attrtype, value) #define NLA_PUT_U32(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, uint32_t, attrtype, value) + NLA_PUT_TYPE (msg, uint32_t, attrtype, value) #define NLA_PUT_S32(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, int32_t, attrtype, value) + NLA_PUT_TYPE (msg, int32_t, attrtype, value) #define NLA_PUT_U64(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, uint64_t, attrtype, value) + NLA_PUT_TYPE (msg, uint64_t, attrtype, value) #define NLA_PUT_STRING(msg, attrtype, value) \ - NLA_PUT(msg, attrtype, (int) strlen(value) + 1, value) + NLA_PUT (msg, attrtype, (int) strlen (value) + 1, value) #define NLA_PUT_FLAG(msg, attrtype) \ - NLA_PUT(msg, attrtype, 0, NULL) + NLA_PUT (msg, attrtype, 0, NULL) struct nlattr *nla_find (const struct nlattr *head, int len, int attrtype); static inline int nla_ok (const struct nlattr *nla, int remaining) { - return remaining >= (int) sizeof(*nla) && - nla->nla_len >= sizeof(*nla) && + return remaining >= (int) sizeof (*nla) && + nla->nla_len >= sizeof (*nla) && nla->nla_len <= remaining; } static inline struct nlattr * -nla_next(const struct nlattr *nla, int *remaining) +nla_next (const struct nlattr *nla, int *remaining) { - int totlen = NLA_ALIGN(nla->nla_len); + int totlen = NLA_ALIGN (nla->nla_len); *remaining -= totlen; return (struct nlattr *) ((char *) nla + totlen); @@ -262,28 +347,47 @@ nla_next(const struct nlattr *nla, int *remaining) #define nla_for_each_attr(pos, head, len, rem) \ for (pos = head, rem = len; \ - nla_ok(pos, rem); \ - pos = nla_next(pos, &(rem))) + nla_ok (pos, rem); \ + pos = nla_next (pos, &(rem))) #define nla_for_each_nested(pos, nla, rem) \ - for (pos = (struct nlattr *) nla_data(nla), rem = nla_len(nla); \ - nla_ok(pos, rem); \ - pos = nla_next(pos, &(rem))) + for (pos = (struct nlattr *) nla_data (nla), rem = nla_len (nla); \ + nla_ok (pos, rem); \ + pos = nla_next (pos, &(rem))) void nla_nest_cancel (struct nl_msg *msg, const struct nlattr *attr); struct nlattr *nla_nest_start (struct nl_msg *msg, int attrtype); int nla_nest_end (struct nl_msg *msg, struct nlattr *start); -int nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, +int nla_parse (struct nlattr *tb[], + int maxtype, + struct nlattr *head, + int len, const struct nla_policy *policy); +#define nla_parse_arr(tb, head, len, policy) \ + ({ \ + _nl_static_assert_tb ((tb), (policy)); \ + \ + nla_parse ((tb), G_N_ELEMENTS (tb) - 1, (head), (len), (policy)); \ + }) + static inline int -nla_parse_nested (struct nlattr *tb[], int maxtype, struct nlattr *nla, +nla_parse_nested (struct nlattr *tb[], + int maxtype, + struct nlattr *nla, const struct nla_policy *policy) { - return nla_parse (tb, maxtype, nla_data(nla), nla_len(nla), policy); + return nla_parse (tb, maxtype, nla_data (nla), nla_len (nla), policy); } +#define nla_parse_nested_arr(tb, nla, policy) \ + ({ \ + _nl_static_assert_tb ((tb), (policy)); \ + \ + nla_parse_nested ((tb), G_N_ELEMENTS (tb) - 1, (nla), (policy)); \ + }) + /*****************************************************************************/ struct nl_msg *nlmsg_alloc (void); @@ -296,7 +400,13 @@ struct nl_msg *nlmsg_alloc_simple (int nlmsgtype, int flags); void *nlmsg_reserve (struct nl_msg *n, size_t len, int pad); -int nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad); +int nlmsg_append (struct nl_msg *n, + const void *data, + size_t len, + int pad); + +#define nlmsg_append_struct(n, data) \ + nlmsg_append (n, (data), sizeof (*(data)), NLMSG_ALIGNTO) void nlmsg_free (struct nl_msg *msg); @@ -316,15 +426,15 @@ nlmsg_total_size (int payload) static inline int nlmsg_ok (const struct nlmsghdr *nlh, int remaining) { - return (remaining >= (int)sizeof(struct nlmsghdr) && - nlh->nlmsg_len >= sizeof(struct nlmsghdr) && + return (remaining >= (int) sizeof (struct nlmsghdr) && + nlh->nlmsg_len >= sizeof (struct nlmsghdr) && nlh->nlmsg_len <= remaining); } static inline struct nlmsghdr * nlmsg_next (struct nlmsghdr *nlh, int *remaining) { - int totlen = NLMSG_ALIGN(nlh->nlmsg_len); + int totlen = NLMSG_ALIGN (nlh->nlmsg_len); *remaining -= totlen; @@ -344,7 +454,7 @@ _nm_auto_nl_msg_cleanup (struct nl_msg **ptr) { nlmsg_free (*ptr); } -#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup) +#define nm_auto_nlmsg nm_auto (_nm_auto_nl_msg_cleanup) static inline void * nlmsg_data (const struct nlmsghdr *nlh) @@ -355,13 +465,13 @@ nlmsg_data (const struct nlmsghdr *nlh) static inline void * nlmsg_tail (const struct nlmsghdr *nlh) { - return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len); + return (unsigned char *) nlh + NLMSG_ALIGN (nlh->nlmsg_len); } struct nlmsghdr *nlmsg_hdr (struct nl_msg *n); static inline int -nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen) +nlmsg_valid_hdr (const struct nlmsghdr *nlh, int hdrlen) { if (nlh->nlmsg_len < nlmsg_size (hdrlen)) return 0; @@ -384,8 +494,8 @@ nlmsg_attrlen (const struct nlmsghdr *nlh, int hdrlen) static inline struct nlattr * nlmsg_attrdata (const struct nlmsghdr *nlh, int hdrlen) { - unsigned char *data = nlmsg_data(nlh); - return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen)); + unsigned char *data = nlmsg_data (nlh); + return (struct nlattr *) (data + NLMSG_ALIGN (hdrlen)); } static inline struct nlattr * @@ -396,8 +506,19 @@ nlmsg_find_attr (struct nlmsghdr *nlh, int hdrlen, int attrtype) attrtype); } -int nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], - int maxtype, const struct nla_policy *policy); +int nlmsg_parse (struct nlmsghdr *nlh, + int hdrlen, + struct nlattr *tb[], + int maxtype, + const struct nla_policy *policy); + +#define nlmsg_parse_arr(nlh, hdrlen, tb, policy) \ + ({ \ + _nl_static_assert_tb ((tb), (policy)); \ + G_STATIC_ASSERT_EXPR ((hdrlen) >= 0); \ + \ + nlmsg_parse ((nlh), (hdrlen), (tb), G_N_ELEMENTS (tb) - 1, (policy)); \ + }) struct nlmsghdr *nlmsg_put (struct nl_msg *n, uint32_t pid, uint32_t seq, int type, int payload, int flags); @@ -499,8 +620,20 @@ struct nlattr *genlmsg_attrdata (const struct genlmsghdr *gnlh, int hdrlen); int genlmsg_len (const struct genlmsghdr *gnlh); int genlmsg_attrlen (const struct genlmsghdr *gnlh, int hdrlen); int genlmsg_valid_hdr (struct nlmsghdr *nlh, int hdrlen); -int genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], - int maxtype, const struct nla_policy *policy); + +int genlmsg_parse (struct nlmsghdr *nlh, + int hdrlen, + struct nlattr *tb[], + int maxtype, + const struct nla_policy *policy); + +#define genlmsg_parse_arr(nlh, hdrlen, tb, policy) \ + ({ \ + _nl_static_assert_tb ((tb), (policy)); \ + G_STATIC_ASSERT_EXPR ((hdrlen) >= 0); \ + \ + genlmsg_parse ((nlh), (hdrlen), (tb), G_N_ELEMENTS (tb) - 1, (policy)); \ + }) int genl_ctrl_resolve (struct nl_sock *sk, const char *name); -- cgit 1.3.0-6-gf8a5