ax25: fix a use-after-free in ax25_fillin_cb()
There are multiple issues here: 1. After freeing dev->ax25_ptr, we need to set it to NULL otherwise we may use a dangling pointer. 2. There is a race between ax25_setsockopt() and device notifier as reported by syzbot. Close it by holding RTNL lock. 3. We need to test if dev->ax25_ptr is NULL before using it. Reported-and-tested-by: syzbot+ae6bb869cbed29b29040@syzkaller.appspotmail.com Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
7f334a7e1a
commit
c433570458
@ -653,15 +653,22 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = dev_get_by_name(&init_net, devname);
|
rtnl_lock();
|
||||||
|
dev = __dev_get_by_name(&init_net, devname);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
|
rtnl_unlock();
|
||||||
res = -ENODEV;
|
res = -ENODEV;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ax25->ax25_dev = ax25_dev_ax25dev(dev);
|
ax25->ax25_dev = ax25_dev_ax25dev(dev);
|
||||||
|
if (!ax25->ax25_dev) {
|
||||||
|
rtnl_unlock();
|
||||||
|
res = -ENODEV;
|
||||||
|
break;
|
||||||
|
}
|
||||||
ax25_fillin_cb(ax25, ax25->ax25_dev);
|
ax25_fillin_cb(ax25, ax25->ax25_dev);
|
||||||
dev_put(dev);
|
rtnl_unlock();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -116,6 +116,7 @@ void ax25_dev_device_down(struct net_device *dev)
|
|||||||
if ((s = ax25_dev_list) == ax25_dev) {
|
if ((s = ax25_dev_list) == ax25_dev) {
|
||||||
ax25_dev_list = s->next;
|
ax25_dev_list = s->next;
|
||||||
spin_unlock_bh(&ax25_dev_lock);
|
spin_unlock_bh(&ax25_dev_lock);
|
||||||
|
dev->ax25_ptr = NULL;
|
||||||
dev_put(dev);
|
dev_put(dev);
|
||||||
kfree(ax25_dev);
|
kfree(ax25_dev);
|
||||||
return;
|
return;
|
||||||
@ -125,6 +126,7 @@ void ax25_dev_device_down(struct net_device *dev)
|
|||||||
if (s->next == ax25_dev) {
|
if (s->next == ax25_dev) {
|
||||||
s->next = ax25_dev->next;
|
s->next = ax25_dev->next;
|
||||||
spin_unlock_bh(&ax25_dev_lock);
|
spin_unlock_bh(&ax25_dev_lock);
|
||||||
|
dev->ax25_ptr = NULL;
|
||||||
dev_put(dev);
|
dev_put(dev);
|
||||||
kfree(ax25_dev);
|
kfree(ax25_dev);
|
||||||
return;
|
return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user