ipv6: add complete rcu protection around np->opt
This patch addresses multiple problems : UDP/RAW sendmsg() need to get a stable struct ipv6_txoptions while socket is not locked : Other threads can change np->opt concurrently. Dmitry posted a syzkaller (http://github.com/google/syzkaller) program desmonstrating use-after-free. Starting with TCP/DCCP lockless listeners, tcp_v6_syn_recv_sock() and dccp_v6_request_recv_sock() also need to use RCU protection to dereference np->opt once (before calling ipv6_dup_options()) This patch adds full RCU protection to np->opt Reported-by: Dmitry Vyukov <dvyukov@google.com> Signed-off-by: Eric Dumazet <edumazet@google.com> Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
01b3f52157
commit
45f6fad84c
@@ -78,7 +78,9 @@ struct dst_entry *inet6_csk_route_req(const struct sock *sk,
|
||||
memset(fl6, 0, sizeof(*fl6));
|
||||
fl6->flowi6_proto = proto;
|
||||
fl6->daddr = ireq->ir_v6_rmt_addr;
|
||||
final_p = fl6_update_dst(fl6, np->opt, &final);
|
||||
rcu_read_lock();
|
||||
final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
|
||||
rcu_read_unlock();
|
||||
fl6->saddr = ireq->ir_v6_loc_addr;
|
||||
fl6->flowi6_oif = ireq->ir_iif;
|
||||
fl6->flowi6_mark = ireq->ir_mark;
|
||||
@@ -142,7 +144,9 @@ static struct dst_entry *inet6_csk_route_socket(struct sock *sk,
|
||||
fl6->fl6_dport = inet->inet_dport;
|
||||
security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
|
||||
|
||||
final_p = fl6_update_dst(fl6, np->opt, &final);
|
||||
rcu_read_lock();
|
||||
final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
|
||||
rcu_read_unlock();
|
||||
|
||||
dst = __inet6_csk_dst_check(sk, np->dst_cookie);
|
||||
if (!dst) {
|
||||
@@ -175,7 +179,8 @@ int inet6_csk_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl_unused
|
||||
/* Restore final destination back after routing done */
|
||||
fl6.daddr = sk->sk_v6_daddr;
|
||||
|
||||
res = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
|
||||
res = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
|
||||
np->tclass);
|
||||
rcu_read_unlock();
|
||||
return res;
|
||||
}
|
||||
|
Reference in New Issue
Block a user