forked from Minki/linux
netlink: netlink_recvmsg() fix
commit 1dacc76d00
(net/compat/wext: send different messages to compat tasks)
introduced a race condition on netlink, in case MSG_PEEK is used.
An skb given by skb_recv_datagram() might be shared, we must copy it
before any modification, or risk fatal corruption.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
7b5e078cf0
commit
1235f504aa
@ -1406,7 +1406,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
|
||||
struct netlink_sock *nlk = nlk_sk(sk);
|
||||
int noblock = flags&MSG_DONTWAIT;
|
||||
size_t copied;
|
||||
struct sk_buff *skb, *frag __maybe_unused = NULL;
|
||||
struct sk_buff *skb;
|
||||
int err;
|
||||
|
||||
if (flags&MSG_OOB)
|
||||
@ -1441,7 +1441,21 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
|
||||
kfree_skb(skb);
|
||||
skb = compskb;
|
||||
} else {
|
||||
frag = skb_shinfo(skb)->frag_list;
|
||||
/*
|
||||
* Before setting frag_list to NULL, we must get a
|
||||
* private copy of skb if shared (because of MSG_PEEK)
|
||||
*/
|
||||
if (skb_shared(skb)) {
|
||||
struct sk_buff *nskb;
|
||||
|
||||
nskb = pskb_copy(skb, GFP_KERNEL);
|
||||
kfree_skb(skb);
|
||||
skb = nskb;
|
||||
err = -ENOMEM;
|
||||
if (!skb)
|
||||
goto out;
|
||||
}
|
||||
kfree_skb(skb_shinfo(skb)->frag_list);
|
||||
skb_shinfo(skb)->frag_list = NULL;
|
||||
}
|
||||
}
|
||||
@ -1478,10 +1492,6 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
|
||||
if (flags & MSG_TRUNC)
|
||||
copied = skb->len;
|
||||
|
||||
#ifdef CONFIG_COMPAT_NETLINK_MESSAGES
|
||||
skb_shinfo(skb)->frag_list = frag;
|
||||
#endif
|
||||
|
||||
skb_free_datagram(sk, skb);
|
||||
|
||||
if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2)
|
||||
|
Loading…
Reference in New Issue
Block a user