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
@@ -205,6 +205,7 @@ extern rwlock_t ip6_ra_lock;
|
||||
*/
|
||||
|
||||
struct ipv6_txoptions {
|
||||
atomic_t refcnt;
|
||||
/* Length of this structure */
|
||||
int tot_len;
|
||||
|
||||
@@ -217,7 +218,7 @@ struct ipv6_txoptions {
|
||||
struct ipv6_opt_hdr *dst0opt;
|
||||
struct ipv6_rt_hdr *srcrt; /* Routing Header */
|
||||
struct ipv6_opt_hdr *dst1opt;
|
||||
|
||||
struct rcu_head rcu;
|
||||
/* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */
|
||||
};
|
||||
|
||||
@@ -252,6 +253,24 @@ struct ipv6_fl_socklist {
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
static inline struct ipv6_txoptions *txopt_get(const struct ipv6_pinfo *np)
|
||||
{
|
||||
struct ipv6_txoptions *opt;
|
||||
|
||||
rcu_read_lock();
|
||||
opt = rcu_dereference(np->opt);
|
||||
if (opt && !atomic_inc_not_zero(&opt->refcnt))
|
||||
opt = NULL;
|
||||
rcu_read_unlock();
|
||||
return opt;
|
||||
}
|
||||
|
||||
static inline void txopt_put(struct ipv6_txoptions *opt)
|
||||
{
|
||||
if (opt && atomic_dec_and_test(&opt->refcnt))
|
||||
kfree_rcu(opt, rcu);
|
||||
}
|
||||
|
||||
struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label);
|
||||
struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space,
|
||||
struct ip6_flowlabel *fl,
|
||||
|
Reference in New Issue
Block a user