diff --git a/.gitignore b/.gitignore index e69de29..16433d5 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,2 @@ +SOURCES/kernel-5.14.0-162.18.1.el9_1.src.rpm +SOURCES/v0.9.7.tar.gz diff --git a/.kpatch-patch-5_14_0-162_18_1.metadata b/.kpatch-patch-5_14_0-162_18_1.metadata index e69de29..03a123b 100644 --- a/.kpatch-patch-5_14_0-162_18_1.metadata +++ b/.kpatch-patch-5_14_0-162_18_1.metadata @@ -0,0 +1,2 @@ +2ecdc516aa3b43bf05bbea011a78cf08d5b25080 SOURCES/kernel-5.14.0-162.18.1.el9_1.src.rpm +da88fa82b005bbafc1719c59bd00847ce2a22a60 SOURCES/v0.9.7.tar.gz diff --git a/SOURCES/CVE-2022-4744.patch b/SOURCES/CVE-2022-4744.patch new file mode 100644 index 0000000..13bee3a --- /dev/null +++ b/SOURCES/CVE-2022-4744.patch @@ -0,0 +1,349 @@ +From 951ae7dd395dd1407cfc6d7f2f59163850ec0362 Mon Sep 17 00:00:00 2001 +From: Yannick Cote +Date: Tue, 14 Mar 2023 21:40:48 -0400 +Subject: [KPATCH CVE-2022-4744] kpatch fixes for CVE-2022-4744 + +Kernels: +5.14.0-162.6.1.el9_1 +5.14.0-162.12.1.el9_1 +5.14.0-162.18.1.el9_1 + + +Kpatch-MR: https://gitlab.com/redhat/prdsc/rhel/src/kpatch/rhel-9/-/merge_requests/28 +Approved-by: Joe Lawrence (@joe.lawrence) +Changes since last build: +[x86_64]: +control.o: changed function: snd_ctl_elem_read +control.o: changed function: snd_ctl_ioctl +dev.o: changed function: register_netdevice +tun.o: changed function: tun_free_netdev +tun.o: changed function: tun_set_iff.constprop.0 +tun.o: new function: kpp_cve_2022_4744_tun_net_init + +[ppc64le]: +dev.o: changed function: register_netdevice +tun.o: changed function: tun_free_netdev +tun.o: changed function: tun_set_iff.constprop.0 +tun.o: new function: kpp_cve_2022_4744_tun_net_init + +--------------------------- + +Modifications: +- add shadow variables for tun->ifr, tun->file, ndo_init +- call init from register_netdevice() when shadow variables are detected +- renamed new tun_net_init() -> kpp_cve_2022_4744_tun_net_init() +- code to allocate, maintain and remove shadow variables + +commit 8ab79b18abf2f3a2cf33903794ff0de7cec105fc +Author: Jon Maloy +Date: Wed Mar 8 11:35:45 2023 -0500 + + tun: avoid double free in tun_free_netdev + + Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2156372 + Upstream: Merged + CVE: CVE-2022-4744 + + commit 158b515f703e75e7d68289bf4d98c664e1d632df + Author: George Kennedy + Date: Thu Dec 16 13:25:32 2021 -0500 + + tun: avoid double free in tun_free_netdev + + Avoid double free in tun_free_netdev() by moving the + dev->tstats and tun->security allocs to a new ndo_init routine + (tun_net_init()) that will be called by register_netdevice(). + ndo_init is paired with the desctructor (tun_free_netdev()), + so if there's an error in register_netdevice() the destructor + will handle the frees. + + BUG: KASAN: double-free or invalid-free in selinux_tun_dev_free_security+0x1a/0x20 security/selinux/hooks.c:5605 + + CPU: 0 PID: 25750 Comm: syz-executor416 Not tainted 5.16.0-rc2-syzk #1 + Hardware name: Red Hat KVM, BIOS + Call Trace: + + __dump_stack lib/dump_stack.c:88 [inline] + dump_stack_lvl+0x89/0xb5 lib/dump_stack.c:106 + print_address_description.constprop.9+0x28/0x160 mm/kasan/report.c:247 + kasan_report_invalid_free+0x55/0x80 mm/kasan/report.c:372 + ____kasan_slab_free mm/kasan/common.c:346 [inline] + __kasan_slab_free+0x107/0x120 mm/kasan/common.c:374 + kasan_slab_free include/linux/kasan.h:235 [inline] + slab_free_hook mm/slub.c:1723 [inline] + slab_free_freelist_hook mm/slub.c:1749 [inline] + slab_free mm/slub.c:3513 [inline] + kfree+0xac/0x2d0 mm/slub.c:4561 + selinux_tun_dev_free_security+0x1a/0x20 security/selinux/hooks.c:5605 + security_tun_dev_free_security+0x4f/0x90 security/security.c:2342 + tun_free_netdev+0xe6/0x150 drivers/net/tun.c:2215 + netdev_run_todo+0x4df/0x840 net/core/dev.c:10627 + rtnl_unlock+0x13/0x20 net/core/rtnetlink.c:112 + __tun_chr_ioctl+0x80c/0x2870 drivers/net/tun.c:3302 + tun_chr_ioctl+0x2f/0x40 drivers/net/tun.c:3311 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:874 [inline] + __se_sys_ioctl fs/ioctl.c:860 [inline] + __x64_sys_ioctl+0x19d/0x220 fs/ioctl.c:860 + do_syscall_x64 arch/x86/entry/common.c:50 [inline] + do_syscall_64+0x3a/0x80 arch/x86/entry/common.c:80 + entry_SYSCALL_64_after_hwframe+0x44/0xae + + Reported-by: syzkaller + Signed-off-by: George Kennedy + Suggested-by: Jakub Kicinski + Link: https://lore.kernel.org/r/1639679132-19884-1-git-send-email-george.kennedy@oracle.com + Signed-off-by: Jakub Kicinski + + Signed-off-by: Jon Maloy + +Signed-off-by: Yannick Cote +--- + drivers/net/tun.c | 135 ++++++++++++++++++++++++++++------------------ + net/core/dev.c | 31 ++++++++++- + 2 files changed, 112 insertions(+), 54 deletions(-) + +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index a3aec566fb4b..2a2fee5e3c10 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -216,6 +216,9 @@ struct veth { + __be16 h_vlan_TCI; + }; + ++static void tun_flow_init(struct tun_struct *tun); ++static void tun_flow_uninit(struct tun_struct *tun); ++ + static int tun_napi_receive(struct napi_struct *napi, int budget) + { + struct tun_file *tfile = container_of(napi, struct tun_file, napi); +@@ -953,6 +956,67 @@ static int check_filter(struct tap_filter *filter, const struct sk_buff *skb) + + static const struct ethtool_ops tun_ethtool_ops; + ++/* CVE-2022-4744 - kpatch gathered definitions */ ++#ifndef __GENKSYMS__ ++/* Note: avoid symvers churn for tun_get_tx_ring and tun_get_socket */ ++# include ++# define KLP_CVE_2022_4744 0x2022474400000001 ++struct klp_cve_2022_4774_t { ++ struct ifreq tun_ifr; ++ struct file tun_file; ++ int (*ndo_init)(struct net_device *netdev); ++}; ++#endif ++int kpp_cve_2022_4744_tun_net_init(struct net_device *dev) ++{ ++ struct tun_struct *tun = netdev_priv(dev); ++ int err; ++ struct klp_cve_2022_4774_t *klp_sv; ++ ++ klp_sv = klp_shadow_get(tun, KLP_CVE_2022_4744); ++ if (!klp_sv) ++ return -EINVAL; ++ ++ dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); ++ if (!dev->tstats) ++ return -ENOMEM; ++ ++ spin_lock_init(&tun->lock); ++ ++ err = security_tun_dev_alloc_security(&tun->security); ++ if (err < 0) { ++ free_percpu(dev->tstats); ++ return err; ++ } ++ ++ tun_flow_init(tun); ++ ++ dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | ++ TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX | ++ NETIF_F_HW_VLAN_STAG_TX; ++ dev->features = dev->hw_features | NETIF_F_LLTX; ++ dev->vlan_features = dev->features & ++ ~(NETIF_F_HW_VLAN_CTAG_TX | ++ NETIF_F_HW_VLAN_STAG_TX); ++ klp_sv = klp_shadow_get(tun, KLP_CVE_2022_4744); ++ if (klp_sv) { ++ tun->flags = (tun->flags & ~TUN_FEATURES) | ++ (klp_sv->tun_ifr.ifr_flags & TUN_FEATURES); ++ ++ INIT_LIST_HEAD(&tun->disabled); ++ err = tun_attach(tun, &klp_sv->tun_file, false, ++ klp_sv->tun_ifr.ifr_flags & IFF_NAPI, ++ klp_sv->tun_ifr.ifr_flags & IFF_NAPI_FRAGS, false); ++ } ++ if (err < 0) { ++ tun_flow_uninit(tun); ++ security_tun_dev_free_security(tun->security); ++ free_percpu(dev->tstats); ++ return err; ++ } ++ return 0; ++} ++ + /* Net device detach from fd. */ + static void tun_net_uninit(struct net_device *dev) + { +@@ -2206,15 +2270,11 @@ static void tun_free_netdev(struct net_device *dev) + BUG_ON(!(list_empty(&tun->disabled))); + + free_percpu(dev->tstats); +- /* We clear tstats so that tun_set_iff() can tell if +- * tun_free_netdev() has been called from register_netdevice(). +- */ +- dev->tstats = NULL; +- + tun_flow_uninit(tun); + security_tun_dev_free_security(tun->security); + __tun_set_ebpf(tun, &tun->steering_prog, NULL); + __tun_set_ebpf(tun, &tun->filter_prog, NULL); ++ klp_shadow_free(tun, KLP_CVE_2022_4744, NULL); + } + + static void tun_setup(struct net_device *dev) +@@ -2716,41 +2776,30 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) + tun->rx_batched = 0; + RCU_INIT_POINTER(tun->steering_prog, NULL); + +- dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); +- if (!dev->tstats) { +- err = -ENOMEM; +- goto err_free_dev; +- } ++/* kpatch */ ++{ ++ struct klp_cve_2022_4774_t *klp_sv; + +- spin_lock_init(&tun->lock); ++ klp_sv = klp_shadow_alloc(tun, KLP_CVE_2022_4744, ++ sizeof(*klp_sv), GFP_KERNEL, NULL, NULL); ++ if (!klp_sv) { ++ free_netdev(dev); ++ return -ENOMEM; ++ } + +- err = security_tun_dev_alloc_security(&tun->security); +- if (err < 0) +- goto err_free_stat; ++ memcpy(&klp_sv->tun_ifr, ifr, sizeof(*ifr)); ++ memcpy(&klp_sv->tun_file, file, sizeof(*file)); ++ klp_sv->ndo_init = kpp_cve_2022_4744_tun_net_init; ++} + + tun_net_init(dev); +- tun_flow_init(tun); +- +- dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | +- TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX | +- NETIF_F_HW_VLAN_STAG_TX; +- dev->features = dev->hw_features | NETIF_F_LLTX; +- dev->vlan_features = dev->features & +- ~(NETIF_F_HW_VLAN_CTAG_TX | +- NETIF_F_HW_VLAN_STAG_TX); +- +- tun->flags = (tun->flags & ~TUN_FEATURES) | +- (ifr->ifr_flags & TUN_FEATURES); +- +- INIT_LIST_HEAD(&tun->disabled); +- err = tun_attach(tun, file, false, ifr->ifr_flags & IFF_NAPI, +- ifr->ifr_flags & IFF_NAPI_FRAGS, false); +- if (err < 0) +- goto err_free_flow; + + err = register_netdevice(tun->dev); +- if (err < 0) +- goto err_detach; ++ if (err < 0) { ++ klp_shadow_free(tun, KLP_CVE_2022_4744, NULL); ++ free_netdev(dev); ++ return err; ++ } + /* free_netdev() won't check refcnt, to avoid race + * with dev_put() we need publish tun after registration. + */ +@@ -2767,24 +2816,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) + + strcpy(ifr->ifr_name, tun->dev->name); + return 0; +- +-err_detach: +- tun_detach_all(dev); +- /* We are here because register_netdevice() has failed. +- * If register_netdevice() already called tun_free_netdev() +- * while dealing with the error, dev->stats has been cleared. +- */ +- if (!dev->tstats) +- goto err_free_dev; +- +-err_free_flow: +- tun_flow_uninit(tun); +- security_tun_dev_free_security(tun->security); +-err_free_stat: +- free_percpu(dev->tstats); +-err_free_dev: +- free_netdev(dev); +- return err; + } + + static void tun_get_iff(struct tun_struct *tun, struct ifreq *ifr) +diff --git a/net/core/dev.c b/net/core/dev.c +index 89ff6b1e7735..d5f07da178dc 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -9544,6 +9544,15 @@ EXPORT_SYMBOL(netif_tx_stop_all_queues); + * will not get the same name. + */ + ++/* CVE-2022-4744 - kpatch gathered definitions */ ++#include ++#define KLP_CVE_2022_4744 0x2022474400000001 ++struct klp_cve_2022_4774_t { ++ struct ifreq tun_ifr; ++ struct file tun_file; ++ int (*ndo_init)(struct net_device *netdev); ++}; ++ + int register_netdevice(struct net_device *dev) + { + int ret; +@@ -9576,15 +9585,33 @@ int register_netdevice(struct net_device *dev) + if (!dev->name_node) + goto out; + ++/* kpatch */ ++{ + /* Init, if this function is available */ +- if (dev->netdev_ops->ndo_init) { +- ret = dev->netdev_ops->ndo_init(dev); ++ struct klp_cve_2022_4774_t *klp_sv; ++ int (*ndo_init)(struct net_device *netdev) = NULL; ++ ++ /* Does device has shadow variable ndo_init? */ ++ if (netdev_priv(dev)) { ++ klp_sv = klp_shadow_get(netdev_priv(dev), KLP_CVE_2022_4744); ++ if (klp_sv && klp_sv->ndo_init) ++ ndo_init = klp_sv->ndo_init; ++ } ++ ++ /* How about typical netdev_ops->ndo_init */ ++ if (!ndo_init && dev->netdev_ops->ndo_init) ++ ndo_init = dev->netdev_ops->ndo_init; ++ ++ /* Run ndo_init callback if found */ ++ if (ndo_init) { ++ ret = ndo_init(dev); + if (ret) { + if (ret > 0) + ret = -EIO; + goto err_free_name; + } + } ++} + + if (((dev->hw_features | dev->features) & + NETIF_F_HW_VLAN_CTAG_FILTER) && +-- +2.39.2 + + diff --git a/SOURCES/CVE-2023-0266.patch b/SOURCES/CVE-2023-0266.patch new file mode 100644 index 0000000..3d6a0de --- /dev/null +++ b/SOURCES/CVE-2023-0266.patch @@ -0,0 +1,152 @@ +From 120548cde1d7642ff79d71827993e32babfb4e2f Mon Sep 17 00:00:00 2001 +From: Ryan Sullivan +Date: Fri, 17 Feb 2023 12:26:57 -0500 +Subject: [KPATCH CVE-2023-0266] kpatch fixes for CVE-2023-0266 + +Kernels: +5.14.0-162.6.1.el9_1 +5.14.0-162.12.1.el9_1 + + +Kpatch-MR: https://gitlab.com/redhat/prdsc/rhel/src/kpatch/rhel-9/-/merge_requests/24 +Approved-by: Yannick Cote (@ycote1) +Approved-by: Joe Lawrence (@joe.lawrence) +Changes since last build: +[x86_64]: +control.o: changed function: snd_ctl_elem_read +control.o: changed function: snd_ctl_ioctl +dev.o: changed function: register_netdevice +tun.o: changed function: tun_free_netdev +tun.o: changed function: tun_set_iff.constprop.0 +tun.o: new function: kpp_cve_2022_4744_tun_net_init + +[ppc64le]: +dev.o: changed function: register_netdevice +tun.o: changed function: tun_free_netdev +tun.o: changed function: tun_set_iff.constprop.0 +tun.o: new function: kpp_cve_2022_4744_tun_net_init + +--------------------------- + +Modifications: none + +commit c0295d3bd6b49f47e30822a9de9c042020092424 +Author: Jaroslav Kysela +Date: Tue Jan 31 17:13:11 2023 +0100 + + ALSA: pcm: Move rwsem lock inside snd_ctl_elem_read to prevent UAF + + Takes rwsem lock inside snd_ctl_elem_read instead of snd_ctl_elem_read_user + like it was done for write in commit 1fa4445f9adf1 ("ALSA: control - introduce + snd_ctl_notify_one() helper"). Doing this way we are also fixing the following + locking issue happening in the compat path which can be easily triggered and + turned into an use-after-free. + + 64-bits: + snd_ctl_ioctl + snd_ctl_elem_read_user + [takes controls_rwsem] + snd_ctl_elem_read [lock properly held, all good] + [drops controls_rwsem] + + 32-bits: + snd_ctl_ioctl_compat + snd_ctl_elem_write_read_compat + ctl_elem_write_read + snd_ctl_elem_read [missing lock, not good] + + CVE-2023-0266 was assigned for this issue. + + Cc: stable@kernel.org # 5.13+ + Signed-off-by: Clement Lecigne + Reviewed-by: Jaroslav Kysela + Link: https://lore.kernel.org/r/20230113120745.25464-1-tiwai@suse.de + Signed-off-by: Takashi Iwai + + Author: Clement Lecigne + Date: Fri Jan 13 13:07:45 2023 +0100 + + CVE: CVE-2023-0266 + + Signed-off-by: Jaroslav Kysela + (cherry picked from commit 56b88b50565cd8b946a2d00b0c83927b7ebb055e) + Bugzilla: https://bugzilla.redhat.com/2163390 + +Signed-off-by: Ryan Sullivan +--- + sound/core/control.c | 24 +++++++++++++++--------- + 1 file changed, 15 insertions(+), 9 deletions(-) + +diff --git a/sound/core/control.c b/sound/core/control.c +index a25c0d64d104..6e2a1e424627 100644 +--- a/sound/core/control.c ++++ b/sound/core/control.c +@@ -1066,14 +1066,19 @@ static int snd_ctl_elem_read(struct snd_card *card, + const u32 pattern = 0xdeadbeef; + int ret; + ++ down_read(&card->controls_rwsem); + kctl = snd_ctl_find_id(card, &control->id); +- if (kctl == NULL) +- return -ENOENT; ++ if (kctl == NULL) { ++ ret = -ENOENT; ++ goto unlock; ++ } + + index_offset = snd_ctl_get_ioff(kctl, &control->id); + vd = &kctl->vd[index_offset]; +- if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL) +- return -EPERM; ++ if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL) { ++ ret = -EPERM; ++ goto unlock; ++ } + + snd_ctl_build_ioff(&control->id, kctl, index_offset); + +@@ -1083,7 +1088,7 @@ static int snd_ctl_elem_read(struct snd_card *card, + info.id = control->id; + ret = __snd_ctl_elem_info(card, kctl, &info, NULL); + if (ret < 0) +- return ret; ++ goto unlock; + #endif + + if (!snd_ctl_skip_validation(&info)) +@@ -1093,7 +1098,7 @@ static int snd_ctl_elem_read(struct snd_card *card, + ret = kctl->get(kctl, control); + snd_power_unref(card); + if (ret < 0) +- return ret; ++ goto unlock; + if (!snd_ctl_skip_validation(&info) && + sanity_check_elem_value(card, control, &info, pattern) < 0) { + dev_err(card->dev, +@@ -1101,8 +1106,11 @@ static int snd_ctl_elem_read(struct snd_card *card, + control->id.iface, control->id.device, + control->id.subdevice, control->id.name, + control->id.index); +- return -EINVAL; ++ ret = -EINVAL; ++ goto unlock; + } ++unlock: ++ up_read(&card->controls_rwsem); + return ret; + } + +@@ -1116,9 +1124,7 @@ static int snd_ctl_elem_read_user(struct snd_card *card, + if (IS_ERR(control)) + return PTR_ERR(control); + +- down_read(&card->controls_rwsem); + result = snd_ctl_elem_read(card, control); +- up_read(&card->controls_rwsem); + if (result < 0) + goto error; + +-- +2.39.2 + + diff --git a/SOURCES/v0.9.7-backport-MR-1314-create-diff-object-fix-__UNI.patch b/SOURCES/v0.9.7-backport-MR-1314-create-diff-object-fix-__UNI.patch new file mode 100644 index 0000000..0cef2c1 --- /dev/null +++ b/SOURCES/v0.9.7-backport-MR-1314-create-diff-object-fix-__UNI.patch @@ -0,0 +1,77 @@ +From c351828bf35121628461095eeb25ea2152e98d38 Mon Sep 17 00:00:00 2001 +From: Josh Poimboeuf +Date: Mon, 21 Nov 2022 19:32:18 -0800 +Subject: [PATCH] v0.9.7 backport: MR!1314 ("create-diff-object: fix + __UNIQUE_ID() variable correlation") + +commit 901445a54fcecbd6852b79878e67153c5048602e +Author: Josh Poimboeuf +Date: Mon Nov 21 19:32:18 2022 -0800 + + create-diff-object: fix __UNIQUE_ID() variable correlation + + kpatch_mangled_strcmp() only ignores the digits after the period, but in + the case of __UNIQUE_ID(), the symbol names have random digits before + the period due to the use of `__COUNTER__`. Make sure such symbols are + properly correlated. + + Signed-off-by: Josh Poimboeuf + +Signed-off-by: Yannick Cote +--- + kpatch-build/create-diff-object.c | 32 +++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index 360441111c5e..7106b67cfd25 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -396,6 +396,35 @@ static bool has_digit_tail(char *tail) + return false; + } + ++/* ++ * Hack for __UNIQUE_ID(). The following should match: ++ * ++ * __UNIQUE_ID_ddebug1131.186 ++ * __UNIQUE_ID_ddebug1132.187 ++ */ ++static int __kpatch_unique_id_strcmp(char *s1, char *s2) ++{ ++ /* match '__UNIQUE_ID_ddebug' */ ++ while (*s1 == *s2) { ++ if (!*s1) ++ return 0; ++ s1++; ++ s2++; ++ } ++ ++ /* skip digits before '.' or EOL */ ++ while (isdigit(*s1)) ++ s1++; ++ while (isdigit(*s2)) ++ s2++; ++ ++ if ((!*s1 || has_digit_tail(s1)) && ++ (!*s2 || has_digit_tail(s2))) ++ return 0; ++ ++ return 1; ++} ++ + /* + * This is like strcmp, but for gcc-mangled symbols. It skips the comparison + * of any substring which consists of '.' followed by any number of digits. +@@ -409,6 +438,9 @@ static int kpatch_mangled_strcmp(char *s1, char *s2) + if (strstr(s1, ".str1.")) + return strcmp(s1, s2); + ++ if (!strncmp(s1, "__UNIQUE_ID_", 12)) ++ return __kpatch_unique_id_strcmp(s1, s2); ++ + while (*s1 == *s2) { + if (!*s1) + return 0; +-- +2.38.1 + diff --git a/SOURCES/v0.9.7-backport-MR-1315-Static-call-fixes.patch b/SOURCES/v0.9.7-backport-MR-1315-Static-call-fixes.patch new file mode 100644 index 0000000..58f2e3f --- /dev/null +++ b/SOURCES/v0.9.7-backport-MR-1315-Static-call-fixes.patch @@ -0,0 +1,529 @@ +From 358743e6d8748510f4c9a71511d7ceea7c72f7aa Mon Sep 17 00:00:00 2001 +From: Josh Poimboeuf +Date: Mon, 21 Nov 2022 19:23:07 -0800 +Subject: [PATCH] v0.9.7 backport: MR!1315 ("Static call fixes") + +commit 87ad96760a3af0db294d44865dfa1703f57f5595 +Author: Josh Poimboeuf +Date: Mon Nov 21 19:23:07 2022 -0800 + + create-diff-object: fix s390 special_section initializer spacing + + Align the s390 special_section initializers to improve readability and + for consistency with the rest. + + Signed-off-by: Josh Poimboeuf + +commit 56bd8c4d0da1634f8549e7269f77a53e9d936a57 +Author: Josh Poimboeuf +Date: Mon Nov 21 19:27:23 2022 -0800 + + create-diff-object: refactor jump label filtering + + Convert the hard-coded should_keep_jump_label() to a proper callback, + since static calls will need a similar filter. + + Signed-off-by: Josh Poimboeuf + +commit f83218ad12a2d9e20d99d379c78974a576aa558c +Author: Josh Poimboeuf +Date: Mon Nov 21 19:29:53 2022 -0800 + + create-diff-object: detect unsupported static calls + + Similar to jump labels, static calls aren't supported when the static + call key was originally defined in a module rather than in vmlinux. + Detect those cases and either remove them (in the case of tracepoints) + or error out. + + Signed-off-by: Josh Poimboeuf + +commit ab2397c03e31f0f697aa8bf943d70b4e5a7def54 +Author: Josh Poimboeuf +Date: Mon Nov 21 19:41:30 2022 -0800 + + kpatch-macros: add KPATCH_STATIC_CALL() + + Signed-off-by: Josh Poimboeuf + +commit 92c178b6a30a827c48db46ff4238501ec406a28e +Author: Josh Poimboeuf +Date: Tue Nov 22 12:53:09 2022 -0800 + + create-diff-object: use errx() instead of err() + + Otherwise on recent distros it appends the errno to the error message, + like: + + create-diff-object: ERROR: x86.o: kpatch_regenerate_special_section: 2633: Found 1 unsupported static call(s) in the patched code. Use KPATCH_STATIC_CALL() instead.: Success + + which is not what we want in most cases. + + Signed-off-by: Josh Poimboeuf + +Signed-off-by: Yannick Cote +--- + kmod/patch/kpatch-macros.h | 11 + + kpatch-build/create-diff-object.c | 328 ++++++++++++++++++------------ + kpatch-build/log.h | 2 +- + 3 files changed, 211 insertions(+), 130 deletions(-) + +diff --git a/kmod/patch/kpatch-macros.h b/kmod/patch/kpatch-macros.h +index 8e09702ea001..b797838849ca 100644 +--- a/kmod/patch/kpatch-macros.h ++++ b/kmod/patch/kpatch-macros.h +@@ -141,4 +141,15 @@ struct kpatch_post_unpatch_callback { + printk(_fmt, ## __VA_ARGS__); \ + }) + ++/* ++ * KPATCH_STATIC_CALL macro ++ * ++ * Replace usages of static_call() with this macro, when create-diff-object ++ * recommends it due to the original static call key living in a module. ++ * ++ * This converts the static call to a regular indirect call. ++ */ ++#define KPATCH_STATIC_CALL(name) \ ++ ((typeof(STATIC_CALL_TRAMP(name))*)(STATIC_CALL_KEY(name).func)) ++ + #endif /* __KPATCH_MACROS_H_ */ +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index 7106b67cfd25..ddaa9b44f11e 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -56,7 +56,7 @@ + #define DIFF_FATAL(format, ...) \ + ({ \ + fprintf(stderr, "ERROR: %s: " format "\n", childobj, ##__VA_ARGS__); \ +- err(EXIT_STATUS_DIFF_FATAL, "unreconcilable difference"); \ ++ errx(EXIT_STATUS_DIFF_FATAL, "unreconcilable difference"); \ + }) + + char *childobj; +@@ -71,6 +71,8 @@ enum loglevel loglevel = NORMAL; + + bool KLP_ARCH; + ++int jump_label_errors, static_call_errors; ++ + /******************* + * Data structures + * ****************/ +@@ -78,6 +80,9 @@ struct special_section { + char *name; + enum architecture arch; + int (*group_size)(struct kpatch_elf *kelf, int offset); ++ bool (*group_filter)(struct lookup_table *lookup, ++ struct section *relasec, unsigned int offset, ++ unsigned int size); + }; + + /************* +@@ -2215,6 +2220,169 @@ static int fixup_group_size(struct kpatch_elf *kelf, int offset) + return (int)(rela->addend - offset); + } + ++static bool jump_table_group_filter(struct lookup_table *lookup, ++ struct section *relasec, ++ unsigned int group_offset, ++ unsigned int group_size) ++{ ++ struct rela *code = NULL, *key = NULL, *rela; ++ bool tracepoint = false, dynamic_debug = false; ++ struct lookup_result symbol; ++ int i = 0; ++ ++ /* ++ * Here we hard-code knowledge about the contents of the jump_entry ++ * struct. It has three fields: code, target, and key. Each field has ++ * a relocation associated with it. ++ */ ++ list_for_each_entry(rela, &relasec->relas, list) { ++ if (rela->offset >= group_offset && ++ rela->offset < group_offset + group_size) { ++ if (i == 0) ++ code = rela; ++ else if (i == 2) ++ key = rela; ++ i++; ++ } ++ } ++ ++ if (i != 3 || !key || !code) ++ ERROR("BUG: __jump_table has an unexpected format"); ++ ++ if (!strncmp(key->sym->name, "__tracepoint_", 13)) ++ tracepoint = true; ++ ++ if (is_dynamic_debug_symbol(key->sym)) ++ dynamic_debug = true; ++ ++ if (KLP_ARCH) { ++ /* ++ * On older kernels (with .klp.arch support), jump labels ++ * aren't supported at all. Error out when they occur in a ++ * replacement function, with the exception of tracepoints and ++ * dynamic debug printks. An inert tracepoint or printk is ++ * harmless enough, but a broken jump label can cause ++ * unexpected behavior. ++ */ ++ if (tracepoint || dynamic_debug) ++ return false; ++ ++ /* ++ * This will be upgraded to an error after all jump labels have ++ * been reported. ++ */ ++ log_normal("Found a jump label at %s()+0x%lx, using key %s. Jump labels aren't supported with this kernel. Use static_key_enabled() instead.\n", ++ code->sym->name, code->addend, key->sym->name); ++ jump_label_errors++; ++ return false; ++ } ++ ++ /* ++ * On newer (5.8+) kernels, jump labels are supported in the case where ++ * the corresponding static key lives in vmlinux. That's because such ++ * kernels apply vmlinux-specific .klp.rela sections at the same time ++ * (in the klp module load) as normal relas, before jump label init. ++ * On the other hand, jump labels based on static keys which are ++ * defined in modules aren't supported, because late module patching ++ * can result in the klp relas getting applied *after* the klp module's ++ * jump label init. ++ */ ++ ++ if (lookup_symbol(lookup, key->sym, &symbol) && ++ strcmp(symbol.objname, "vmlinux")) { ++ ++ /* The static key lives in a module -- not supported */ ++ ++ /* Inert tracepoints and dynamic debug printks are harmless */ ++ if (tracepoint || dynamic_debug) ++ return false; ++ ++ /* ++ * This will be upgraded to an error after all jump label ++ * errors have been reported. ++ */ ++ log_normal("Found a jump label at %s()+0x%lx, using key %s, which is defined in a module. Use static_key_enabled() instead.\n", ++ code->sym->name, code->addend, key->sym->name); ++ jump_label_errors++; ++ return false; ++ } ++ ++ /* The static key lives in vmlinux or the patch module itself */ ++ ++ /* ++ * If the jump label key lives in the '__dyndbg' section, make sure ++ * the section gets included, because we don't use klp relocs for ++ * dynamic debug symbols. For an example of such a key, see ++ * DYNAMIC_DEBUG_BRANCH(). ++ */ ++ if (dynamic_debug) ++ kpatch_include_symbol(key->sym); ++ ++ return true; ++} ++ ++static bool static_call_sites_group_filter(struct lookup_table *lookup, ++ struct section *relasec, ++ unsigned int group_offset, ++ unsigned int group_size) ++{ ++ struct rela *code = NULL, *key = NULL, *rela; ++ bool tracepoint = false; ++ struct lookup_result symbol; ++ int i = 0; ++ ++ /* ++ * Here we hard-code knowledge about the contents of the jump_entry ++ * struct. It has three fields: code, target, and key. Each field has ++ * a relocation associated with it. ++ */ ++ list_for_each_entry(rela, &relasec->relas, list) { ++ if (rela->offset >= group_offset && ++ rela->offset < group_offset + group_size) { ++ if (i == 0) ++ code = rela; ++ else if (i == 1) ++ key = rela; ++ i++; ++ } ++ } ++ ++ if (i != 2 || !key || !code) ++ ERROR("BUG: .static_call_sites has an unexpected format"); ++ ++ if (!strncmp(key->sym->name, "__SCK__tp_func_", 15)) ++ tracepoint = true; ++ ++ /* ++ * Static calls are only supported in the case where the corresponding ++ * static call key lives in vmlinux (see explanation in ++ * jump_table_group_filter). ++ */ ++ ++ if (lookup_symbol(lookup, key->sym, &symbol) && ++ strcmp(symbol.objname, "vmlinux")) { ++ ++ /* The key lives in a module -- not supported */ ++ ++ /* Inert tracepoints are harmless */ ++ if (tracepoint) ++ return false; ++ ++ /* ++ * This will be upgraded to an error after all static call ++ * errors have been reported. ++ */ ++ log_normal("Found a static call at %s()+0x%lx, using key %s, which is defined in a module. Use KPATCH_STATIC_CALL() instead.\n", ++ code->sym->name, code->addend, key->sym->name); ++ static_call_errors++; ++ return false; ++ } ++ ++ /* The key lives in vmlinux or the patch module itself */ ++ return true; ++} ++ ++ + static struct special_section special_sections[] = { + { + .name = "__bug_table", +@@ -2235,6 +2403,7 @@ static struct special_section special_sections[] = { + .name = "__jump_table", + .arch = X86_64 | PPC64 | S390, + .group_size = jump_table_group_size, ++ .group_filter = jump_table_group_filter, + }, + { + .name = ".printk_index", +@@ -2260,6 +2429,7 @@ static struct special_section special_sections[] = { + .name = ".static_call_sites", + .arch = X86_64, + .group_size = static_call_sites_group_size, ++ .group_filter = static_call_sites_group_filter, + }, + { + .name = ".retpoline_sites", +@@ -2297,138 +2467,36 @@ static struct special_section special_sections[] = { + .group_size = fixup_barrier_nospec_group_size, + }, + { +- .name = ".s390_return_mem", +- .arch = S390, +- .group_size = s390_expolines_group_size, ++ .name = ".s390_return_mem", ++ .arch = S390, ++ .group_size = s390_expolines_group_size, + }, + { +- .name = ".s390_return_reg", +- .arch = S390, +- .group_size = s390_expolines_group_size, ++ .name = ".s390_return_reg", ++ .arch = S390, ++ .group_size = s390_expolines_group_size, + }, + { +- .name = ".s390_indirect_call", +- .arch = S390, +- .group_size = s390_expolines_group_size, ++ .name = ".s390_indirect_call", ++ .arch = S390, ++ .group_size = s390_expolines_group_size, + }, + { +- .name = ".s390_indirect_branches", +- .arch = S390, +- .group_size = s390_expolines_group_size, ++ .name = ".s390_indirect_branches", ++ .arch = S390, ++ .group_size = s390_expolines_group_size, + }, + { +- .name = ".s390_indirect_jump", +- .arch = S390, +- .group_size = s390_expolines_group_size, ++ .name = ".s390_indirect_jump", ++ .arch = S390, ++ .group_size = s390_expolines_group_size, + }, + {}, + }; + +-static bool should_keep_jump_label(struct lookup_table *lookup, +- struct section *relasec, +- unsigned int group_offset, +- unsigned int group_size, +- int *jump_labels_found) +-{ +- struct rela *code = NULL, *key = NULL, *rela; +- bool tracepoint = false, dynamic_debug = false; +- struct lookup_result symbol; +- int i = 0; +- +- /* +- * Here we hard-code knowledge about the contents of the jump_entry +- * struct. It has three fields: code, target, and key. Each field has +- * a relocation associated with it. +- */ +- list_for_each_entry(rela, &relasec->relas, list) { +- if (rela->offset >= group_offset && +- rela->offset < group_offset + group_size) { +- if (i == 0) +- code = rela; +- else if (i == 2) +- key = rela; +- i++; +- } +- } +- +- if (i != 3 || !key || !code) +- ERROR("BUG: __jump_table has an unexpected format"); +- +- if (!strncmp(key->sym->name, "__tracepoint_", 13)) +- tracepoint = true; +- +- if (is_dynamic_debug_symbol(key->sym)) +- dynamic_debug = true; +- +- if (KLP_ARCH) { +- /* +- * On older kernels (with .klp.arch support), jump labels +- * aren't supported at all. Error out when they occur in a +- * replacement function, with the exception of tracepoints and +- * dynamic debug printks. An inert tracepoint or printk is +- * harmless enough, but a broken jump label can cause +- * unexpected behavior. +- */ +- if (tracepoint || dynamic_debug) +- return false; +- +- /* +- * This will be upgraded to an error after all jump labels have +- * been reported. +- */ +- log_normal("Found a jump label at %s()+0x%lx, using key %s. Jump labels aren't supported with this kernel. Use static_key_enabled() instead.\n", +- code->sym->name, code->addend, key->sym->name); +- (*jump_labels_found)++; +- return false; +- } +- +- /* +- * On newer (5.8+) kernels, jump labels are supported in the case where +- * the corresponding static key lives in vmlinux. That's because such +- * kernels apply vmlinux-specific .klp.rela sections at the same time +- * (in the klp module load) as normal relas, before jump label init. +- * On the other hand, jump labels based on static keys which are +- * defined in modules aren't supported, because late module patching +- * can result in the klp relas getting applied *after* the klp module's +- * jump label init. +- */ +- +- if (lookup_symbol(lookup, key->sym, &symbol) && +- strcmp(symbol.objname, "vmlinux")) { +- +- /* The static key lives in a module -- not supported */ +- +- /* Inert tracepoints and dynamic debug printks are harmless */ +- if (tracepoint || dynamic_debug) +- return false; +- +- /* +- * This will be upgraded to an error after all jump labels have +- * been reported. +- */ +- log_normal("Found a jump label at %s()+0x%lx, using key %s, which is defined in a module. Use static_key_enabled() instead.\n", +- code->sym->name, code->addend, key->sym->name); +- (*jump_labels_found)++; +- return false; +- } +- +- /* The static key lives in vmlinux or the patch module itself */ +- +- /* +- * If the jump label key lives in the '__dyndbg' section, make sure +- * the section gets included, because we don't use klp relocs for +- * dynamic debug symbols. For an example of such a key, see +- * DYNAMIC_DEBUG_BRANCH(). +- */ +- if (dynamic_debug) +- kpatch_include_symbol(key->sym); +- +- return true; +-} +- + static bool should_keep_rela_group(struct lookup_table *lookup, + struct section *relasec, unsigned int offset, +- unsigned int size, int *jump_labels_found) ++ unsigned int size) + { + struct rela *rela; + bool found = false; +@@ -2448,10 +2516,6 @@ static bool should_keep_rela_group(struct lookup_table *lookup, + if (!found) + return false; + +- if (!strcmp(relasec->name, ".rela__jump_table")) +- return should_keep_jump_label(lookup, relasec, offset, size, +- jump_labels_found); +- + return true; + } + +@@ -2488,7 +2552,6 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, + struct rela *rela, *safe; + char *src, *dest; + unsigned int group_size, src_offset, dest_offset; +- int jump_labels_found = 0; + + LIST_HEAD(newrelas); + +@@ -2523,8 +2586,11 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, + if (src_offset + group_size > relasec->base->sh.sh_size) + group_size = (unsigned int)(relasec->base->sh.sh_size - src_offset); + +- if (!should_keep_rela_group(lookup, relasec, src_offset, group_size, +- &jump_labels_found)) ++ if (!should_keep_rela_group(lookup, relasec, src_offset, group_size)) ++ continue; ++ ++ if (special->group_filter && ++ !special->group_filter(lookup, relasec, src_offset, group_size)) + continue; + + /* +@@ -2557,9 +2623,13 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, + dest_offset += group_size; + } + +- if (jump_labels_found) +- ERROR("Found %d jump label(s) in the patched code. Jump labels aren't currently supported. Use static_key_enabled() instead.", +- jump_labels_found); ++ if (jump_label_errors) ++ ERROR("Found %d unsupported jump label(s) in the patched code. Use static_key_enabled() instead.", ++ jump_label_errors); ++ ++ if (static_call_errors) ++ ERROR("Found %d unsupported static call(s) in the patched code. Use KPATCH_STATIC_CALL() instead.", ++ static_call_errors); + + if (!dest_offset) { + /* no changed or global functions referenced */ +diff --git a/kpatch-build/log.h b/kpatch-build/log.h +index eefa0fce7b08..dbdc212713e1 100644 +--- a/kpatch-build/log.h ++++ b/kpatch-build/log.h +@@ -9,7 +9,7 @@ extern enum loglevel loglevel; + extern char *childobj; + + #define ERROR(format, ...) \ +- err(EXIT_STATUS_ERROR, "ERROR: %s: %s: %d: " format, childobj, __FUNCTION__, __LINE__, ##__VA_ARGS__) ++ errx(EXIT_STATUS_ERROR, "ERROR: %s: %s: %d: " format, childobj, __FUNCTION__, __LINE__, ##__VA_ARGS__) + + #define log_debug(format, ...) log(DEBUG, format, ##__VA_ARGS__) + #define log_normal(format, ...) log(NORMAL, "%s: " format, childobj, ##__VA_ARGS__) +-- +2.38.1 + diff --git a/SPECS/kpatch-patch.spec b/SPECS/kpatch-patch.spec index 8a63122..ab3a4d3 100644 --- a/SPECS/kpatch-patch.spec +++ b/SPECS/kpatch-patch.spec @@ -1,17 +1,21 @@ # Set to 1 if building an empty subscription-only package. -%define empty_package 1 +%define empty_package 0 ####################################################### # Only need to update these variables and the changelog %define kernel_ver 5.14.0-162.18.1.el9_1 %define kpatch_ver 0.9.7 -%define rpm_ver 0 -%define rpm_rel 0 +%define rpm_ver 1 +%define rpm_rel 1 %if !%{empty_package} # Patch sources below. DO NOT REMOVE THIS LINE. -Source100: XXX.patch -#Source101: YYY.patch +# +# https://bugzilla.redhat.com/2156383 +Source100: CVE-2022-4744.patch +# +# https://bugzilla.redhat.com/2163415 +Source101: CVE-2023-0266.patch # End of patch sources. DO NOT REMOVE THIS LINE. %endif @@ -189,5 +193,9 @@ It is only a method to subscribe to the kpatch stream for kernel-%{kernel_ver}. %endif %changelog +* Sat Mar 18 2023 Yannick Cote [1-1.el9_1] +- ALSA: pcm: Move rwsem lock inside snd_ctl_elem_read to prevent UAF [2163415] {CVE-2023-0266} +- EMBARGOED CVE-2022-4744 kernel: tun: avoid double free in tun_free_netdev [2156383] {CVE-2022-4744} + * Thu Feb 09 2023 Linqing Lu [0-0.el9] - An empty patch to subscribe to kpatch stream for kernel-5.14.0-162.18.1.el9_1 [2168756]