|
|
4be359 |
From 951ae7dd395dd1407cfc6d7f2f59163850ec0362 Mon Sep 17 00:00:00 2001
|
|
|
4be359 |
From: Yannick Cote <ycote@redhat.com>
|
|
|
4be359 |
Date: Tue, 14 Mar 2023 21:40:48 -0400
|
|
|
4be359 |
Subject: [KPATCH CVE-2022-4744] kpatch fixes for CVE-2022-4744
|
|
|
4be359 |
|
|
|
4be359 |
Kernels:
|
|
|
4be359 |
5.14.0-162.6.1.el9_1
|
|
|
4be359 |
5.14.0-162.12.1.el9_1
|
|
|
4be359 |
5.14.0-162.18.1.el9_1
|
|
|
4be359 |
|
|
|
4be359 |
|
|
|
4be359 |
Kpatch-MR: https://gitlab.com/redhat/prdsc/rhel/src/kpatch/rhel-9/-/merge_requests/28
|
|
|
4be359 |
Approved-by: Joe Lawrence (@joe.lawrence)
|
|
|
4be359 |
Changes since last build:
|
|
|
4be359 |
[x86_64]:
|
|
|
4be359 |
control.o: changed function: snd_ctl_elem_read
|
|
|
4be359 |
control.o: changed function: snd_ctl_ioctl
|
|
|
4be359 |
dev.o: changed function: register_netdevice
|
|
|
4be359 |
tun.o: changed function: tun_free_netdev
|
|
|
4be359 |
tun.o: changed function: tun_set_iff.constprop.0
|
|
|
4be359 |
tun.o: new function: kpp_cve_2022_4744_tun_net_init
|
|
|
4be359 |
|
|
|
4be359 |
[ppc64le]:
|
|
|
4be359 |
dev.o: changed function: register_netdevice
|
|
|
4be359 |
tun.o: changed function: tun_free_netdev
|
|
|
4be359 |
tun.o: changed function: tun_set_iff.constprop.0
|
|
|
4be359 |
tun.o: new function: kpp_cve_2022_4744_tun_net_init
|
|
|
4be359 |
|
|
|
4be359 |
---------------------------
|
|
|
4be359 |
|
|
|
4be359 |
Modifications:
|
|
|
4be359 |
- add shadow variables for tun->ifr, tun->file, ndo_init
|
|
|
4be359 |
- call init from register_netdevice() when shadow variables are detected
|
|
|
4be359 |
- renamed new tun_net_init() -> kpp_cve_2022_4744_tun_net_init()
|
|
|
4be359 |
- code to allocate, maintain and remove shadow variables
|
|
|
4be359 |
|
|
|
4be359 |
commit 8ab79b18abf2f3a2cf33903794ff0de7cec105fc
|
|
|
4be359 |
Author: Jon Maloy <jmaloy@redhat.com>
|
|
|
4be359 |
Date: Wed Mar 8 11:35:45 2023 -0500
|
|
|
4be359 |
|
|
|
4be359 |
tun: avoid double free in tun_free_netdev
|
|
|
4be359 |
|
|
|
4be359 |
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2156372
|
|
|
4be359 |
Upstream: Merged
|
|
|
4be359 |
CVE: CVE-2022-4744
|
|
|
4be359 |
|
|
|
4be359 |
commit 158b515f703e75e7d68289bf4d98c664e1d632df
|
|
|
4be359 |
Author: George Kennedy <george.kennedy@oracle.com>
|
|
|
4be359 |
Date: Thu Dec 16 13:25:32 2021 -0500
|
|
|
4be359 |
|
|
|
4be359 |
tun: avoid double free in tun_free_netdev
|
|
|
4be359 |
|
|
|
4be359 |
Avoid double free in tun_free_netdev() by moving the
|
|
|
4be359 |
dev->tstats and tun->security allocs to a new ndo_init routine
|
|
|
4be359 |
(tun_net_init()) that will be called by register_netdevice().
|
|
|
4be359 |
ndo_init is paired with the desctructor (tun_free_netdev()),
|
|
|
4be359 |
so if there's an error in register_netdevice() the destructor
|
|
|
4be359 |
will handle the frees.
|
|
|
4be359 |
|
|
|
4be359 |
BUG: KASAN: double-free or invalid-free in selinux_tun_dev_free_security+0x1a/0x20 security/selinux/hooks.c:5605
|
|
|
4be359 |
|
|
|
4be359 |
CPU: 0 PID: 25750 Comm: syz-executor416 Not tainted 5.16.0-rc2-syzk #1
|
|
|
4be359 |
Hardware name: Red Hat KVM, BIOS
|
|
|
4be359 |
Call Trace:
|
|
|
4be359 |
<TASK>
|
|
|
4be359 |
__dump_stack lib/dump_stack.c:88 [inline]
|
|
|
4be359 |
dump_stack_lvl+0x89/0xb5 lib/dump_stack.c:106
|
|
|
4be359 |
print_address_description.constprop.9+0x28/0x160 mm/kasan/report.c:247
|
|
|
4be359 |
kasan_report_invalid_free+0x55/0x80 mm/kasan/report.c:372
|
|
|
4be359 |
____kasan_slab_free mm/kasan/common.c:346 [inline]
|
|
|
4be359 |
__kasan_slab_free+0x107/0x120 mm/kasan/common.c:374
|
|
|
4be359 |
kasan_slab_free include/linux/kasan.h:235 [inline]
|
|
|
4be359 |
slab_free_hook mm/slub.c:1723 [inline]
|
|
|
4be359 |
slab_free_freelist_hook mm/slub.c:1749 [inline]
|
|
|
4be359 |
slab_free mm/slub.c:3513 [inline]
|
|
|
4be359 |
kfree+0xac/0x2d0 mm/slub.c:4561
|
|
|
4be359 |
selinux_tun_dev_free_security+0x1a/0x20 security/selinux/hooks.c:5605
|
|
|
4be359 |
security_tun_dev_free_security+0x4f/0x90 security/security.c:2342
|
|
|
4be359 |
tun_free_netdev+0xe6/0x150 drivers/net/tun.c:2215
|
|
|
4be359 |
netdev_run_todo+0x4df/0x840 net/core/dev.c:10627
|
|
|
4be359 |
rtnl_unlock+0x13/0x20 net/core/rtnetlink.c:112
|
|
|
4be359 |
__tun_chr_ioctl+0x80c/0x2870 drivers/net/tun.c:3302
|
|
|
4be359 |
tun_chr_ioctl+0x2f/0x40 drivers/net/tun.c:3311
|
|
|
4be359 |
vfs_ioctl fs/ioctl.c:51 [inline]
|
|
|
4be359 |
__do_sys_ioctl fs/ioctl.c:874 [inline]
|
|
|
4be359 |
__se_sys_ioctl fs/ioctl.c:860 [inline]
|
|
|
4be359 |
__x64_sys_ioctl+0x19d/0x220 fs/ioctl.c:860
|
|
|
4be359 |
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
|
|
|
4be359 |
do_syscall_64+0x3a/0x80 arch/x86/entry/common.c:80
|
|
|
4be359 |
entry_SYSCALL_64_after_hwframe+0x44/0xae
|
|
|
4be359 |
|
|
|
4be359 |
Reported-by: syzkaller <syzkaller@googlegroups.com>
|
|
|
4be359 |
Signed-off-by: George Kennedy <george.kennedy@oracle.com>
|
|
|
4be359 |
Suggested-by: Jakub Kicinski <kuba@kernel.org>
|
|
|
4be359 |
Link: https://lore.kernel.org/r/1639679132-19884-1-git-send-email-george.kennedy@oracle.com
|
|
|
4be359 |
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
|
|
4be359 |
|
|
|
4be359 |
Signed-off-by: Jon Maloy <jmaloy@redhat.com>
|
|
|
4be359 |
|
|
|
4be359 |
Signed-off-by: Yannick Cote <ycote@redhat.com>
|
|
|
4be359 |
---
|
|
|
4be359 |
drivers/net/tun.c | 135 ++++++++++++++++++++++++++++------------------
|
|
|
4be359 |
net/core/dev.c | 31 ++++++++++-
|
|
|
4be359 |
2 files changed, 112 insertions(+), 54 deletions(-)
|
|
|
4be359 |
|
|
|
4be359 |
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
|
|
|
4be359 |
index a3aec566fb4b..2a2fee5e3c10 100644
|
|
|
4be359 |
--- a/drivers/net/tun.c
|
|
|
4be359 |
+++ b/drivers/net/tun.c
|
|
|
4be359 |
@@ -216,6 +216,9 @@ struct veth {
|
|
|
4be359 |
__be16 h_vlan_TCI;
|
|
|
4be359 |
};
|
|
|
4be359 |
|
|
|
4be359 |
+static void tun_flow_init(struct tun_struct *tun);
|
|
|
4be359 |
+static void tun_flow_uninit(struct tun_struct *tun);
|
|
|
4be359 |
+
|
|
|
4be359 |
static int tun_napi_receive(struct napi_struct *napi, int budget)
|
|
|
4be359 |
{
|
|
|
4be359 |
struct tun_file *tfile = container_of(napi, struct tun_file, napi);
|
|
|
4be359 |
@@ -953,6 +956,67 @@ static int check_filter(struct tap_filter *filter, const struct sk_buff *skb)
|
|
|
4be359 |
|
|
|
4be359 |
static const struct ethtool_ops tun_ethtool_ops;
|
|
|
4be359 |
|
|
|
4be359 |
+/* CVE-2022-4744 - kpatch gathered definitions */
|
|
|
4be359 |
+#ifndef __GENKSYMS__
|
|
|
4be359 |
+/* Note: avoid symvers churn for tun_get_tx_ring and tun_get_socket */
|
|
|
4be359 |
+# include <linux/livepatch.h>
|
|
|
4be359 |
+# define KLP_CVE_2022_4744 0x2022474400000001
|
|
|
4be359 |
+struct klp_cve_2022_4774_t {
|
|
|
4be359 |
+ struct ifreq tun_ifr;
|
|
|
4be359 |
+ struct file tun_file;
|
|
|
4be359 |
+ int (*ndo_init)(struct net_device *netdev);
|
|
|
4be359 |
+};
|
|
|
4be359 |
+#endif
|
|
|
4be359 |
+int kpp_cve_2022_4744_tun_net_init(struct net_device *dev)
|
|
|
4be359 |
+{
|
|
|
4be359 |
+ struct tun_struct *tun = netdev_priv(dev);
|
|
|
4be359 |
+ int err;
|
|
|
4be359 |
+ struct klp_cve_2022_4774_t *klp_sv;
|
|
|
4be359 |
+
|
|
|
4be359 |
+ klp_sv = klp_shadow_get(tun, KLP_CVE_2022_4744);
|
|
|
4be359 |
+ if (!klp_sv)
|
|
|
4be359 |
+ return -EINVAL;
|
|
|
4be359 |
+
|
|
|
4be359 |
+ dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
|
|
|
4be359 |
+ if (!dev->tstats)
|
|
|
4be359 |
+ return -ENOMEM;
|
|
|
4be359 |
+
|
|
|
4be359 |
+ spin_lock_init(&tun->lock);
|
|
|
4be359 |
+
|
|
|
4be359 |
+ err = security_tun_dev_alloc_security(&tun->security);
|
|
|
4be359 |
+ if (err < 0) {
|
|
|
4be359 |
+ free_percpu(dev->tstats);
|
|
|
4be359 |
+ return err;
|
|
|
4be359 |
+ }
|
|
|
4be359 |
+
|
|
|
4be359 |
+ tun_flow_init(tun);
|
|
|
4be359 |
+
|
|
|
4be359 |
+ dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
|
|
|
4be359 |
+ TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
|
|
|
4be359 |
+ NETIF_F_HW_VLAN_STAG_TX;
|
|
|
4be359 |
+ dev->features = dev->hw_features | NETIF_F_LLTX;
|
|
|
4be359 |
+ dev->vlan_features = dev->features &
|
|
|
4be359 |
+ ~(NETIF_F_HW_VLAN_CTAG_TX |
|
|
|
4be359 |
+ NETIF_F_HW_VLAN_STAG_TX);
|
|
|
4be359 |
+ klp_sv = klp_shadow_get(tun, KLP_CVE_2022_4744);
|
|
|
4be359 |
+ if (klp_sv) {
|
|
|
4be359 |
+ tun->flags = (tun->flags & ~TUN_FEATURES) |
|
|
|
4be359 |
+ (klp_sv->tun_ifr.ifr_flags & TUN_FEATURES);
|
|
|
4be359 |
+
|
|
|
4be359 |
+ INIT_LIST_HEAD(&tun->disabled);
|
|
|
4be359 |
+ err = tun_attach(tun, &klp_sv->tun_file, false,
|
|
|
4be359 |
+ klp_sv->tun_ifr.ifr_flags & IFF_NAPI,
|
|
|
4be359 |
+ klp_sv->tun_ifr.ifr_flags & IFF_NAPI_FRAGS, false);
|
|
|
4be359 |
+ }
|
|
|
4be359 |
+ if (err < 0) {
|
|
|
4be359 |
+ tun_flow_uninit(tun);
|
|
|
4be359 |
+ security_tun_dev_free_security(tun->security);
|
|
|
4be359 |
+ free_percpu(dev->tstats);
|
|
|
4be359 |
+ return err;
|
|
|
4be359 |
+ }
|
|
|
4be359 |
+ return 0;
|
|
|
4be359 |
+}
|
|
|
4be359 |
+
|
|
|
4be359 |
/* Net device detach from fd. */
|
|
|
4be359 |
static void tun_net_uninit(struct net_device *dev)
|
|
|
4be359 |
{
|
|
|
4be359 |
@@ -2206,15 +2270,11 @@ static void tun_free_netdev(struct net_device *dev)
|
|
|
4be359 |
BUG_ON(!(list_empty(&tun->disabled)));
|
|
|
4be359 |
|
|
|
4be359 |
free_percpu(dev->tstats);
|
|
|
4be359 |
- /* We clear tstats so that tun_set_iff() can tell if
|
|
|
4be359 |
- * tun_free_netdev() has been called from register_netdevice().
|
|
|
4be359 |
- */
|
|
|
4be359 |
- dev->tstats = NULL;
|
|
|
4be359 |
-
|
|
|
4be359 |
tun_flow_uninit(tun);
|
|
|
4be359 |
security_tun_dev_free_security(tun->security);
|
|
|
4be359 |
__tun_set_ebpf(tun, &tun->steering_prog, NULL);
|
|
|
4be359 |
__tun_set_ebpf(tun, &tun->filter_prog, NULL);
|
|
|
4be359 |
+ klp_shadow_free(tun, KLP_CVE_2022_4744, NULL);
|
|
|
4be359 |
}
|
|
|
4be359 |
|
|
|
4be359 |
static void tun_setup(struct net_device *dev)
|
|
|
4be359 |
@@ -2716,41 +2776,30 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
|
|
|
4be359 |
tun->rx_batched = 0;
|
|
|
4be359 |
RCU_INIT_POINTER(tun->steering_prog, NULL);
|
|
|
4be359 |
|
|
|
4be359 |
- dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
|
|
|
4be359 |
- if (!dev->tstats) {
|
|
|
4be359 |
- err = -ENOMEM;
|
|
|
4be359 |
- goto err_free_dev;
|
|
|
4be359 |
- }
|
|
|
4be359 |
+/* kpatch */
|
|
|
4be359 |
+{
|
|
|
4be359 |
+ struct klp_cve_2022_4774_t *klp_sv;
|
|
|
4be359 |
|
|
|
4be359 |
- spin_lock_init(&tun->lock);
|
|
|
4be359 |
+ klp_sv = klp_shadow_alloc(tun, KLP_CVE_2022_4744,
|
|
|
4be359 |
+ sizeof(*klp_sv), GFP_KERNEL, NULL, NULL);
|
|
|
4be359 |
+ if (!klp_sv) {
|
|
|
4be359 |
+ free_netdev(dev);
|
|
|
4be359 |
+ return -ENOMEM;
|
|
|
4be359 |
+ }
|
|
|
4be359 |
|
|
|
4be359 |
- err = security_tun_dev_alloc_security(&tun->security);
|
|
|
4be359 |
- if (err < 0)
|
|
|
4be359 |
- goto err_free_stat;
|
|
|
4be359 |
+ memcpy(&klp_sv->tun_ifr, ifr, sizeof(*ifr));
|
|
|
4be359 |
+ memcpy(&klp_sv->tun_file, file, sizeof(*file));
|
|
|
4be359 |
+ klp_sv->ndo_init = kpp_cve_2022_4744_tun_net_init;
|
|
|
4be359 |
+}
|
|
|
4be359 |
|
|
|
4be359 |
tun_net_init(dev);
|
|
|
4be359 |
- tun_flow_init(tun);
|
|
|
4be359 |
-
|
|
|
4be359 |
- dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
|
|
|
4be359 |
- TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
|
|
|
4be359 |
- NETIF_F_HW_VLAN_STAG_TX;
|
|
|
4be359 |
- dev->features = dev->hw_features | NETIF_F_LLTX;
|
|
|
4be359 |
- dev->vlan_features = dev->features &
|
|
|
4be359 |
- ~(NETIF_F_HW_VLAN_CTAG_TX |
|
|
|
4be359 |
- NETIF_F_HW_VLAN_STAG_TX);
|
|
|
4be359 |
-
|
|
|
4be359 |
- tun->flags = (tun->flags & ~TUN_FEATURES) |
|
|
|
4be359 |
- (ifr->ifr_flags & TUN_FEATURES);
|
|
|
4be359 |
-
|
|
|
4be359 |
- INIT_LIST_HEAD(&tun->disabled);
|
|
|
4be359 |
- err = tun_attach(tun, file, false, ifr->ifr_flags & IFF_NAPI,
|
|
|
4be359 |
- ifr->ifr_flags & IFF_NAPI_FRAGS, false);
|
|
|
4be359 |
- if (err < 0)
|
|
|
4be359 |
- goto err_free_flow;
|
|
|
4be359 |
|
|
|
4be359 |
err = register_netdevice(tun->dev);
|
|
|
4be359 |
- if (err < 0)
|
|
|
4be359 |
- goto err_detach;
|
|
|
4be359 |
+ if (err < 0) {
|
|
|
4be359 |
+ klp_shadow_free(tun, KLP_CVE_2022_4744, NULL);
|
|
|
4be359 |
+ free_netdev(dev);
|
|
|
4be359 |
+ return err;
|
|
|
4be359 |
+ }
|
|
|
4be359 |
/* free_netdev() won't check refcnt, to avoid race
|
|
|
4be359 |
* with dev_put() we need publish tun after registration.
|
|
|
4be359 |
*/
|
|
|
4be359 |
@@ -2767,24 +2816,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
|
|
|
4be359 |
|
|
|
4be359 |
strcpy(ifr->ifr_name, tun->dev->name);
|
|
|
4be359 |
return 0;
|
|
|
4be359 |
-
|
|
|
4be359 |
-err_detach:
|
|
|
4be359 |
- tun_detach_all(dev);
|
|
|
4be359 |
- /* We are here because register_netdevice() has failed.
|
|
|
4be359 |
- * If register_netdevice() already called tun_free_netdev()
|
|
|
4be359 |
- * while dealing with the error, dev->stats has been cleared.
|
|
|
4be359 |
- */
|
|
|
4be359 |
- if (!dev->tstats)
|
|
|
4be359 |
- goto err_free_dev;
|
|
|
4be359 |
-
|
|
|
4be359 |
-err_free_flow:
|
|
|
4be359 |
- tun_flow_uninit(tun);
|
|
|
4be359 |
- security_tun_dev_free_security(tun->security);
|
|
|
4be359 |
-err_free_stat:
|
|
|
4be359 |
- free_percpu(dev->tstats);
|
|
|
4be359 |
-err_free_dev:
|
|
|
4be359 |
- free_netdev(dev);
|
|
|
4be359 |
- return err;
|
|
|
4be359 |
}
|
|
|
4be359 |
|
|
|
4be359 |
static void tun_get_iff(struct tun_struct *tun, struct ifreq *ifr)
|
|
|
4be359 |
diff --git a/net/core/dev.c b/net/core/dev.c
|
|
|
4be359 |
index 89ff6b1e7735..d5f07da178dc 100644
|
|
|
4be359 |
--- a/net/core/dev.c
|
|
|
4be359 |
+++ b/net/core/dev.c
|
|
|
4be359 |
@@ -9544,6 +9544,15 @@ EXPORT_SYMBOL(netif_tx_stop_all_queues);
|
|
|
4be359 |
* will not get the same name.
|
|
|
4be359 |
*/
|
|
|
4be359 |
|
|
|
4be359 |
+/* CVE-2022-4744 - kpatch gathered definitions */
|
|
|
4be359 |
+#include <linux/livepatch.h>
|
|
|
4be359 |
+#define KLP_CVE_2022_4744 0x2022474400000001
|
|
|
4be359 |
+struct klp_cve_2022_4774_t {
|
|
|
4be359 |
+ struct ifreq tun_ifr;
|
|
|
4be359 |
+ struct file tun_file;
|
|
|
4be359 |
+ int (*ndo_init)(struct net_device *netdev);
|
|
|
4be359 |
+};
|
|
|
4be359 |
+
|
|
|
4be359 |
int register_netdevice(struct net_device *dev)
|
|
|
4be359 |
{
|
|
|
4be359 |
int ret;
|
|
|
4be359 |
@@ -9576,15 +9585,33 @@ int register_netdevice(struct net_device *dev)
|
|
|
4be359 |
if (!dev->name_node)
|
|
|
4be359 |
goto out;
|
|
|
4be359 |
|
|
|
4be359 |
+/* kpatch */
|
|
|
4be359 |
+{
|
|
|
4be359 |
/* Init, if this function is available */
|
|
|
4be359 |
- if (dev->netdev_ops->ndo_init) {
|
|
|
4be359 |
- ret = dev->netdev_ops->ndo_init(dev);
|
|
|
4be359 |
+ struct klp_cve_2022_4774_t *klp_sv;
|
|
|
4be359 |
+ int (*ndo_init)(struct net_device *netdev) = NULL;
|
|
|
4be359 |
+
|
|
|
4be359 |
+ /* Does device has shadow variable ndo_init? */
|
|
|
4be359 |
+ if (netdev_priv(dev)) {
|
|
|
4be359 |
+ klp_sv = klp_shadow_get(netdev_priv(dev), KLP_CVE_2022_4744);
|
|
|
4be359 |
+ if (klp_sv && klp_sv->ndo_init)
|
|
|
4be359 |
+ ndo_init = klp_sv->ndo_init;
|
|
|
4be359 |
+ }
|
|
|
4be359 |
+
|
|
|
4be359 |
+ /* How about typical netdev_ops->ndo_init */
|
|
|
4be359 |
+ if (!ndo_init && dev->netdev_ops->ndo_init)
|
|
|
4be359 |
+ ndo_init = dev->netdev_ops->ndo_init;
|
|
|
4be359 |
+
|
|
|
4be359 |
+ /* Run ndo_init callback if found */
|
|
|
4be359 |
+ if (ndo_init) {
|
|
|
4be359 |
+ ret = ndo_init(dev);
|
|
|
4be359 |
if (ret) {
|
|
|
4be359 |
if (ret > 0)
|
|
|
4be359 |
ret = -EIO;
|
|
|
4be359 |
goto err_free_name;
|
|
|
4be359 |
}
|
|
|
4be359 |
}
|
|
|
4be359 |
+}
|
|
|
4be359 |
|
|
|
4be359 |
if (((dev->hw_features | dev->features) &
|
|
|
4be359 |
NETIF_F_HW_VLAN_CTAG_FILTER) &&
|
|
|
4be359 |
--
|
|
|
4be359 |
2.39.2
|
|
|
4be359 |
|
|
|
4be359 |
|