| From bippy-1.2.0 Mon Sep 17 00:00:00 2001 |
| From: Greg Kroah-Hartman <gregkh@kernel.org> |
| To: <linux-cve-announce@vger.kernel.org> |
| Reply-to: <cve@kernel.org>, <linux-kernel@vger.kernel.org> |
| Subject: CVE-2025-22111: net: Remove RTNL dance for SIOCBRADDIF and SIOCBRDELIF. |
| |
| Description |
| =========== |
| |
| In the Linux kernel, the following vulnerability has been resolved: |
| |
| net: Remove RTNL dance for SIOCBRADDIF and SIOCBRDELIF. |
| |
| SIOCBRDELIF is passed to dev_ioctl() first and later forwarded to |
| br_ioctl_call(), which causes unnecessary RTNL dance and the splat |
| below [0] under RTNL pressure. |
| |
| Let's say Thread A is trying to detach a device from a bridge and |
| Thread B is trying to remove the bridge. |
| |
| In dev_ioctl(), Thread A bumps the bridge device's refcnt by |
| netdev_hold() and releases RTNL because the following br_ioctl_call() |
| also re-acquires RTNL. |
| |
| In the race window, Thread B could acquire RTNL and try to remove |
| the bridge device. Then, rtnl_unlock() by Thread B will release RTNL |
| and wait for netdev_put() by Thread A. |
| |
| Thread A, however, must hold RTNL after the unlock in dev_ifsioc(), |
| which may take long under RTNL pressure, resulting in the splat by |
| Thread B. |
| |
| Thread A (SIOCBRDELIF) Thread B (SIOCBRDELBR) |
| ---------------------- ---------------------- |
| sock_ioctl sock_ioctl |
| `- sock_do_ioctl `- br_ioctl_call |
| `- dev_ioctl `- br_ioctl_stub |
| |- rtnl_lock | |
| |- dev_ifsioc ' |
| ' |- dev = __dev_get_by_name(...) |
| |- netdev_hold(dev, ...) . |
| / |- rtnl_unlock ------. | |
| | |- br_ioctl_call `---> |- rtnl_lock |
| Race | | `- br_ioctl_stub |- br_del_bridge |
| Window | | | |- dev = __dev_get_by_name(...) |
| | | | May take long | `- br_dev_delete(dev, ...) |
| | | | under RTNL pressure | `- unregister_netdevice_queue(dev, ...) |
| | | | | `- rtnl_unlock |
| \ | |- rtnl_lock <-' `- netdev_run_todo |
| | |- ... `- netdev_run_todo |
| | `- rtnl_unlock |- __rtnl_unlock |
| | |- netdev_wait_allrefs_any |
| |- netdev_put(dev, ...) <----------------' |
| Wait refcnt decrement |
| and log splat below |
| |
| To avoid blocking SIOCBRDELBR unnecessarily, let's not call |
| dev_ioctl() for SIOCBRADDIF and SIOCBRDELIF. |
| |
| In the dev_ioctl() path, we do the following: |
| |
| 1. Copy struct ifreq by get_user_ifreq in sock_do_ioctl() |
| 2. Check CAP_NET_ADMIN in dev_ioctl() |
| 3. Call dev_load() in dev_ioctl() |
| 4. Fetch the master dev from ifr.ifr_name in dev_ifsioc() |
| |
| 3. can be done by request_module() in br_ioctl_call(), so we move |
| 1., 2., and 4. to br_ioctl_stub(). |
| |
| Note that 2. is also checked later in add_del_if(), but it's better |
| performed before RTNL. |
| |
| SIOCBRADDIF and SIOCBRDELIF have been processed in dev_ioctl() since |
| the pre-git era, and there seems to be no specific reason to process |
| them there. |
| |
| [0]: |
| unregister_netdevice: waiting for wpan3 to become free. Usage count = 2 |
| ref_tracker: wpan3@ffff8880662d8608 has 1/1 users at |
| __netdev_tracker_alloc include/linux/netdevice.h:4282 [inline] |
| netdev_hold include/linux/netdevice.h:4311 [inline] |
| dev_ifsioc+0xc6a/0x1160 net/core/dev_ioctl.c:624 |
| dev_ioctl+0x255/0x10c0 net/core/dev_ioctl.c:826 |
| sock_do_ioctl+0x1ca/0x260 net/socket.c:1213 |
| sock_ioctl+0x23a/0x6c0 net/socket.c:1318 |
| vfs_ioctl fs/ioctl.c:51 [inline] |
| __do_sys_ioctl fs/ioctl.c:906 [inline] |
| __se_sys_ioctl fs/ioctl.c:892 [inline] |
| __x64_sys_ioctl+0x1a4/0x210 fs/ioctl.c:892 |
| do_syscall_x64 arch/x86/entry/common.c:52 [inline] |
| do_syscall_64+0xcb/0x250 arch/x86/entry/common.c:83 |
| entry_SYSCALL_64_after_hwframe+0x77/0x7f |
| |
| The Linux kernel CVE team has assigned CVE-2025-22111 to this issue. |
| |
| |
| Affected and fixed versions |
| =========================== |
| |
| Issue introduced in 5.15 with commit 893b195875340cb44b54c9db99e708145f1210e8 and fixed in 6.14.2 with commit 00fe0ac64efd1f5373b3dd9f1f84b19235371e39 |
| Issue introduced in 5.15 with commit 893b195875340cb44b54c9db99e708145f1210e8 and fixed in 6.15 with commit ed3ba9b6e280e14cc3148c1b226ba453f02fa76c |
| |
| Please see https://www.kernel.org for a full list of currently supported |
| kernel versions by the kernel community. |
| |
| Unaffected versions might change over time as fixes are backported to |
| older supported kernel versions. The official CVE entry at |
| https://cve.org/CVERecord/?id=CVE-2025-22111 |
| will be updated if fixes are backported, please check that for the most |
| up to date information about this issue. |
| |
| |
| Affected files |
| ============== |
| |
| The file(s) affected by this issue are: |
| include/linux/if_bridge.h |
| net/bridge/br_ioctl.c |
| net/bridge/br_private.h |
| net/core/dev_ioctl.c |
| net/socket.c |
| |
| |
| Mitigation |
| ========== |
| |
| The Linux kernel CVE team recommends that you update to the latest |
| stable kernel version for this, and many other bugfixes. Individual |
| changes are never tested alone, but rather are part of a larger kernel |
| release. Cherry-picking individual commits is not recommended or |
| supported by the Linux kernel community at all. If however, updating to |
| the latest release is impossible, the individual changes to resolve this |
| issue can be found at these commits: |
| https://git.kernel.org/stable/c/00fe0ac64efd1f5373b3dd9f1f84b19235371e39 |
| https://git.kernel.org/stable/c/ed3ba9b6e280e14cc3148c1b226ba453f02fa76c |