]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/net/gtp.c
gtp: fix use-after-free in gtp_encap_destroy()
[linux.git] / drivers / net / gtp.c
index 939da5442f6558e66cf8f468f81c4b19cb0c6fe6..5101f8c3c99cb1baf37cd6f0cc6bd69fafc2a15a 100644 (file)
@@ -285,13 +285,17 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
        return gtp_rx(pctx, skb, hdrlen, gtp->role);
 }
 
-static void gtp_encap_destroy(struct sock *sk)
+static void __gtp_encap_destroy(struct sock *sk)
 {
        struct gtp_dev *gtp;
 
        lock_sock(sk);
        gtp = sk->sk_user_data;
        if (gtp) {
+               if (gtp->sk0 == sk)
+                       gtp->sk0 = NULL;
+               else
+                       gtp->sk1u = NULL;
                udp_sk(sk)->encap_type = 0;
                rcu_assign_sk_user_data(sk, NULL);
                sock_put(sk);
@@ -299,12 +303,19 @@ static void gtp_encap_destroy(struct sock *sk)
        release_sock(sk);
 }
 
+static void gtp_encap_destroy(struct sock *sk)
+{
+       rtnl_lock();
+       __gtp_encap_destroy(sk);
+       rtnl_unlock();
+}
+
 static void gtp_encap_disable_sock(struct sock *sk)
 {
        if (!sk)
                return;
 
-       gtp_encap_destroy(sk);
+       __gtp_encap_destroy(sk);
 }
 
 static void gtp_encap_disable(struct gtp_dev *gtp)
@@ -1038,6 +1049,7 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
                return -EINVAL;
        }
 
+       rtnl_lock();
        rcu_read_lock();
 
        gtp = gtp_find_dev(sock_net(skb->sk), info->attrs);
@@ -1062,6 +1074,7 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
 
 out_unlock:
        rcu_read_unlock();
+       rtnl_unlock();
        return err;
 }