diff options
author | David S. Miller <davem@davemloft.net> | 2014-04-11 16:15:36 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-04-11 16:15:36 -0400 |
commit | 676d23690fb62b5d51ba5d659935e9f7d9da9f8e (patch) | |
tree | f6fbceee43e05c724868153ca37b702fb5e43b8c /net/rxrpc | |
parent | ad20d5f673898578f9d8a156d7a4c921f5ca4584 (diff) | |
download | linux-676d23690fb62b5d51ba5d659935e9f7d9da9f8e.tar.gz linux-676d23690fb62b5d51ba5d659935e9f7d9da9f8e.tar.bz2 linux-676d23690fb62b5d51ba5d659935e9f7d9da9f8e.zip |
net: Fix use after free by removing length arg from sk_data_ready callbacks.
Several spots in the kernel perform a sequence like:
skb_queue_tail(&sk->s_receive_queue, skb);
sk->sk_data_ready(sk, skb->len);
But at the moment we place the SKB onto the socket receive queue it
can be consumed and freed up. So this skb->len access is potentially
to freed up memory.
Furthermore, the skb->len can be modified by the consumer so it is
possible that the value isn't accurate.
And finally, no actual implementation of this callback actually uses
the length argument. And since nobody actually cared about it's
value, lots of call sites pass arbitrary values in such as '0' and
even '1'.
So just remove the length argument from the callback, that way there
is no confusion whatsoever and all of these use-after-free cases get
fixed as a side effect.
Based upon a patch by Eric Dumazet and his suggestion to audit this
issue tree-wide.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/rxrpc')
-rw-r--r-- | net/rxrpc/ar-input.c | 6 | ||||
-rw-r--r-- | net/rxrpc/ar-internal.h | 2 |
2 files changed, 4 insertions, 4 deletions
diff --git a/net/rxrpc/ar-input.c b/net/rxrpc/ar-input.c index 73742647c135..63b21e580de9 100644 --- a/net/rxrpc/ar-input.c +++ b/net/rxrpc/ar-input.c @@ -113,7 +113,7 @@ int rxrpc_queue_rcv_skb(struct rxrpc_call *call, struct sk_buff *skb, spin_unlock_bh(&sk->sk_receive_queue.lock); if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_data_ready(sk, skb_len); + sk->sk_data_ready(sk); } skb = NULL; } else { @@ -632,14 +632,14 @@ cant_find_conn: * handle data received on the local endpoint * - may be called in interrupt context */ -void rxrpc_data_ready(struct sock *sk, int count) +void rxrpc_data_ready(struct sock *sk) { struct rxrpc_skb_priv *sp; struct rxrpc_local *local; struct sk_buff *skb; int ret; - _enter("%p, %d", sk, count); + _enter("%p", sk); ASSERT(!irqs_disabled()); diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index c831d44b0841..ba9fd36d3f15 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -518,7 +518,7 @@ void rxrpc_UDP_error_handler(struct work_struct *); */ extern const char *rxrpc_pkts[]; -void rxrpc_data_ready(struct sock *, int); +void rxrpc_data_ready(struct sock *); int rxrpc_queue_rcv_skb(struct rxrpc_call *, struct sk_buff *, bool, bool); void rxrpc_fast_process_packet(struct rxrpc_call *, struct sk_buff *); |