2022-05-04 04:59:03

by Kees Cook

[permalink] [raw]
Subject: [PATCH 01/32] netlink: Avoid memcpy() across flexible array boundary

In preparation for run-time memcpy() bounds checking, split the nlmsg
copying for error messages (which crosses a previous unspecified flexible
array boundary) in half. Avoids the future run-time warning:

memcpy: detected field-spanning write (size 32) of single field "&errmsg->msg" (size 16)

Creates an explicit flexible array at the end of nlmsghdr for the payload,
named "nlmsg_payload". There is no impact on UAPI; the sizeof(struct
nlmsghdr) does not change, but now the compiler can better reason about
where things are being copied.

Fixed-by: Rasmus Villemoes <[email protected]>
Link: https://lore.kernel.org/lkml/[email protected]
Cc: "David S. Miller" <[email protected]>
Cc: Jakub Kicinski <[email protected]>
Cc: Rich Felker <[email protected]>
Cc: Eric Dumazet <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
include/uapi/linux/netlink.h | 1 +
net/netlink/af_netlink.c | 5 ++++-
2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/include/uapi/linux/netlink.h b/include/uapi/linux/netlink.h
index 855dffb4c1c3..47f9342d51bc 100644
--- a/include/uapi/linux/netlink.h
+++ b/include/uapi/linux/netlink.h
@@ -47,6 +47,7 @@ struct nlmsghdr {
__u16 nlmsg_flags; /* Additional flags */
__u32 nlmsg_seq; /* Sequence number */
__u32 nlmsg_pid; /* Sending process port ID */
+ __u8 nlmsg_payload[];/* Contents of message */
};

/* Flags values */
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 1b5a9c2e1c29..09346aee1022 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -2445,7 +2445,10 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
NLMSG_ERROR, payload, flags);
errmsg = nlmsg_data(rep);
errmsg->error = err;
- memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg) ? nlh->nlmsg_len : sizeof(*nlh));
+ errmsg->msg = *nlh;
+ if (payload > sizeof(*errmsg))
+ memcpy(errmsg->msg.nlmsg_payload, nlh->nlmsg_payload,
+ nlh->nlmsg_len - sizeof(*nlh));

if (nlk_has_extack && extack) {
if (extack->_msg) {
--
2.32.0