Merge branch 'gtp-fix-several-bugs'
Taehee Yoo says: ==================== gtp: fix several bugs This patch series fixes several bugs in the gtp module. First patch fixes suspicious RCU usage. The problem is to use rcu_dereference_sk_user_data() outside of RCU read critical section. Second patch fixes use-after-free. gtp_encap_destroy() is called twice. gtp_encap_destroy() use both gtp->sk0 and gtp->sk1u. these pointers can be freed in gtp_encap_destroy(). So, gtp_encap_destroy() should avoid using freed sk pointer. Third patch removes duplicate code in gtp_dellink(). gtp_dellink() calls gtp_encap_disable() twice. So, remove one of them. Fourth patch fixes usage of GFP_KERNEL. GFP_KERNEL can not be used in RCU read critical section. This patch make ipv4_pdp_add() to use GFP_ATOMIC instead of GFP_KERNEL. Fifth patch fixes use-after-free in gtp_newlink(). gtp_newlink() uses gtp_net which would be destroyed by the __exit_net routine. So, gtp_newlink should not be called after the __exit_net routine. Sixth patch adds missing error handling routine in gtp_encap_enable(). gtp_encap_enable() will fail, if invalid role value is sent from user-space. if so, gtp_encap_enable() should execute error handling routine. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
0799678349
@ -285,16 +285,29 @@ 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;
|
||||
|
||||
gtp = rcu_dereference_sk_user_data(sk);
|
||||
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);
|
||||
}
|
||||
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)
|
||||
@ -302,7 +315,7 @@ 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)
|
||||
@ -681,7 +694,6 @@ static void gtp_dellink(struct net_device *dev, struct list_head *head)
|
||||
{
|
||||
struct gtp_dev *gtp = netdev_priv(dev);
|
||||
|
||||
gtp_encap_disable(gtp);
|
||||
gtp_hashtable_free(gtp);
|
||||
list_del_rcu(>p->list);
|
||||
unregister_netdevice_queue(dev, head);
|
||||
@ -796,7 +808,8 @@ static struct sock *gtp_encap_enable_socket(int fd, int type,
|
||||
goto out_sock;
|
||||
}
|
||||
|
||||
if (rcu_dereference_sk_user_data(sock->sk)) {
|
||||
lock_sock(sock->sk);
|
||||
if (sock->sk->sk_user_data) {
|
||||
sk = ERR_PTR(-EBUSY);
|
||||
goto out_sock;
|
||||
}
|
||||
@ -812,6 +825,7 @@ static struct sock *gtp_encap_enable_socket(int fd, int type,
|
||||
setup_udp_tunnel_sock(sock_net(sock->sk), sock, &tuncfg);
|
||||
|
||||
out_sock:
|
||||
release_sock(sock->sk);
|
||||
sockfd_put(sock);
|
||||
return sk;
|
||||
}
|
||||
@ -843,8 +857,13 @@ static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[])
|
||||
|
||||
if (data[IFLA_GTP_ROLE]) {
|
||||
role = nla_get_u32(data[IFLA_GTP_ROLE]);
|
||||
if (role > GTP_ROLE_SGSN)
|
||||
if (role > GTP_ROLE_SGSN) {
|
||||
if (sk0)
|
||||
gtp_encap_disable_sock(sk0);
|
||||
if (sk1u)
|
||||
gtp_encap_disable_sock(sk1u);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
gtp->sk0 = sk0;
|
||||
@ -945,7 +964,7 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct sock *sk,
|
||||
|
||||
}
|
||||
|
||||
pctx = kmalloc(sizeof(struct pdp_ctx), GFP_KERNEL);
|
||||
pctx = kmalloc(sizeof(*pctx), GFP_ATOMIC);
|
||||
if (pctx == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -1034,6 +1053,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);
|
||||
@ -1058,6 +1078,7 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
rtnl_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1360,9 +1381,9 @@ late_initcall(gtp_init);
|
||||
|
||||
static void __exit gtp_fini(void)
|
||||
{
|
||||
unregister_pernet_subsys(>p_net_ops);
|
||||
genl_unregister_family(>p_genl_family);
|
||||
rtnl_link_unregister(>p_link_ops);
|
||||
unregister_pernet_subsys(>p_net_ops);
|
||||
|
||||
pr_info("GTP module unloaded\n");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user