Skip to content

Commit 738136a

Browse files
kuba-moodavem330
authored andcommitted
netlink: split up copies in the ack construction
Clean up the use of unsafe_memcpy() by adding a flexible array at the end of netlink message header and splitting up the header and data copies. Reviewed-by: Kees Cook <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent eca485d commit 738136a

File tree

3 files changed

+43
-9
lines changed

3 files changed

+43
-9
lines changed

include/net/netlink.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,27 @@ static inline struct nlmsghdr *nlmsg_put(struct sk_buff *skb, u32 portid, u32 se
931931
return __nlmsg_put(skb, portid, seq, type, payload, flags);
932932
}
933933

934+
/**
935+
* nlmsg_append - Add more data to a nlmsg in a skb
936+
* @skb: socket buffer to store message in
937+
* @size: length of message payload
938+
*
939+
* Append data to an existing nlmsg, used when constructing a message
940+
* with multiple fixed-format headers (which is rare).
941+
* Returns NULL if the tailroom of the skb is insufficient to store
942+
* the extra payload.
943+
*/
944+
static inline void *nlmsg_append(struct sk_buff *skb, u32 size)
945+
{
946+
if (unlikely(skb_tailroom(skb) < NLMSG_ALIGN(size)))
947+
return NULL;
948+
949+
if (NLMSG_ALIGN(size) - size)
950+
memset(skb_tail_pointer(skb) + size, 0,
951+
NLMSG_ALIGN(size) - size);
952+
return __skb_put(skb, NLMSG_ALIGN(size));
953+
}
954+
934955
/**
935956
* nlmsg_put_answer - Add a new callback based netlink message to an skb
936957
* @skb: socket buffer to store message in

include/uapi/linux/netlink.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,15 @@ struct sockaddr_nl {
4848
* @nlmsg_flags: Additional flags
4949
* @nlmsg_seq: Sequence number
5050
* @nlmsg_pid: Sending process port ID
51+
* @nlmsg_data: Message payload
5152
*/
5253
struct nlmsghdr {
5354
__u32 nlmsg_len;
5455
__u16 nlmsg_type;
5556
__u16 nlmsg_flags;
5657
__u32 nlmsg_seq;
5758
__u32 nlmsg_pid;
59+
__u8 nlmsg_data[];
5860
};
5961

6062
/* Flags values */

net/netlink/af_netlink.c

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2499,26 +2499,37 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
24992499
flags |= NLM_F_ACK_TLVS;
25002500

25012501
skb = nlmsg_new(payload + tlvlen, GFP_KERNEL);
2502-
if (!skb) {
2503-
NETLINK_CB(in_skb).sk->sk_err = ENOBUFS;
2504-
sk_error_report(NETLINK_CB(in_skb).sk);
2505-
return;
2506-
}
2502+
if (!skb)
2503+
goto err_bad_put;
25072504

25082505
rep = nlmsg_put(skb, NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
2509-
NLMSG_ERROR, payload, flags);
2506+
NLMSG_ERROR, sizeof(*errmsg), flags);
2507+
if (!rep)
2508+
goto err_bad_put;
25102509
errmsg = nlmsg_data(rep);
25112510
errmsg->error = err;
2512-
unsafe_memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg)
2513-
? nlh->nlmsg_len : sizeof(*nlh),
2514-
/* Bounds checked by the skb layer. */);
2511+
errmsg->msg = *nlh;
2512+
2513+
if (!(flags & NLM_F_CAPPED)) {
2514+
if (!nlmsg_append(skb, nlmsg_len(nlh)))
2515+
goto err_bad_put;
2516+
2517+
memcpy(errmsg->msg.nlmsg_data, nlh->nlmsg_data,
2518+
nlmsg_len(nlh));
2519+
}
25152520

25162521
if (tlvlen)
25172522
netlink_ack_tlv_fill(in_skb, skb, nlh, err, extack);
25182523

25192524
nlmsg_end(skb, rep);
25202525

25212526
nlmsg_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid);
2527+
2528+
return;
2529+
2530+
err_bad_put:
2531+
NETLINK_CB(in_skb).sk->sk_err = ENOBUFS;
2532+
sk_error_report(NETLINK_CB(in_skb).sk);
25222533
}
25232534
EXPORT_SYMBOL(netlink_ack);
25242535

0 commit comments

Comments
 (0)