Commit 9d410c79 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

net: fix sk_forward_alloc corruption

On UDP sockets, we must call skb_free_datagram() with socket locked,
or risk sk_forward_alloc corruption. This requirement is not respected
in SUNRPC.

Add a convenient helper, skb_free_datagram_locked() and use it in SUNRPC
Reported-by: default avatarFrancis Moreau <francis.moro@gmail.com>
Signed-off-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 63ca2d74
...@@ -1757,6 +1757,8 @@ extern int skb_copy_datagram_const_iovec(const struct sk_buff *from, ...@@ -1757,6 +1757,8 @@ extern int skb_copy_datagram_const_iovec(const struct sk_buff *from,
int to_offset, int to_offset,
int size); int size);
extern void skb_free_datagram(struct sock *sk, struct sk_buff *skb); extern void skb_free_datagram(struct sock *sk, struct sk_buff *skb);
extern void skb_free_datagram_locked(struct sock *sk,
struct sk_buff *skb);
extern int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, extern int skb_kill_datagram(struct sock *sk, struct sk_buff *skb,
unsigned int flags); unsigned int flags);
extern __wsum skb_checksum(const struct sk_buff *skb, int offset, extern __wsum skb_checksum(const struct sk_buff *skb, int offset,
......
...@@ -224,6 +224,15 @@ void skb_free_datagram(struct sock *sk, struct sk_buff *skb) ...@@ -224,6 +224,15 @@ void skb_free_datagram(struct sock *sk, struct sk_buff *skb)
consume_skb(skb); consume_skb(skb);
sk_mem_reclaim_partial(sk); sk_mem_reclaim_partial(sk);
} }
EXPORT_SYMBOL(skb_free_datagram);
void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb)
{
lock_sock(sk);
skb_free_datagram(sk, skb);
release_sock(sk);
}
EXPORT_SYMBOL(skb_free_datagram_locked);
/** /**
* skb_kill_datagram - Free a datagram skbuff forcibly * skb_kill_datagram - Free a datagram skbuff forcibly
...@@ -752,5 +761,4 @@ unsigned int datagram_poll(struct file *file, struct socket *sock, ...@@ -752,5 +761,4 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,
EXPORT_SYMBOL(datagram_poll); EXPORT_SYMBOL(datagram_poll);
EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec); EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec);
EXPORT_SYMBOL(skb_copy_datagram_iovec); EXPORT_SYMBOL(skb_copy_datagram_iovec);
EXPORT_SYMBOL(skb_free_datagram);
EXPORT_SYMBOL(skb_recv_datagram); EXPORT_SYMBOL(skb_recv_datagram);
...@@ -999,9 +999,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ...@@ -999,9 +999,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
err = ulen; err = ulen;
out_free: out_free:
lock_sock(sk); skb_free_datagram_locked(sk, skb);
skb_free_datagram(sk, skb);
release_sock(sk);
out: out:
return err; return err;
......
...@@ -288,9 +288,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, ...@@ -288,9 +288,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
err = ulen; err = ulen;
out_free: out_free:
lock_sock(sk); skb_free_datagram_locked(sk, skb);
skb_free_datagram(sk, skb);
release_sock(sk);
out: out:
return err; return err;
......
...@@ -111,7 +111,7 @@ static void svc_release_skb(struct svc_rqst *rqstp) ...@@ -111,7 +111,7 @@ static void svc_release_skb(struct svc_rqst *rqstp)
rqstp->rq_xprt_ctxt = NULL; rqstp->rq_xprt_ctxt = NULL;
dprintk("svc: service %p, releasing skb %p\n", rqstp, skb); dprintk("svc: service %p, releasing skb %p\n", rqstp, skb);
skb_free_datagram(svsk->sk_sk, skb); skb_free_datagram_locked(svsk->sk_sk, skb);
} }
} }
...@@ -578,7 +578,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) ...@@ -578,7 +578,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
"svc: received unknown control message %d/%d; " "svc: received unknown control message %d/%d; "
"dropping RPC reply datagram\n", "dropping RPC reply datagram\n",
cmh->cmsg_level, cmh->cmsg_type); cmh->cmsg_level, cmh->cmsg_type);
skb_free_datagram(svsk->sk_sk, skb); skb_free_datagram_locked(svsk->sk_sk, skb);
return 0; return 0;
} }
...@@ -588,18 +588,18 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) ...@@ -588,18 +588,18 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
if (csum_partial_copy_to_xdr(&rqstp->rq_arg, skb)) { if (csum_partial_copy_to_xdr(&rqstp->rq_arg, skb)) {
local_bh_enable(); local_bh_enable();
/* checksum error */ /* checksum error */
skb_free_datagram(svsk->sk_sk, skb); skb_free_datagram_locked(svsk->sk_sk, skb);
return 0; return 0;
} }
local_bh_enable(); local_bh_enable();
skb_free_datagram(svsk->sk_sk, skb); skb_free_datagram_locked(svsk->sk_sk, skb);
} else { } else {
/* we can use it in-place */ /* we can use it in-place */
rqstp->rq_arg.head[0].iov_base = skb->data + rqstp->rq_arg.head[0].iov_base = skb->data +
sizeof(struct udphdr); sizeof(struct udphdr);
rqstp->rq_arg.head[0].iov_len = len; rqstp->rq_arg.head[0].iov_len = len;
if (skb_checksum_complete(skb)) { if (skb_checksum_complete(skb)) {
skb_free_datagram(svsk->sk_sk, skb); skb_free_datagram_locked(svsk->sk_sk, skb);
return 0; return 0;
} }
rqstp->rq_xprt_ctxt = skb; rqstp->rq_xprt_ctxt = skb;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment