diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index da869ce..c385f13 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -553,6 +553,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int ulen = len; struct ipcm_cookie ipc; struct rtable *rt = NULL; + int rt_release = 0; int free = 0; int connected = 0; __be32 daddr, faddr, saddr; @@ -656,8 +657,9 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, connected = 0; } + rcu_read_lock(); if (connected) - rt = (struct rtable*)sk_dst_check(sk, 0); + rt = (struct rtable *)__sk_dst_check(sk, 0); if (rt == NULL) { struct flowi fl = { .oif = ipc.oif, @@ -681,11 +683,14 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, } err = -EACCES; + rt_release = 1; if ((rt->rt_flags & RTCF_BROADCAST) && !sock_flag(sk, SOCK_BROADCAST)) goto out; - if (connected) - sk_dst_set(sk, dst_clone(&rt->u.dst)); + if (connected) { + sk_dst_set(sk, &rt->u.dst); + rt_release = 0; + } } if (msg->msg_flags&MSG_CONFIRM) @@ -730,7 +735,9 @@ do_append_data: release_sock(sk); out: - ip_rt_put(rt); + if (rt_release) + ip_rt_put(rt); + rcu_read_unlock(); if (free) kfree(ipc.opt); if (!err)