Commit 1235f504aaba2ebeabc863fdb3ceac764a317d47

Authored by Eric Dumazet
Committed by David S. Miller
1 parent 7b5e078cf0

netlink: netlink_recvmsg() fix

commit 1dacc76d0014
(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>

Showing 1 changed file with 16 additions and 6 deletions Side-by-side Diff

net/netlink/af_netlink.c
... ... @@ -1406,7 +1406,7 @@
1406 1406 struct netlink_sock *nlk = nlk_sk(sk);
1407 1407 int noblock = flags&MSG_DONTWAIT;
1408 1408 size_t copied;
1409   - struct sk_buff *skb, *frag __maybe_unused = NULL;
  1409 + struct sk_buff *skb;
1410 1410 int err;
1411 1411  
1412 1412 if (flags&MSG_OOB)
... ... @@ -1441,7 +1441,21 @@
1441 1441 kfree_skb(skb);
1442 1442 skb = compskb;
1443 1443 } else {
1444   - frag = skb_shinfo(skb)->frag_list;
  1444 + /*
  1445 + * Before setting frag_list to NULL, we must get a
  1446 + * private copy of skb if shared (because of MSG_PEEK)
  1447 + */
  1448 + if (skb_shared(skb)) {
  1449 + struct sk_buff *nskb;
  1450 +
  1451 + nskb = pskb_copy(skb, GFP_KERNEL);
  1452 + kfree_skb(skb);
  1453 + skb = nskb;
  1454 + err = -ENOMEM;
  1455 + if (!skb)
  1456 + goto out;
  1457 + }
  1458 + kfree_skb(skb_shinfo(skb)->frag_list);
1445 1459 skb_shinfo(skb)->frag_list = NULL;
1446 1460 }
1447 1461 }
... ... @@ -1477,10 +1491,6 @@
1477 1491 siocb->scm->creds = *NETLINK_CREDS(skb);
1478 1492 if (flags & MSG_TRUNC)
1479 1493 copied = skb->len;
1480   -
1481   -#ifdef CONFIG_COMPAT_NETLINK_MESSAGES
1482   - skb_shinfo(skb)->frag_list = frag;
1483   -#endif
1484 1494  
1485 1495 skb_free_datagram(sk, skb);
1486 1496