Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1757,6 +1757,8 @@ extern int skb_copy_datagram_const_iovec(const struct sk_buff *from,
						     int to_offset,
						     int size);
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,
					 unsigned int flags);
extern __wsum	       skb_checksum(const struct sk_buff *skb, int offset,
+9 −1
Original line number Diff line number Diff line
@@ -224,6 +224,15 @@ void skb_free_datagram(struct sock *sk, struct sk_buff *skb)
	consume_skb(skb);
	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
@@ -752,5 +761,4 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,
EXPORT_SYMBOL(datagram_poll);
EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec);
EXPORT_SYMBOL(skb_copy_datagram_iovec);
EXPORT_SYMBOL(skb_free_datagram);
EXPORT_SYMBOL(skb_recv_datagram);
+1 −3
Original line number Diff line number Diff line
@@ -999,9 +999,7 @@ try_again:
		err = ulen;

out_free:
	lock_sock(sk);
	skb_free_datagram(sk, skb);
	release_sock(sk);
	skb_free_datagram_locked(sk, skb);
out:
	return err;

+1 −3
Original line number Diff line number Diff line
@@ -288,9 +288,7 @@ try_again:
		err = ulen;

out_free:
	lock_sock(sk);
	skb_free_datagram(sk, skb);
	release_sock(sk);
	skb_free_datagram_locked(sk, skb);
out:
	return err;

+5 −5
Original line number Diff line number Diff line
@@ -111,7 +111,7 @@ static void svc_release_skb(struct svc_rqst *rqstp)
		rqstp->rq_xprt_ctxt = NULL;

		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)
				"svc: received unknown control message %d/%d; "
				"dropping RPC reply datagram\n",
					cmh->cmsg_level, cmh->cmsg_type);
		skb_free_datagram(svsk->sk_sk, skb);
		skb_free_datagram_locked(svsk->sk_sk, skb);
		return 0;
	}

@@ -588,18 +588,18 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
		if (csum_partial_copy_to_xdr(&rqstp->rq_arg, skb)) {
			local_bh_enable();
			/* checksum error */
			skb_free_datagram(svsk->sk_sk, skb);
			skb_free_datagram_locked(svsk->sk_sk, skb);
			return 0;
		}
		local_bh_enable();
		skb_free_datagram(svsk->sk_sk, skb);
		skb_free_datagram_locked(svsk->sk_sk, skb);
	} else {
		/* we can use it in-place */
		rqstp->rq_arg.head[0].iov_base = skb->data +
			sizeof(struct udphdr);
		rqstp->rq_arg.head[0].iov_len = len;
		if (skb_checksum_complete(skb)) {
			skb_free_datagram(svsk->sk_sk, skb);
			skb_free_datagram_locked(svsk->sk_sk, skb);
			return 0;
		}
		rqstp->rq_xprt_ctxt = skb;