|
@@ -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)
|