提交 c77a8a39 编写于 作者: D Duoming Zhou 提交者: Zheng Zengkai

ax25: fix reference count leaks of ax25_dev

stable inclusion
from stable-v5.10.112
commit 5ddae8d064412ed868610127561652e90acabeea
bugzilla: 186602, https://gitee.com/src-openeuler/kernel/issues/I5783H
CVE: CVE-2022-1204

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=5ddae8d064412ed868610127561652e90acabeea

--------------------------------

commit 87563a04 upstream.

The previous commit d01ffb9e ("ax25: add refcount in ax25_dev
to avoid UAF bugs") introduces refcount into ax25_dev, but there
are reference leak paths in ax25_ctl_ioctl(), ax25_fwd_ioctl(),
ax25_rt_add(), ax25_rt_del() and ax25_rt_opt().

This patch uses ax25_dev_put() and adjusts the position of
ax25_addr_ax25dev() to fix reference cout leaks of ax25_dev.

Fixes: d01ffb9e ("ax25: add refcount in ax25_dev to avoid UAF bugs")
Signed-off-by: NDuoming Zhou <duoming@zju.edu.cn>
Reviewed-by: NDan Carpenter <dan.carpenter@oracle.com>
Link: https://lore.kernel.org/r/20220203150811.42256-1-duoming@zju.edu.cnSigned-off-by: NJakub Kicinski <kuba@kernel.org>
[OP: backport to 5.10: adjust context]
Signed-off-by: NOvidiu Panait <ovidiu.panait@windriver.com>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: NLu Wei <luwei32@huawei.com>
Reviewed-by: NWei Yongjun <weiyongjun1@huawei.com>
Reviewed-by: NXiu Jianfeng <xiujianfeng@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 cd574ba1
...@@ -291,10 +291,12 @@ static __inline__ void ax25_cb_put(ax25_cb *ax25) ...@@ -291,10 +291,12 @@ static __inline__ void ax25_cb_put(ax25_cb *ax25)
} }
} }
#define ax25_dev_hold(__ax25_dev) \ static inline void ax25_dev_hold(ax25_dev *ax25_dev)
refcount_inc(&((__ax25_dev)->refcount)) {
refcount_inc(&ax25_dev->refcount);
}
static __inline__ void ax25_dev_put(ax25_dev *ax25_dev) static inline void ax25_dev_put(ax25_dev *ax25_dev)
{ {
if (refcount_dec_and_test(&ax25_dev->refcount)) { if (refcount_dec_and_test(&ax25_dev->refcount)) {
kfree(ax25_dev); kfree(ax25_dev);
......
...@@ -366,21 +366,25 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg) ...@@ -366,21 +366,25 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg)
if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl))) if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl)))
return -EFAULT; return -EFAULT;
if ((ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr)) == NULL)
return -ENODEV;
if (ax25_ctl.digi_count > AX25_MAX_DIGIS) if (ax25_ctl.digi_count > AX25_MAX_DIGIS)
return -EINVAL; return -EINVAL;
if (ax25_ctl.arg > ULONG_MAX / HZ && ax25_ctl.cmd != AX25_KILL) if (ax25_ctl.arg > ULONG_MAX / HZ && ax25_ctl.cmd != AX25_KILL)
return -EINVAL; return -EINVAL;
ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr);
if (!ax25_dev)
return -ENODEV;
digi.ndigi = ax25_ctl.digi_count; digi.ndigi = ax25_ctl.digi_count;
for (k = 0; k < digi.ndigi; k++) for (k = 0; k < digi.ndigi; k++)
digi.calls[k] = ax25_ctl.digi_addr[k]; digi.calls[k] = ax25_ctl.digi_addr[k];
if ((ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev)) == NULL) ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev);
if (!ax25) {
ax25_dev_put(ax25_dev);
return -ENOTCONN; return -ENOTCONN;
}
switch (ax25_ctl.cmd) { switch (ax25_ctl.cmd) {
case AX25_KILL: case AX25_KILL:
......
...@@ -85,8 +85,8 @@ void ax25_dev_device_up(struct net_device *dev) ...@@ -85,8 +85,8 @@ void ax25_dev_device_up(struct net_device *dev)
spin_lock_bh(&ax25_dev_lock); spin_lock_bh(&ax25_dev_lock);
ax25_dev->next = ax25_dev_list; ax25_dev->next = ax25_dev_list;
ax25_dev_list = ax25_dev; ax25_dev_list = ax25_dev;
ax25_dev_hold(ax25_dev);
spin_unlock_bh(&ax25_dev_lock); spin_unlock_bh(&ax25_dev_lock);
ax25_dev_hold(ax25_dev);
ax25_register_dev_sysctl(ax25_dev); ax25_register_dev_sysctl(ax25_dev);
} }
...@@ -115,8 +115,8 @@ void ax25_dev_device_down(struct net_device *dev) ...@@ -115,8 +115,8 @@ 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;
ax25_dev_put(ax25_dev);
spin_unlock_bh(&ax25_dev_lock); spin_unlock_bh(&ax25_dev_lock);
ax25_dev_put(ax25_dev);
dev->ax25_ptr = NULL; dev->ax25_ptr = NULL;
dev_put(dev); dev_put(dev);
ax25_dev_put(ax25_dev); ax25_dev_put(ax25_dev);
...@@ -126,8 +126,8 @@ void ax25_dev_device_down(struct net_device *dev) ...@@ -126,8 +126,8 @@ void ax25_dev_device_down(struct net_device *dev)
while (s != NULL && s->next != NULL) { while (s != NULL && s->next != NULL) {
if (s->next == ax25_dev) { if (s->next == ax25_dev) {
s->next = ax25_dev->next; s->next = ax25_dev->next;
ax25_dev_put(ax25_dev);
spin_unlock_bh(&ax25_dev_lock); spin_unlock_bh(&ax25_dev_lock);
ax25_dev_put(ax25_dev);
dev->ax25_ptr = NULL; dev->ax25_ptr = NULL;
dev_put(dev); dev_put(dev);
ax25_dev_put(ax25_dev); ax25_dev_put(ax25_dev);
...@@ -150,25 +150,35 @@ int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd) ...@@ -150,25 +150,35 @@ int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
switch (cmd) { switch (cmd) {
case SIOCAX25ADDFWD: case SIOCAX25ADDFWD:
if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL) fwd_dev = ax25_addr_ax25dev(&fwd->port_to);
if (!fwd_dev) {
ax25_dev_put(ax25_dev);
return -EINVAL; return -EINVAL;
if (ax25_dev->forward != NULL) }
if (ax25_dev->forward) {
ax25_dev_put(fwd_dev);
ax25_dev_put(ax25_dev);
return -EINVAL; return -EINVAL;
}
ax25_dev->forward = fwd_dev->dev; ax25_dev->forward = fwd_dev->dev;
ax25_dev_put(fwd_dev); ax25_dev_put(fwd_dev);
ax25_dev_put(ax25_dev);
break; break;
case SIOCAX25DELFWD: case SIOCAX25DELFWD:
if (ax25_dev->forward == NULL) if (!ax25_dev->forward) {
ax25_dev_put(ax25_dev);
return -EINVAL; return -EINVAL;
}
ax25_dev->forward = NULL; ax25_dev->forward = NULL;
ax25_dev_put(ax25_dev);
break; break;
default: default:
ax25_dev_put(ax25_dev);
return -EINVAL; return -EINVAL;
} }
ax25_dev_put(ax25_dev);
return 0; return 0;
} }
......
...@@ -75,11 +75,13 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route) ...@@ -75,11 +75,13 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
ax25_dev *ax25_dev; ax25_dev *ax25_dev;
int i; int i;
if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
return -EINVAL;
if (route->digi_count > AX25_MAX_DIGIS) if (route->digi_count > AX25_MAX_DIGIS)
return -EINVAL; return -EINVAL;
ax25_dev = ax25_addr_ax25dev(&route->port_addr);
if (!ax25_dev)
return -EINVAL;
write_lock_bh(&ax25_route_lock); write_lock_bh(&ax25_route_lock);
ax25_rt = ax25_route_list; ax25_rt = ax25_route_list;
...@@ -91,6 +93,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route) ...@@ -91,6 +93,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
if (route->digi_count != 0) { if (route->digi_count != 0) {
if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
write_unlock_bh(&ax25_route_lock); write_unlock_bh(&ax25_route_lock);
ax25_dev_put(ax25_dev);
return -ENOMEM; return -ENOMEM;
} }
ax25_rt->digipeat->lastrepeat = -1; ax25_rt->digipeat->lastrepeat = -1;
...@@ -101,6 +104,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route) ...@@ -101,6 +104,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
} }
} }
write_unlock_bh(&ax25_route_lock); write_unlock_bh(&ax25_route_lock);
ax25_dev_put(ax25_dev);
return 0; return 0;
} }
ax25_rt = ax25_rt->next; ax25_rt = ax25_rt->next;
...@@ -108,6 +112,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route) ...@@ -108,6 +112,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) { if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) {
write_unlock_bh(&ax25_route_lock); write_unlock_bh(&ax25_route_lock);
ax25_dev_put(ax25_dev);
return -ENOMEM; return -ENOMEM;
} }
...@@ -116,11 +121,11 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route) ...@@ -116,11 +121,11 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
ax25_rt->dev = ax25_dev->dev; ax25_rt->dev = ax25_dev->dev;
ax25_rt->digipeat = NULL; ax25_rt->digipeat = NULL;
ax25_rt->ip_mode = ' '; ax25_rt->ip_mode = ' ';
ax25_dev_put(ax25_dev);
if (route->digi_count != 0) { if (route->digi_count != 0) {
if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
write_unlock_bh(&ax25_route_lock); write_unlock_bh(&ax25_route_lock);
kfree(ax25_rt); kfree(ax25_rt);
ax25_dev_put(ax25_dev);
return -ENOMEM; return -ENOMEM;
} }
ax25_rt->digipeat->lastrepeat = -1; ax25_rt->digipeat->lastrepeat = -1;
...@@ -133,6 +138,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route) ...@@ -133,6 +138,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
ax25_rt->next = ax25_route_list; ax25_rt->next = ax25_route_list;
ax25_route_list = ax25_rt; ax25_route_list = ax25_rt;
write_unlock_bh(&ax25_route_lock); write_unlock_bh(&ax25_route_lock);
ax25_dev_put(ax25_dev);
return 0; return 0;
} }
...@@ -173,8 +179,8 @@ static int ax25_rt_del(struct ax25_routes_struct *route) ...@@ -173,8 +179,8 @@ static int ax25_rt_del(struct ax25_routes_struct *route)
} }
} }
} }
ax25_dev_put(ax25_dev);
write_unlock_bh(&ax25_route_lock); write_unlock_bh(&ax25_route_lock);
ax25_dev_put(ax25_dev);
return 0; return 0;
} }
...@@ -216,8 +222,8 @@ static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option) ...@@ -216,8 +222,8 @@ static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option)
} }
out: out:
ax25_dev_put(ax25_dev);
write_unlock_bh(&ax25_route_lock); write_unlock_bh(&ax25_route_lock);
ax25_dev_put(ax25_dev);
return err; return err;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册