aboutsummaryrefslogtreecommitdiff
path: root/tools/lib/bpf/nlattr.h
diff options
context:
space:
mode:
authorKumar Kartikeya Dwivedi2021-06-19 09:44:53 +0530
committerDaniel Borkmann2021-06-22 17:03:52 +0200
commit0ae64fb6b645e0f976e08bc3c05e518856f19d00 (patch)
tree56d8bdacdee9db93fc2257d5fbaa450aa3dc6b8a /tools/lib/bpf/nlattr.h
parent5c10a3dbe9220ca7bcee716c13c8a8563bcb010a (diff)
libbpf: Add request buffer type for netlink messages
Coverity complains about OOB writes to nlmsghdr. There is no OOB as we write to the trailing buffer, but static analyzers and compilers may rightfully be confused as the nlmsghdr pointer has subobject provenance (and hence subobject bounds). Fix this by using an explicit request structure containing the nlmsghdr, struct tcmsg/ifinfomsg, and attribute buffer. Also switch nh_tail (renamed to req_tail) to cast req * to char * so that it can be understood as arithmetic on pointer to the representation array (hence having same bound as request structure), which should further appease analyzers. As a bonus, callers don't have to pass sizeof(req) all the time now, as size is implicitly obtained using the pointer. While at it, also reduce the size of attribute buffer to 128 bytes (132 for ifinfomsg using functions due to the padding). Summary of problem: Even though C standard allows interconvertibility of pointer to first member and pointer to struct, for the purposes of alias analysis it would still consider the first as having pointer value "pointer to T" where T is type of first member hence having subobject bounds, allowing analyzers within reason to complain when object is accessed beyond the size of pointed to object. The only exception to this rule may be when a char * is formed to a member subobject. It is not possible for the compiler to be able to tell the intent of the programmer that it is a pointer to member object or the underlying representation array of the containing object, so such diagnosis is suppressed. Fixes: 715c5ce454a6 ("libbpf: Add low level TC-BPF management API") Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Link: https://lore.kernel.org/bpf/20210619041454.417577-1-memxor@gmail.com
Diffstat (limited to 'tools/lib/bpf/nlattr.h')
-rw-r--r--tools/lib/bpf/nlattr.h34
1 files changed, 22 insertions, 12 deletions
diff --git a/tools/lib/bpf/nlattr.h b/tools/lib/bpf/nlattr.h
index 3c780ab6d022..76cbfeb21955 100644
--- a/tools/lib/bpf/nlattr.h
+++ b/tools/lib/bpf/nlattr.h
@@ -13,6 +13,7 @@
#include <string.h>
#include <errno.h>
#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
/* avoid multiple definition of netlink features */
#define __LINUX_NETLINK_H
@@ -52,6 +53,15 @@ struct libbpf_nla_policy {
uint16_t maxlen;
};
+struct libbpf_nla_req {
+ struct nlmsghdr nh;
+ union {
+ struct ifinfomsg ifinfo;
+ struct tcmsg tc;
+ };
+ char buf[128];
+};
+
/**
* @ingroup attr
* Iterate over a stream of attributes
@@ -111,44 +121,44 @@ static inline struct nlattr *nla_data(struct nlattr *nla)
return (struct nlattr *)((char *)nla + NLA_HDRLEN);
}
-static inline struct nlattr *nh_tail(struct nlmsghdr *nh)
+static inline struct nlattr *req_tail(struct libbpf_nla_req *req)
{
- return (struct nlattr *)((char *)nh + NLMSG_ALIGN(nh->nlmsg_len));
+ return (struct nlattr *)((char *)req + NLMSG_ALIGN(req->nh.nlmsg_len));
}
-static inline int nlattr_add(struct nlmsghdr *nh, size_t maxsz, int type,
+static inline int nlattr_add(struct libbpf_nla_req *req, int type,
const void *data, int len)
{
struct nlattr *nla;
- if (NLMSG_ALIGN(nh->nlmsg_len) + NLA_ALIGN(NLA_HDRLEN + len) > maxsz)
+ if (NLMSG_ALIGN(req->nh.nlmsg_len) + NLA_ALIGN(NLA_HDRLEN + len) > sizeof(*req))
return -EMSGSIZE;
if (!!data != !!len)
return -EINVAL;
- nla = nh_tail(nh);
+ nla = req_tail(req);
nla->nla_type = type;
nla->nla_len = NLA_HDRLEN + len;
if (data)
memcpy(nla_data(nla), data, len);
- nh->nlmsg_len = NLMSG_ALIGN(nh->nlmsg_len) + NLA_ALIGN(nla->nla_len);
+ req->nh.nlmsg_len = NLMSG_ALIGN(req->nh.nlmsg_len) + NLA_ALIGN(nla->nla_len);
return 0;
}
-static inline struct nlattr *nlattr_begin_nested(struct nlmsghdr *nh,
- size_t maxsz, int type)
+static inline struct nlattr *nlattr_begin_nested(struct libbpf_nla_req *req, int type)
{
struct nlattr *tail;
- tail = nh_tail(nh);
- if (nlattr_add(nh, maxsz, type | NLA_F_NESTED, NULL, 0))
+ tail = req_tail(req);
+ if (nlattr_add(req, type | NLA_F_NESTED, NULL, 0))
return NULL;
return tail;
}
-static inline void nlattr_end_nested(struct nlmsghdr *nh, struct nlattr *tail)
+static inline void nlattr_end_nested(struct libbpf_nla_req *req,
+ struct nlattr *tail)
{
- tail->nla_len = (char *)nh_tail(nh) - (char *)tail;
+ tail->nla_len = (char *)req_tail(req) - (char *)tail;
}
#endif /* __LIBBPF_NLATTR_H */