diff options
Diffstat (limited to 'net/netlink/af_netlink.c')
-rw-r--r-- | net/netlink/af_netlink.c | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index d46da6cb92e4..da3163d15ef0 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -1361,7 +1361,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, | |||
1361 | struct netlink_sock *nlk = nlk_sk(sk); | 1361 | struct netlink_sock *nlk = nlk_sk(sk); |
1362 | int noblock = flags&MSG_DONTWAIT; | 1362 | int noblock = flags&MSG_DONTWAIT; |
1363 | size_t copied; | 1363 | size_t copied; |
1364 | struct sk_buff *skb; | 1364 | struct sk_buff *skb, *frag __maybe_unused = NULL; |
1365 | int err; | 1365 | int err; |
1366 | 1366 | ||
1367 | if (flags&MSG_OOB) | 1367 | if (flags&MSG_OOB) |
@@ -1373,6 +1373,35 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, | |||
1373 | if (skb == NULL) | 1373 | if (skb == NULL) |
1374 | goto out; | 1374 | goto out; |
1375 | 1375 | ||
1376 | #ifdef CONFIG_COMPAT_NETLINK_MESSAGES | ||
1377 | if (unlikely(skb_shinfo(skb)->frag_list)) { | ||
1378 | bool need_compat = !!(flags & MSG_CMSG_COMPAT); | ||
1379 | |||
1380 | /* | ||
1381 | * If this skb has a frag_list, then here that means that | ||
1382 | * we will have to use the frag_list skb for compat tasks | ||
1383 | * and the regular skb for non-compat tasks. | ||
1384 | * | ||
1385 | * The skb might (and likely will) be cloned, so we can't | ||
1386 | * just reset frag_list and go on with things -- we need to | ||
1387 | * keep that. For the compat case that's easy -- simply get | ||
1388 | * a reference to the compat skb and free the regular one | ||
1389 | * including the frag. For the non-compat case, we need to | ||
1390 | * avoid sending the frag to the user -- so assign NULL but | ||
1391 | * restore it below before freeing the skb. | ||
1392 | */ | ||
1393 | if (need_compat) { | ||
1394 | struct sk_buff *compskb = skb_shinfo(skb)->frag_list; | ||
1395 | skb_get(compskb); | ||
1396 | kfree_skb(skb); | ||
1397 | skb = compskb; | ||
1398 | } else { | ||
1399 | frag = skb_shinfo(skb)->frag_list; | ||
1400 | skb_shinfo(skb)->frag_list = NULL; | ||
1401 | } | ||
1402 | } | ||
1403 | #endif | ||
1404 | |||
1376 | msg->msg_namelen = 0; | 1405 | msg->msg_namelen = 0; |
1377 | 1406 | ||
1378 | copied = skb->len; | 1407 | copied = skb->len; |
@@ -1403,6 +1432,11 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, | |||
1403 | siocb->scm->creds = *NETLINK_CREDS(skb); | 1432 | siocb->scm->creds = *NETLINK_CREDS(skb); |
1404 | if (flags & MSG_TRUNC) | 1433 | if (flags & MSG_TRUNC) |
1405 | copied = skb->len; | 1434 | copied = skb->len; |
1435 | |||
1436 | #ifdef CONFIG_COMPAT_NETLINK_MESSAGES | ||
1437 | skb_shinfo(skb)->frag_list = frag; | ||
1438 | #endif | ||
1439 | |||
1406 | skb_free_datagram(sk, skb); | 1440 | skb_free_datagram(sk, skb); |
1407 | 1441 | ||
1408 | if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) | 1442 | if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) |