diff options
author | Cong Wang <xiyou.wangcong@gmail.com> | 2018-12-29 16:56:36 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-12-30 17:07:54 -0500 |
commit | c433570458e49bccea5c551df628d058b3526289 (patch) | |
tree | 05427f71af7a74fb15b0eb08f138cc6004a225c1 /net/ax25 | |
parent | 7f334a7e1ae113212e39aafba51352ea9ab8c9f9 (diff) |
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>
Diffstat (limited to 'net/ax25')
-rw-r--r-- | net/ax25/af_ax25.c | 11 | ||||
-rw-r--r-- | net/ax25/ax25_dev.c | 2 |
2 files changed, 11 insertions, 2 deletions
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index c603d33d5410..5d01edf8d819 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c | |||
@@ -653,15 +653,22 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, | |||
653 | break; | 653 | break; |
654 | } | 654 | } |
655 | 655 | ||
656 | dev = dev_get_by_name(&init_net, devname); | 656 | rtnl_lock(); |
657 | dev = __dev_get_by_name(&init_net, devname); | ||
657 | if (!dev) { | 658 | if (!dev) { |
659 | rtnl_unlock(); | ||
658 | res = -ENODEV; | 660 | res = -ENODEV; |
659 | break; | 661 | break; |
660 | } | 662 | } |
661 | 663 | ||
662 | ax25->ax25_dev = ax25_dev_ax25dev(dev); | 664 | ax25->ax25_dev = ax25_dev_ax25dev(dev); |
665 | if (!ax25->ax25_dev) { | ||
666 | rtnl_unlock(); | ||
667 | res = -ENODEV; | ||
668 | break; | ||
669 | } | ||
663 | ax25_fillin_cb(ax25, ax25->ax25_dev); | 670 | ax25_fillin_cb(ax25, ax25->ax25_dev); |
664 | dev_put(dev); | 671 | rtnl_unlock(); |
665 | break; | 672 | break; |
666 | 673 | ||
667 | default: | 674 | default: |
diff --git a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c index 9a3a301e1e2f..d92195cd7834 100644 --- a/net/ax25/ax25_dev.c +++ b/net/ax25/ax25_dev.c | |||
@@ -116,6 +116,7 @@ void ax25_dev_device_down(struct net_device *dev) | |||
116 | if ((s = ax25_dev_list) == ax25_dev) { | 116 | if ((s = ax25_dev_list) == ax25_dev) { |
117 | ax25_dev_list = s->next; | 117 | ax25_dev_list = s->next; |
118 | spin_unlock_bh(&ax25_dev_lock); | 118 | spin_unlock_bh(&ax25_dev_lock); |
119 | dev->ax25_ptr = NULL; | ||
119 | dev_put(dev); | 120 | dev_put(dev); |
120 | kfree(ax25_dev); | 121 | kfree(ax25_dev); |
121 | return; | 122 | return; |
@@ -125,6 +126,7 @@ void ax25_dev_device_down(struct net_device *dev) | |||
125 | if (s->next == ax25_dev) { | 126 | if (s->next == ax25_dev) { |
126 | s->next = ax25_dev->next; | 127 | s->next = ax25_dev->next; |
127 | spin_unlock_bh(&ax25_dev_lock); | 128 | spin_unlock_bh(&ax25_dev_lock); |
129 | dev->ax25_ptr = NULL; | ||
128 | dev_put(dev); | 130 | dev_put(dev); |
129 | kfree(ax25_dev); | 131 | kfree(ax25_dev); |
130 | return; | 132 | return; |