Skip to content

Commit 706cc36

Browse files
q2venkuba-moo
authored andcommitted
atm: clip: Fix potential null-ptr-deref in to_atmarpd().
atmarpd is protected by RTNL since commit f3a0592 ("[ATM]: clip causes unregister hang"). However, it is not enough because to_atmarpd() is called without RTNL, especially clip_neigh_solicit() / neigh_ops->solicit() is unsleepable. Also, there is no RTNL dependency around atmarpd. Let's use a private mutex and RCU to protect access to atmarpd in to_atmarpd(). Fixes: 1da177e ("Linux-2.6.12-rc2") Signed-off-by: Kuniyuki Iwashima <[email protected]> Reviewed-by: Simon Horman <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 3c78f91 commit 706cc36

File tree

1 file changed

+29
-15
lines changed

1 file changed

+29
-15
lines changed

net/atm/clip.c

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,32 +45,44 @@
4545
#include <net/atmclip.h>
4646

4747
static struct net_device *clip_devs;
48-
static struct atm_vcc *atmarpd;
48+
static struct atm_vcc __rcu *atmarpd;
49+
static DEFINE_MUTEX(atmarpd_lock);
4950
static struct timer_list idle_timer;
5051
static const struct neigh_ops clip_neigh_ops;
5152

5253
static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip)
5354
{
5455
struct sock *sk;
5556
struct atmarp_ctrl *ctrl;
57+
struct atm_vcc *vcc;
5658
struct sk_buff *skb;
59+
int err = 0;
5760

5861
pr_debug("(%d)\n", type);
59-
if (!atmarpd)
60-
return -EUNATCH;
62+
63+
rcu_read_lock();
64+
vcc = rcu_dereference(atmarpd);
65+
if (!vcc) {
66+
err = -EUNATCH;
67+
goto unlock;
68+
}
6169
skb = alloc_skb(sizeof(struct atmarp_ctrl), GFP_ATOMIC);
62-
if (!skb)
63-
return -ENOMEM;
70+
if (!skb) {
71+
err = -ENOMEM;
72+
goto unlock;
73+
}
6474
ctrl = skb_put(skb, sizeof(struct atmarp_ctrl));
6575
ctrl->type = type;
6676
ctrl->itf_num = itf;
6777
ctrl->ip = ip;
68-
atm_force_charge(atmarpd, skb->truesize);
78+
atm_force_charge(vcc, skb->truesize);
6979

70-
sk = sk_atm(atmarpd);
80+
sk = sk_atm(vcc);
7181
skb_queue_tail(&sk->sk_receive_queue, skb);
7282
sk->sk_data_ready(sk);
73-
return 0;
83+
unlock:
84+
rcu_read_unlock();
85+
return err;
7486
}
7587

7688
static void link_vcc(struct clip_vcc *clip_vcc, struct atmarp_entry *entry)
@@ -607,10 +619,12 @@ static void atmarpd_close(struct atm_vcc *vcc)
607619
{
608620
pr_debug("\n");
609621

610-
rtnl_lock();
611-
atmarpd = NULL;
622+
mutex_lock(&atmarpd_lock);
623+
RCU_INIT_POINTER(atmarpd, NULL);
624+
mutex_unlock(&atmarpd_lock);
625+
626+
synchronize_rcu();
612627
skb_queue_purge(&sk_atm(vcc)->sk_receive_queue);
613-
rtnl_unlock();
614628

615629
pr_debug("(done)\n");
616630
module_put(THIS_MODULE);
@@ -631,15 +645,15 @@ static struct atm_dev atmarpd_dev = {
631645

632646
static int atm_init_atmarp(struct atm_vcc *vcc)
633647
{
634-
rtnl_lock();
648+
mutex_lock(&atmarpd_lock);
635649
if (atmarpd) {
636-
rtnl_unlock();
650+
mutex_unlock(&atmarpd_lock);
637651
return -EADDRINUSE;
638652
}
639653

640654
mod_timer(&idle_timer, jiffies + CLIP_CHECK_INTERVAL * HZ);
641655

642-
atmarpd = vcc;
656+
rcu_assign_pointer(atmarpd, vcc);
643657
set_bit(ATM_VF_META, &vcc->flags);
644658
set_bit(ATM_VF_READY, &vcc->flags);
645659
/* allow replies and avoid getting closed if signaling dies */
@@ -648,7 +662,7 @@ static int atm_init_atmarp(struct atm_vcc *vcc)
648662
vcc->push = NULL;
649663
vcc->pop = NULL; /* crash */
650664
vcc->push_oam = NULL; /* crash */
651-
rtnl_unlock();
665+
mutex_unlock(&atmarpd_lock);
652666
return 0;
653667
}
654668

0 commit comments

Comments
 (0)