tree: https://gitee.com/openeuler/kernel.git OLK-6.6
head: 604e996dd0189ddb0875f389b87fa2084b3a9424
commit: cf98ffbc116bc49dc4506c68e20b02e26519ad35 [1682/1682] mm/dynamic_pool: fill dpool with pagelist
config: x86_64-randconfig-121-20250101 (https://download.01.org/0day-ci/archive/20250103/202501031919.9n6qbVhX-lkp@…)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250103/202501031919.9n6qbVhX-lkp@…)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp(a)intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202501031919.9n6qbVhX-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
mm/dynamic_pool.c:999:55: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct cgroup_subsys_state *css @@ got struct cgroup_subsys_state [noderef] __rcu * @@
mm/dynamic_pool.c:999:55: sparse: expected struct cgroup_subsys_state *css
mm/dynamic_pool.c:999:55: sparse: got struct cgroup_subsys_state [noderef] __rcu *
>> mm/dynamic_pool.c:1577:25: sparse: sparse: symbol 'pagelist_dpool_ops' was not declared. Should it be static?
vim +/pagelist_dpool_ops +1577 mm/dynamic_pool.c
1576
> 1577 struct dynamic_pool_ops pagelist_dpool_ops = {
1578 .fill_pool = dpool_fill_from_pagelist,
1579 .drain_pool = dpool_drain_to_pagelist,
1580 .restore_pool = dpool_migrate_used_pages,
1581 };
1582
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
From: Kumar Kartikeya Dwivedi <memxor(a)gmail.com>
mainline inclusion
from mainline-v6.13-rc1
commit cb4158ce8ec8a5bb528cc1693356a5eb8058094d
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEDPP
CVE: CVE-2024-56702
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?…
--------------------------------
Arguments to a raw tracepoint are tagged as trusted, which carries the
semantics that the pointer will be non-NULL. However, in certain cases,
a raw tracepoint argument may end up being NULL. More context about this
issue is available in [0].
Thus, there is a discrepancy between the reality, that raw_tp arguments
can actually be NULL, and the verifier's knowledge, that they are never
NULL, causing explicit NULL checks to be deleted, and accesses to such
pointers potentially crashing the kernel.
To fix this, mark raw_tp arguments as PTR_MAYBE_NULL, and then special
case the dereference and pointer arithmetic to permit it, and allow
passing them into helpers/kfuncs; these exceptions are made for raw_tp
programs only. Ensure that we don't do this when ref_obj_id > 0, as in
that case this is an acquired object and doesn't need such adjustment.
The reason we do mask_raw_tp_trusted_reg logic is because other will
recheck in places whether the register is a trusted_reg, and then
consider our register as untrusted when detecting the presence of the
PTR_MAYBE_NULL flag.
To allow safe dereference, we enable PROBE_MEM marking when we see loads
into trusted pointers with PTR_MAYBE_NULL.
While trusted raw_tp arguments can also be passed into helpers or kfuncs
where such broken assumption may cause issues, a future patch set will
tackle their case separately, as PTR_TO_BTF_ID (without PTR_TRUSTED) can
already be passed into helpers and causes similar problems. Thus, they
are left alone for now.
It is possible that these checks also permit passing non-raw_tp args
that are trusted PTR_TO_BTF_ID with null marking. In such a case,
allowing dereference when pointer is NULL expands allowed behavior, so
won't regress existing programs, and the case of passing these into
helpers is the same as above and will be dealt with later.
Also update the failure case in tp_btf_nullable selftest to capture the
new behavior, as the verifier will no longer cause an error when
directly dereference a raw tracepoint argument marked as __nullable.
[0]: https://lore.kernel.org/bpf/ZrCZS6nisraEqehw@jlelli-thinkpadt14gen4.remote.…
Reviewed-by: Jiri Olsa <jolsa(a)kernel.org>
Reported-by: Juri Lelli <juri.lelli(a)redhat.com>
Tested-by: Juri Lelli <juri.lelli(a)redhat.com>
Fixes: 3f00c5239344 ("bpf: Allow trusted pointers to be passed to KF_TRUSTED_ARGS kfuncs")
Signed-off-by: Kumar Kartikeya Dwivedi <memxor(a)gmail.com>
Link: https://lore.kernel.org/r/20241104171959.2938862-2-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast(a)kernel.org>
Conflicts:
kernel/bpf/verifier.c
tools/testing/selftests/bpf/progs/test_tp_btf_nullable.c
[The conflicts were due to not merge commit e2b3c4ff5d18 and 2060f07f861a2]
Signed-off-by: Pu Lehui <pulehui(a)huawei.com>
---
include/linux/bpf.h | 6 ++++
kernel/bpf/btf.c | 4 +++
kernel/bpf/verifier.c | 77 ++++++++++++++++++++++++++++++++++++++-----
3 files changed, 79 insertions(+), 8 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 73ef8dda7ada..7e7a2507a3e5 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -3322,4 +3322,10 @@ static inline gfp_t bpf_memcg_flags(gfp_t flags)
return flags;
}
+static inline bool bpf_prog_is_raw_tp(const struct bpf_prog *prog)
+{
+ return prog->type == BPF_PROG_TYPE_TRACING &&
+ prog->expected_attach_type == BPF_TRACE_RAW_TP;
+}
+
#endif /* _LINUX_BPF_H */
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 7a82194ad51d..a54a7fdf99cd 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -6076,6 +6076,10 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
if (prog_args_trusted(prog))
info->reg_type |= PTR_TRUSTED;
+ /* Raw tracepoint arguments always get marked as maybe NULL */
+ if (bpf_prog_is_raw_tp(prog))
+ info->reg_type |= PTR_MAYBE_NULL;
+
if (tgt_prog) {
enum bpf_prog_type tgt_type;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 8fa7b37152c0..fe0c8bf97663 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -495,6 +495,25 @@ static struct btf_record *reg_btf_record(const struct bpf_reg_state *reg)
return rec;
}
+static bool mask_raw_tp_reg_cond(const struct bpf_verifier_env *env, struct bpf_reg_state *reg) {
+ return reg->type == (PTR_TO_BTF_ID | PTR_TRUSTED | PTR_MAYBE_NULL) &&
+ bpf_prog_is_raw_tp(env->prog) && !reg->ref_obj_id;
+}
+
+static bool mask_raw_tp_reg(const struct bpf_verifier_env *env, struct bpf_reg_state *reg)
+{
+ if (!mask_raw_tp_reg_cond(env, reg))
+ return false;
+ reg->type &= ~PTR_MAYBE_NULL;
+ return true;
+}
+
+static void unmask_raw_tp_reg(struct bpf_reg_state *reg, bool result)
+{
+ if (result)
+ reg->type |= PTR_MAYBE_NULL;
+}
+
static bool subprog_is_global(const struct bpf_verifier_env *env, int subprog)
{
struct bpf_func_info_aux *aux = env->prog->aux->func_info_aux;
@@ -6458,6 +6477,7 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
const char *field_name = NULL;
enum bpf_type_flag flag = 0;
u32 btf_id = 0;
+ bool mask;
int ret;
if (!env->allow_ptr_leaks) {
@@ -6529,7 +6549,21 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
if (ret < 0)
return ret;
-
+ /* For raw_tp progs, we allow dereference of PTR_MAYBE_NULL
+ * trusted PTR_TO_BTF_ID, these are the ones that are possibly
+ * arguments to the raw_tp. Since internal checks in for trusted
+ * reg in check_ptr_to_btf_access would consider PTR_MAYBE_NULL
+ * modifier as problematic, mask it out temporarily for the
+ * check. Don't apply this to pointers with ref_obj_id > 0, as
+ * those won't be raw_tp args.
+ *
+ * We may end up applying this relaxation to other trusted
+ * PTR_TO_BTF_ID with maybe null flag, since we cannot
+ * distinguish PTR_MAYBE_NULL tagged for arguments vs normal
+ * tagging, but that should expand allowed behavior, and not
+ * cause regression for existing behavior.
+ */
+ mask = mask_raw_tp_reg(env, reg);
if (ret != PTR_TO_BTF_ID) {
/* just mark; */
@@ -6590,8 +6624,13 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
clear_trusted_flags(&flag);
}
- if (atype == BPF_READ && value_regno >= 0)
+ if (atype == BPF_READ && value_regno >= 0) {
mark_btf_ld_reg(env, regs, value_regno, ret, reg->btf, btf_id, flag);
+ /* We've assigned a new type to regno, so don't undo masking. */
+ if (regno == value_regno)
+ mask = false;
+ }
+ unmask_raw_tp_reg(reg, mask);
return 0;
}
@@ -6963,7 +7002,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
if (!err && t == BPF_READ && value_regno >= 0)
mark_reg_unknown(env, regs, value_regno);
} else if (base_type(reg->type) == PTR_TO_BTF_ID &&
- !type_may_be_null(reg->type)) {
+ (mask_raw_tp_reg_cond(env, reg) || !type_may_be_null(reg->type))) {
err = check_ptr_to_btf_access(env, regs, regno, off, size, t,
value_regno);
} else if (reg->type == CONST_PTR_TO_MAP) {
@@ -8515,6 +8554,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
enum bpf_reg_type type = reg->type;
u32 *arg_btf_id = NULL;
int err = 0;
+ bool mask;
if (arg_type == ARG_DONTCARE)
return 0;
@@ -8555,11 +8595,11 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
base_type(arg_type) == ARG_PTR_TO_SPIN_LOCK)
arg_btf_id = fn->arg_btf_id[arg];
+ mask = mask_raw_tp_reg(env, reg);
err = check_reg_type(env, regno, arg_type, arg_btf_id, meta);
- if (err)
- return err;
- err = check_func_arg_reg_off(env, reg, regno, arg_type);
+ err = err ?: check_func_arg_reg_off(env, reg, regno, arg_type);
+ unmask_raw_tp_reg(reg, mask);
if (err)
return err;
@@ -11366,6 +11406,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
enum bpf_arg_type arg_type = ARG_DONTCARE;
u32 regno = i + 1, ref_id, type_size;
bool is_ret_buf_sz = false;
+ bool mask = false;
int kf_arg_type;
t = btf_type_skip_modifiers(btf, args[i].type, NULL);
@@ -11424,11 +11465,14 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
return -EINVAL;
}
+ mask = mask_raw_tp_reg(env, reg);
if ((is_kfunc_trusted_args(meta) || is_kfunc_rcu(meta)) &&
(register_is_null(reg) || type_may_be_null(reg->type))) {
verbose(env, "Possibly NULL pointer passed to trusted arg%d\n", i);
+ unmask_raw_tp_reg(reg, mask);
return -EACCES;
}
+ unmask_raw_tp_reg(reg, mask);
if (reg->ref_obj_id) {
if (is_kfunc_release(meta) && meta->ref_obj_id) {
@@ -11455,17 +11499,24 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
if (!is_kfunc_trusted_args(meta) && !is_kfunc_rcu(meta))
break;
+ /* Allow passing maybe NULL raw_tp arguments to
+ * kfuncs for compatibility. Don't apply this to
+ * arguments with ref_obj_id > 0.
+ */
+ mask = mask_raw_tp_reg(env, reg);
if (!is_trusted_reg(reg)) {
if (!is_kfunc_rcu(meta)) {
verbose(env, "R%d must be referenced or trusted\n", regno);
+ unmask_raw_tp_reg(reg, mask);
return -EINVAL;
}
if (!is_rcu_reg(reg)) {
verbose(env, "R%d must be a rcu pointer\n", regno);
+ unmask_raw_tp_reg(reg, mask);
return -EINVAL;
}
}
-
+ unmask_raw_tp_reg(reg, mask);
fallthrough;
case KF_ARG_PTR_TO_CTX:
/* Trusted arguments have the same offset checks as release arguments */
@@ -11490,7 +11541,9 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
if (is_kfunc_release(meta) && reg->ref_obj_id)
arg_type |= OBJ_RELEASE;
+ mask = mask_raw_tp_reg(env, reg);
ret = check_func_arg_reg_off(env, reg, regno, arg_type);
+ unmask_raw_tp_reg(reg, mask);
if (ret < 0)
return ret;
@@ -11651,6 +11704,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
return ret;
break;
case KF_ARG_PTR_TO_BTF_ID:
+ mask = mask_raw_tp_reg(env, reg);
/* Only base_type is checked, further checks are done here */
if ((base_type(reg->type) != PTR_TO_BTF_ID ||
(bpf_type_has_unsafe_modifiers(reg->type) && !is_rcu_reg(reg))) &&
@@ -11659,9 +11713,11 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
verbose(env, "expected %s or socket\n",
reg_type_str(env, base_type(reg->type) |
(type_flag(reg->type) & BPF_REG_TRUSTED_MODIFIERS)));
+ unmask_raw_tp_reg(reg, mask);
return -EINVAL;
}
ret = process_kf_arg_ptr_to_btf_id(env, reg, ref_t, ref_tname, ref_id, meta, i);
+ unmask_raw_tp_reg(reg, mask);
if (ret < 0)
return ret;
break;
@@ -12548,7 +12604,7 @@ static int sanitize_check_bounds(struct bpf_verifier_env *env,
*/
static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
struct bpf_insn *insn,
- const struct bpf_reg_state *ptr_reg,
+ struct bpf_reg_state *ptr_reg,
const struct bpf_reg_state *off_reg)
{
struct bpf_verifier_state *vstate = env->cur_state;
@@ -12562,6 +12618,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
struct bpf_sanitize_info info = {};
u8 opcode = BPF_OP(insn->code);
u32 dst = insn->dst_reg;
+ bool mask;
int ret;
dst_reg = ®s[dst];
@@ -12588,11 +12645,14 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
return -EACCES;
}
+ mask = mask_raw_tp_reg(env, ptr_reg);
if (ptr_reg->type & PTR_MAYBE_NULL) {
verbose(env, "R%d pointer arithmetic on %s prohibited, null-check it first\n",
dst, reg_type_str(env, ptr_reg->type));
+ unmask_raw_tp_reg(ptr_reg, mask);
return -EACCES;
}
+ unmask_raw_tp_reg(ptr_reg, mask);
switch (base_type(ptr_reg->type)) {
case PTR_TO_FLOW_KEYS:
@@ -18455,6 +18515,7 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
* for this case.
*/
case PTR_TO_BTF_ID | MEM_ALLOC | PTR_UNTRUSTED:
+ case PTR_TO_BTF_ID | PTR_TRUSTED | PTR_MAYBE_NULL:
if (type == BPF_READ) {
if (BPF_MODE(insn->code) == BPF_MEM)
insn->code = BPF_LDX | BPF_PROBE_MEM |
--
2.34.1
etmem: fix use-after-free of mm in the scan release process
chenrenhui (1):
etmem: fix use-after-free of mm in the scan release process
fs/proc/task_mmu.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
--
2.33.0
From: Lukas Wunner <lukas(a)wunner.de>
stable inclusion
from stable-v5.10.231
commit da6e6ff1f6c57f16e07af955e0e997fc90dd1e75
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEAF8
CVE: CVE-2024-53194
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
commit c7acef99642b763ba585f4a43af999fcdbcc3dc4 upstream.
Dennis reports a boot crash on recent Lenovo laptops with a USB4 dock.
Since commit 0fc70886569c ("thunderbolt: Reset USB4 v2 host router") and
commit 59a54c5f3dbd ("thunderbolt: Reset topology created by the boot
firmware"), USB4 v2 and v1 Host Routers are reset on probe of the
thunderbolt driver.
The reset clears the Presence Detect State and Data Link Layer Link Active
bits at the USB4 Host Router's Root Port and thus causes hot removal of the
dock.
The crash occurs when pciehp is unbound from one of the dock's Downstream
Ports: pciehp creates a pci_slot on bind and destroys it on unbind. The
pci_slot contains a pointer to the pci_bus below the Downstream Port, but
a reference on that pci_bus is never acquired. The pci_bus is destroyed
before the pci_slot, so a use-after-free ensues when pci_slot_release()
accesses slot->bus.
In principle this should not happen because pci_stop_bus_device() unbinds
pciehp (and therefore destroys the pci_slot) before the pci_bus is
destroyed by pci_remove_bus_device().
However the stacktrace provided by Dennis shows that pciehp is unbound from
pci_remove_bus_device() instead of pci_stop_bus_device(). To understand
the significance of this, one needs to know that the PCI core uses a two
step process to remove a portion of the hierarchy: It first unbinds all
drivers in the sub-hierarchy in pci_stop_bus_device() and then actually
removes the devices in pci_remove_bus_device(). There is no precaution to
prevent driver binding in-between pci_stop_bus_device() and
pci_remove_bus_device().
In Dennis' case, it seems removal of the hierarchy by pciehp races with
driver binding by pci_bus_add_devices(). pciehp is bound to the
Downstream Port after pci_stop_bus_device() has run, so it is unbound by
pci_remove_bus_device() instead of pci_stop_bus_device(). Because the
pci_bus has already been destroyed at that point, accesses to it result in
a use-after-free.
One might conclude that driver binding needs to be prevented after
pci_stop_bus_device() has run. However it seems risky that pci_slot points
to pci_bus without holding a reference. Solely relying on correct ordering
of driver unbind versus pci_bus destruction is certainly not defensive
programming.
If pci_slot has a need to access data in pci_bus, it ought to acquire a
reference. Amend pci_create_slot() accordingly. Dennis reports that the
crash is not reproducible with this change.
Abridged stacktrace:
pcieport 0000:00:07.0: PME: Signaling with IRQ 156
pcieport 0000:00:07.0: pciehp: Slot #12 AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug+ Surprise+ Interlock- NoCompl+ IbPresDis- LLActRep+
pci_bus 0000:20: dev 00, created physical slot 12
pcieport 0000:00:07.0: pciehp: Slot(12): Card not present
...
pcieport 0000:21:02.0: pciehp: pcie_disable_notification: SLOTCTRL d8 write cmd 0
Oops: general protection fault, probably for non-canonical address 0x6b6b6b6b6b6b6b6b: 0000 [#1] PREEMPT SMP NOPTI
CPU: 13 UID: 0 PID: 134 Comm: irq/156-pciehp Not tainted 6.11.0-devel+ #1
RIP: 0010:dev_driver_string+0x12/0x40
pci_destroy_slot
pciehp_remove
pcie_port_remove_service
device_release_driver_internal
bus_remove_device
device_del
device_unregister
remove_iter
device_for_each_child
pcie_portdrv_remove
pci_device_remove
device_release_driver_internal
bus_remove_device
device_del
pci_remove_bus_device (recursive invocation)
pci_remove_bus_device
pciehp_unconfigure_device
pciehp_disable_slot
pciehp_handle_presence_or_link_change
pciehp_ist
Link: https://lore.kernel.org/r/4bfd4c0e976c1776cd08e76603903b338cf25729.17285792…
Reported-by: Dennis Wassenberg <Dennis.Wassenberg(a)secunet.com>
Closes: https://lore.kernel.org/r/6de4b45ff2b32dd91a805ec02ec8ec73ef411bf6.camel@se…
Tested-by: Dennis Wassenberg <Dennis.Wassenberg(a)secunet.com>
Signed-off-by: Lukas Wunner <lukas(a)wunner.de>
Signed-off-by: Bjorn Helgaas <bhelgaas(a)google.com>
Reviewed-by: Mika Westerberg <mika.westerberg(a)linux.intel.com>
Cc: stable(a)vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: Xiongfeng Wang <wangxiongfeng2(a)huawei.com>
---
drivers/pci/slot.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
index ed2077e7470ae..a42e2cf774fd8 100644
--- a/drivers/pci/slot.c
+++ b/drivers/pci/slot.c
@@ -79,6 +79,7 @@ static void pci_slot_release(struct kobject *kobj)
up_read(&pci_bus_sem);
list_del(&slot->list);
+ pci_bus_put(slot->bus);
kfree(slot);
}
@@ -260,7 +261,7 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
goto err;
}
- slot->bus = parent;
+ slot->bus = pci_bus_get(parent);
slot->number = slot_nr;
slot->kobj.kset = pci_slots_kset;
@@ -268,6 +269,7 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
slot_name = make_slot_name(name);
if (!slot_name) {
err = -ENOMEM;
+ pci_bus_put(slot->bus);
kfree(slot);
goto err;
}
--
2.20.1
From: Lukas Wunner <lukas(a)wunner.de>
stable inclusion
from stable-v5.10.231
commit da6e6ff1f6c57f16e07af955e0e997fc90dd1e75
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEAF8
CVE: CVE-2024-53194
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
commit c7acef99642b763ba585f4a43af999fcdbcc3dc4 upstream.
Dennis reports a boot crash on recent Lenovo laptops with a USB4 dock.
Since commit 0fc70886569c ("thunderbolt: Reset USB4 v2 host router") and
commit 59a54c5f3dbd ("thunderbolt: Reset topology created by the boot
firmware"), USB4 v2 and v1 Host Routers are reset on probe of the
thunderbolt driver.
The reset clears the Presence Detect State and Data Link Layer Link Active
bits at the USB4 Host Router's Root Port and thus causes hot removal of the
dock.
The crash occurs when pciehp is unbound from one of the dock's Downstream
Ports: pciehp creates a pci_slot on bind and destroys it on unbind. The
pci_slot contains a pointer to the pci_bus below the Downstream Port, but
a reference on that pci_bus is never acquired. The pci_bus is destroyed
before the pci_slot, so a use-after-free ensues when pci_slot_release()
accesses slot->bus.
In principle this should not happen because pci_stop_bus_device() unbinds
pciehp (and therefore destroys the pci_slot) before the pci_bus is
destroyed by pci_remove_bus_device().
However the stacktrace provided by Dennis shows that pciehp is unbound from
pci_remove_bus_device() instead of pci_stop_bus_device(). To understand
the significance of this, one needs to know that the PCI core uses a two
step process to remove a portion of the hierarchy: It first unbinds all
drivers in the sub-hierarchy in pci_stop_bus_device() and then actually
removes the devices in pci_remove_bus_device(). There is no precaution to
prevent driver binding in-between pci_stop_bus_device() and
pci_remove_bus_device().
In Dennis' case, it seems removal of the hierarchy by pciehp races with
driver binding by pci_bus_add_devices(). pciehp is bound to the
Downstream Port after pci_stop_bus_device() has run, so it is unbound by
pci_remove_bus_device() instead of pci_stop_bus_device(). Because the
pci_bus has already been destroyed at that point, accesses to it result in
a use-after-free.
One might conclude that driver binding needs to be prevented after
pci_stop_bus_device() has run. However it seems risky that pci_slot points
to pci_bus without holding a reference. Solely relying on correct ordering
of driver unbind versus pci_bus destruction is certainly not defensive
programming.
If pci_slot has a need to access data in pci_bus, it ought to acquire a
reference. Amend pci_create_slot() accordingly. Dennis reports that the
crash is not reproducible with this change.
Abridged stacktrace:
pcieport 0000:00:07.0: PME: Signaling with IRQ 156
pcieport 0000:00:07.0: pciehp: Slot #12 AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug+ Surprise+ Interlock- NoCompl+ IbPresDis- LLActRep+
pci_bus 0000:20: dev 00, created physical slot 12
pcieport 0000:00:07.0: pciehp: Slot(12): Card not present
...
pcieport 0000:21:02.0: pciehp: pcie_disable_notification: SLOTCTRL d8 write cmd 0
Oops: general protection fault, probably for non-canonical address 0x6b6b6b6b6b6b6b6b: 0000 [#1] PREEMPT SMP NOPTI
CPU: 13 UID: 0 PID: 134 Comm: irq/156-pciehp Not tainted 6.11.0-devel+ #1
RIP: 0010:dev_driver_string+0x12/0x40
pci_destroy_slot
pciehp_remove
pcie_port_remove_service
device_release_driver_internal
bus_remove_device
device_del
device_unregister
remove_iter
device_for_each_child
pcie_portdrv_remove
pci_device_remove
device_release_driver_internal
bus_remove_device
device_del
pci_remove_bus_device (recursive invocation)
pci_remove_bus_device
pciehp_unconfigure_device
pciehp_disable_slot
pciehp_handle_presence_or_link_change
pciehp_ist
Link: https://lore.kernel.org/r/4bfd4c0e976c1776cd08e76603903b338cf25729.17285792…
Reported-by: Dennis Wassenberg <Dennis.Wassenberg(a)secunet.com>
Closes: https://lore.kernel.org/r/6de4b45ff2b32dd91a805ec02ec8ec73ef411bf6.camel@se…
Tested-by: Dennis Wassenberg <Dennis.Wassenberg(a)secunet.com>
Signed-off-by: Lukas Wunner <lukas(a)wunner.de>
Signed-off-by: Bjorn Helgaas <bhelgaas(a)google.com>
Reviewed-by: Mika Westerberg <mika.westerberg(a)linux.intel.com>
Cc: stable(a)vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: Xiongfeng Wang <wangxiongfeng2(a)huawei.com>
---
drivers/pci/slot.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
index ed2077e7470ae..a42e2cf774fd8 100644
--- a/drivers/pci/slot.c
+++ b/drivers/pci/slot.c
@@ -79,6 +79,7 @@ static void pci_slot_release(struct kobject *kobj)
up_read(&pci_bus_sem);
list_del(&slot->list);
+ pci_bus_put(slot->bus);
kfree(slot);
}
@@ -260,7 +261,7 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
goto err;
}
- slot->bus = parent;
+ slot->bus = pci_bus_get(parent);
slot->number = slot_nr;
slot->kobj.kset = pci_slots_kset;
@@ -268,6 +269,7 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
slot_name = make_slot_name(name);
if (!slot_name) {
err = -ENOMEM;
+ pci_bus_put(slot->bus);
kfree(slot);
goto err;
}
--
2.20.1
From: Lukas Wunner <lukas(a)wunner.de>
stable inclusion
from stable-v4.19.325
commit 50473dd3b2a08601a078f852ea05572de9b1f86c
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEAF8
CVE: CVE-2024-53194
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
commit c7acef99642b763ba585f4a43af999fcdbcc3dc4 upstream.
Dennis reports a boot crash on recent Lenovo laptops with a USB4 dock.
Since commit 0fc70886569c ("thunderbolt: Reset USB4 v2 host router") and
commit 59a54c5f3dbd ("thunderbolt: Reset topology created by the boot
firmware"), USB4 v2 and v1 Host Routers are reset on probe of the
thunderbolt driver.
The reset clears the Presence Detect State and Data Link Layer Link Active
bits at the USB4 Host Router's Root Port and thus causes hot removal of the
dock.
The crash occurs when pciehp is unbound from one of the dock's Downstream
Ports: pciehp creates a pci_slot on bind and destroys it on unbind. The
pci_slot contains a pointer to the pci_bus below the Downstream Port, but
a reference on that pci_bus is never acquired. The pci_bus is destroyed
before the pci_slot, so a use-after-free ensues when pci_slot_release()
accesses slot->bus.
In principle this should not happen because pci_stop_bus_device() unbinds
pciehp (and therefore destroys the pci_slot) before the pci_bus is
destroyed by pci_remove_bus_device().
However the stacktrace provided by Dennis shows that pciehp is unbound from
pci_remove_bus_device() instead of pci_stop_bus_device(). To understand
the significance of this, one needs to know that the PCI core uses a two
step process to remove a portion of the hierarchy: It first unbinds all
drivers in the sub-hierarchy in pci_stop_bus_device() and then actually
removes the devices in pci_remove_bus_device(). There is no precaution to
prevent driver binding in-between pci_stop_bus_device() and
pci_remove_bus_device().
In Dennis' case, it seems removal of the hierarchy by pciehp races with
driver binding by pci_bus_add_devices(). pciehp is bound to the
Downstream Port after pci_stop_bus_device() has run, so it is unbound by
pci_remove_bus_device() instead of pci_stop_bus_device(). Because the
pci_bus has already been destroyed at that point, accesses to it result in
a use-after-free.
One might conclude that driver binding needs to be prevented after
pci_stop_bus_device() has run. However it seems risky that pci_slot points
to pci_bus without holding a reference. Solely relying on correct ordering
of driver unbind versus pci_bus destruction is certainly not defensive
programming.
If pci_slot has a need to access data in pci_bus, it ought to acquire a
reference. Amend pci_create_slot() accordingly. Dennis reports that the
crash is not reproducible with this change.
Abridged stacktrace:
pcieport 0000:00:07.0: PME: Signaling with IRQ 156
pcieport 0000:00:07.0: pciehp: Slot #12 AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug+ Surprise+ Interlock- NoCompl+ IbPresDis- LLActRep+
pci_bus 0000:20: dev 00, created physical slot 12
pcieport 0000:00:07.0: pciehp: Slot(12): Card not present
...
pcieport 0000:21:02.0: pciehp: pcie_disable_notification: SLOTCTRL d8 write cmd 0
Oops: general protection fault, probably for non-canonical address 0x6b6b6b6b6b6b6b6b: 0000 [#1] PREEMPT SMP NOPTI
CPU: 13 UID: 0 PID: 134 Comm: irq/156-pciehp Not tainted 6.11.0-devel+ #1
RIP: 0010:dev_driver_string+0x12/0x40
pci_destroy_slot
pciehp_remove
pcie_port_remove_service
device_release_driver_internal
bus_remove_device
device_del
device_unregister
remove_iter
device_for_each_child
pcie_portdrv_remove
pci_device_remove
device_release_driver_internal
bus_remove_device
device_del
pci_remove_bus_device (recursive invocation)
pci_remove_bus_device
pciehp_unconfigure_device
pciehp_disable_slot
pciehp_handle_presence_or_link_change
pciehp_ist
Link: https://lore.kernel.org/r/4bfd4c0e976c1776cd08e76603903b338cf25729.17285792…
Reported-by: Dennis Wassenberg <Dennis.Wassenberg(a)secunet.com>
Closes: https://lore.kernel.org/r/6de4b45ff2b32dd91a805ec02ec8ec73ef411bf6.camel@se…
Tested-by: Dennis Wassenberg <Dennis.Wassenberg(a)secunet.com>
Signed-off-by: Lukas Wunner <lukas(a)wunner.de>
Signed-off-by: Bjorn Helgaas <bhelgaas(a)google.com>
Reviewed-by: Mika Westerberg <mika.westerberg(a)linux.intel.com>
Cc: stable(a)vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: Xiongfeng Wang <wangxiongfeng2(a)huawei.com>
---
drivers/pci/slot.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
index 19de071ca698..ddc0e962285f 100644
--- a/drivers/pci/slot.c
+++ b/drivers/pci/slot.c
@@ -79,6 +79,7 @@ static void pci_slot_release(struct kobject *kobj)
up_read(&pci_bus_sem);
list_del(&slot->list);
+ pci_bus_put(slot->bus);
kfree(slot);
}
@@ -260,7 +261,7 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
goto err;
}
- slot->bus = parent;
+ slot->bus = pci_bus_get(parent);
slot->number = slot_nr;
slot->kobj.kset = pci_slots_kset;
@@ -268,6 +269,7 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
slot_name = make_slot_name(name);
if (!slot_name) {
err = -ENOMEM;
+ pci_bus_put(slot->bus);
kfree(slot);
goto err;
}
--
2.20.1
From: Lukas Wunner <lukas(a)wunner.de>
stable inclusion
from stable-v6.6.64
commit e5d5c04aac71bf1476dc44b56f2206a4c2facca8
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEAF8
CVE: CVE-2024-53194
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
commit c7acef99642b763ba585f4a43af999fcdbcc3dc4 upstream.
Dennis reports a boot crash on recent Lenovo laptops with a USB4 dock.
Since commit 0fc70886569c ("thunderbolt: Reset USB4 v2 host router") and
commit 59a54c5f3dbd ("thunderbolt: Reset topology created by the boot
firmware"), USB4 v2 and v1 Host Routers are reset on probe of the
thunderbolt driver.
The reset clears the Presence Detect State and Data Link Layer Link Active
bits at the USB4 Host Router's Root Port and thus causes hot removal of the
dock.
The crash occurs when pciehp is unbound from one of the dock's Downstream
Ports: pciehp creates a pci_slot on bind and destroys it on unbind. The
pci_slot contains a pointer to the pci_bus below the Downstream Port, but
a reference on that pci_bus is never acquired. The pci_bus is destroyed
before the pci_slot, so a use-after-free ensues when pci_slot_release()
accesses slot->bus.
In principle this should not happen because pci_stop_bus_device() unbinds
pciehp (and therefore destroys the pci_slot) before the pci_bus is
destroyed by pci_remove_bus_device().
However the stacktrace provided by Dennis shows that pciehp is unbound from
pci_remove_bus_device() instead of pci_stop_bus_device(). To understand
the significance of this, one needs to know that the PCI core uses a two
step process to remove a portion of the hierarchy: It first unbinds all
drivers in the sub-hierarchy in pci_stop_bus_device() and then actually
removes the devices in pci_remove_bus_device(). There is no precaution to
prevent driver binding in-between pci_stop_bus_device() and
pci_remove_bus_device().
In Dennis' case, it seems removal of the hierarchy by pciehp races with
driver binding by pci_bus_add_devices(). pciehp is bound to the
Downstream Port after pci_stop_bus_device() has run, so it is unbound by
pci_remove_bus_device() instead of pci_stop_bus_device(). Because the
pci_bus has already been destroyed at that point, accesses to it result in
a use-after-free.
One might conclude that driver binding needs to be prevented after
pci_stop_bus_device() has run. However it seems risky that pci_slot points
to pci_bus without holding a reference. Solely relying on correct ordering
of driver unbind versus pci_bus destruction is certainly not defensive
programming.
If pci_slot has a need to access data in pci_bus, it ought to acquire a
reference. Amend pci_create_slot() accordingly. Dennis reports that the
crash is not reproducible with this change.
Abridged stacktrace:
pcieport 0000:00:07.0: PME: Signaling with IRQ 156
pcieport 0000:00:07.0: pciehp: Slot #12 AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug+ Surprise+ Interlock- NoCompl+ IbPresDis- LLActRep+
pci_bus 0000:20: dev 00, created physical slot 12
pcieport 0000:00:07.0: pciehp: Slot(12): Card not present
...
pcieport 0000:21:02.0: pciehp: pcie_disable_notification: SLOTCTRL d8 write cmd 0
Oops: general protection fault, probably for non-canonical address 0x6b6b6b6b6b6b6b6b: 0000 [#1] PREEMPT SMP NOPTI
CPU: 13 UID: 0 PID: 134 Comm: irq/156-pciehp Not tainted 6.11.0-devel+ #1
RIP: 0010:dev_driver_string+0x12/0x40
pci_destroy_slot
pciehp_remove
pcie_port_remove_service
device_release_driver_internal
bus_remove_device
device_del
device_unregister
remove_iter
device_for_each_child
pcie_portdrv_remove
pci_device_remove
device_release_driver_internal
bus_remove_device
device_del
pci_remove_bus_device (recursive invocation)
pci_remove_bus_device
pciehp_unconfigure_device
pciehp_disable_slot
pciehp_handle_presence_or_link_change
pciehp_ist
Link: https://lore.kernel.org/r/4bfd4c0e976c1776cd08e76603903b338cf25729.17285792…
Reported-by: Dennis Wassenberg <Dennis.Wassenberg(a)secunet.com>
Closes: https://lore.kernel.org/r/6de4b45ff2b32dd91a805ec02ec8ec73ef411bf6.camel@se…
Tested-by: Dennis Wassenberg <Dennis.Wassenberg(a)secunet.com>
Signed-off-by: Lukas Wunner <lukas(a)wunner.de>
Signed-off-by: Bjorn Helgaas <bhelgaas(a)google.com>
Reviewed-by: Mika Westerberg <mika.westerberg(a)linux.intel.com>
Cc: stable(a)vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: Xiongfeng Wang <wangxiongfeng2(a)huawei.com>
---
drivers/pci/slot.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
index 0f87cade10f7..ed645c7a4e4b 100644
--- a/drivers/pci/slot.c
+++ b/drivers/pci/slot.c
@@ -79,6 +79,7 @@ static void pci_slot_release(struct kobject *kobj)
up_read(&pci_bus_sem);
list_del(&slot->list);
+ pci_bus_put(slot->bus);
kfree(slot);
}
@@ -261,7 +262,7 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
goto err;
}
- slot->bus = parent;
+ slot->bus = pci_bus_get(parent);
slot->number = slot_nr;
slot->kobj.kset = pci_slots_kset;
@@ -269,6 +270,7 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
slot_name = make_slot_name(name);
if (!slot_name) {
err = -ENOMEM;
+ pci_bus_put(slot->bus);
kfree(slot);
goto err;
}
--
2.20.1