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 <keescook@chromium.org> Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
eca485d221
commit
738136a0e3
3 changed files with 43 additions and 9 deletions
|
@ -931,6 +931,27 @@ static inline struct nlmsghdr *nlmsg_put(struct sk_buff *skb, u32 portid, u32 se
|
||||||
return __nlmsg_put(skb, portid, seq, type, payload, flags);
|
return __nlmsg_put(skb, portid, seq, type, payload, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nlmsg_append - Add more data to a nlmsg in a skb
|
||||||
|
* @skb: socket buffer to store message in
|
||||||
|
* @size: length of message payload
|
||||||
|
*
|
||||||
|
* Append data to an existing nlmsg, used when constructing a message
|
||||||
|
* with multiple fixed-format headers (which is rare).
|
||||||
|
* Returns NULL if the tailroom of the skb is insufficient to store
|
||||||
|
* the extra payload.
|
||||||
|
*/
|
||||||
|
static inline void *nlmsg_append(struct sk_buff *skb, u32 size)
|
||||||
|
{
|
||||||
|
if (unlikely(skb_tailroom(skb) < NLMSG_ALIGN(size)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (NLMSG_ALIGN(size) - size)
|
||||||
|
memset(skb_tail_pointer(skb) + size, 0,
|
||||||
|
NLMSG_ALIGN(size) - size);
|
||||||
|
return __skb_put(skb, NLMSG_ALIGN(size));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nlmsg_put_answer - Add a new callback based netlink message to an skb
|
* nlmsg_put_answer - Add a new callback based netlink message to an skb
|
||||||
* @skb: socket buffer to store message in
|
* @skb: socket buffer to store message in
|
||||||
|
|
|
@ -48,6 +48,7 @@ struct sockaddr_nl {
|
||||||
* @nlmsg_flags: Additional flags
|
* @nlmsg_flags: Additional flags
|
||||||
* @nlmsg_seq: Sequence number
|
* @nlmsg_seq: Sequence number
|
||||||
* @nlmsg_pid: Sending process port ID
|
* @nlmsg_pid: Sending process port ID
|
||||||
|
* @nlmsg_data: Message payload
|
||||||
*/
|
*/
|
||||||
struct nlmsghdr {
|
struct nlmsghdr {
|
||||||
__u32 nlmsg_len;
|
__u32 nlmsg_len;
|
||||||
|
@ -55,6 +56,7 @@ struct nlmsghdr {
|
||||||
__u16 nlmsg_flags;
|
__u16 nlmsg_flags;
|
||||||
__u32 nlmsg_seq;
|
__u32 nlmsg_seq;
|
||||||
__u32 nlmsg_pid;
|
__u32 nlmsg_pid;
|
||||||
|
__u8 nlmsg_data[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Flags values */
|
/* Flags values */
|
||||||
|
|
|
@ -2499,19 +2499,24 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
|
||||||
flags |= NLM_F_ACK_TLVS;
|
flags |= NLM_F_ACK_TLVS;
|
||||||
|
|
||||||
skb = nlmsg_new(payload + tlvlen, GFP_KERNEL);
|
skb = nlmsg_new(payload + tlvlen, GFP_KERNEL);
|
||||||
if (!skb) {
|
if (!skb)
|
||||||
NETLINK_CB(in_skb).sk->sk_err = ENOBUFS;
|
goto err_bad_put;
|
||||||
sk_error_report(NETLINK_CB(in_skb).sk);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rep = nlmsg_put(skb, NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
|
rep = nlmsg_put(skb, NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
|
||||||
NLMSG_ERROR, payload, flags);
|
NLMSG_ERROR, sizeof(*errmsg), flags);
|
||||||
|
if (!rep)
|
||||||
|
goto err_bad_put;
|
||||||
errmsg = nlmsg_data(rep);
|
errmsg = nlmsg_data(rep);
|
||||||
errmsg->error = err;
|
errmsg->error = err;
|
||||||
unsafe_memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg)
|
errmsg->msg = *nlh;
|
||||||
? nlh->nlmsg_len : sizeof(*nlh),
|
|
||||||
/* Bounds checked by the skb layer. */);
|
if (!(flags & NLM_F_CAPPED)) {
|
||||||
|
if (!nlmsg_append(skb, nlmsg_len(nlh)))
|
||||||
|
goto err_bad_put;
|
||||||
|
|
||||||
|
memcpy(errmsg->msg.nlmsg_data, nlh->nlmsg_data,
|
||||||
|
nlmsg_len(nlh));
|
||||||
|
}
|
||||||
|
|
||||||
if (tlvlen)
|
if (tlvlen)
|
||||||
netlink_ack_tlv_fill(in_skb, skb, nlh, err, extack);
|
netlink_ack_tlv_fill(in_skb, skb, nlh, err, extack);
|
||||||
|
@ -2519,6 +2524,12 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
|
||||||
nlmsg_end(skb, rep);
|
nlmsg_end(skb, rep);
|
||||||
|
|
||||||
nlmsg_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid);
|
nlmsg_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
err_bad_put:
|
||||||
|
NETLINK_CB(in_skb).sk->sk_err = ENOBUFS;
|
||||||
|
sk_error_report(NETLINK_CB(in_skb).sk);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(netlink_ack);
|
EXPORT_SYMBOL(netlink_ack);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue