| From e18f0e6509ebb2ed91524ab5b591218445998b92 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 15 Sep 2023 19:20:41 +0800 |
| Subject: xfrm6: fix inet6_dev refcount underflow problem |
| |
| From: Zhang Changzhong <zhangchangzhong@huawei.com> |
| |
| [ Upstream commit cc9b364bb1d58d3dae270c7a931a8cc717dc2b3b ] |
| |
| There are race conditions that may lead to inet6_dev refcount underflow |
| in xfrm6_dst_destroy() and rt6_uncached_list_flush_dev(). |
| |
| One of the refcount underflow bugs is shown below: |
| (cpu 1) | (cpu 2) |
| xfrm6_dst_destroy() | |
| ... | |
| in6_dev_put() | |
| | rt6_uncached_list_flush_dev() |
| ... | ... |
| | in6_dev_put() |
| rt6_uncached_list_del() | ... |
| ... | |
| |
| xfrm6_dst_destroy() calls rt6_uncached_list_del() after in6_dev_put(), |
| so rt6_uncached_list_flush_dev() has a chance to call in6_dev_put() |
| again for the same inet6_dev. |
| |
| Fix it by moving in6_dev_put() after rt6_uncached_list_del() in |
| xfrm6_dst_destroy(). |
| |
| Fixes: 510c321b5571 ("xfrm: reuse uncached_list to track xdsts") |
| Signed-off-by: Zhang Changzhong <zhangchangzhong@huawei.com> |
| Reviewed-by: Xin Long <lucien.xin@gmail.com> |
| Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ipv6/xfrm6_policy.c | 4 ++-- |
| 1 file changed, 2 insertions(+), 2 deletions(-) |
| |
| --- a/net/ipv6/xfrm6_policy.c |
| +++ b/net/ipv6/xfrm6_policy.c |
| @@ -120,11 +120,11 @@ static void xfrm6_dst_destroy(struct dst |
| { |
| struct xfrm_dst *xdst = (struct xfrm_dst *)dst; |
| |
| - if (likely(xdst->u.rt6.rt6i_idev)) |
| - in6_dev_put(xdst->u.rt6.rt6i_idev); |
| dst_destroy_metrics_generic(dst); |
| if (xdst->u.rt6.rt6i_uncached_list) |
| rt6_uncached_list_del(&xdst->u.rt6); |
| + if (likely(xdst->u.rt6.rt6i_idev)) |
| + in6_dev_put(xdst->u.rt6.rt6i_idev); |
| xfrm_dst_destroy(xdst); |
| } |
| |