From ff917923f4fb9c83717ba135ee47d7e4c1567bb7 Mon Sep 17 00:00:00 2001 From: Muhammad Bilal Date: Tue, 28 Jul 2026 17:54:55 +0500 Subject: staging: rtl8723bs: fix OOB read in rtw_action_frame_parse() rtw_action_frame_parse() takes a frame_len parameter but never actually checks it before indexing into the frame body: const u8 *frame_body = frame + sizeof(struct ieee80211_hdr_3addr); ... c = frame_body[0]; ... a = frame_body[1]; frame_body already points 24 bytes (sizeof(struct ieee80211_hdr_3addr)) into frame, so reading frame_body[0] and frame_body[1] requires frame_len >= 26. A management action frame shorter than that (e.g. exactly 24 bytes, the minimum a malicious peer can send) causes a 1-2 byte out-of-bounds read. This is reachable from rtw_cfg80211_monitor_if_xmit_entry() and cfg80211_rtw_mgmt_tx() in ioctl_cfg80211.c, both of which pass attacker/user-influenced frame buffers and lengths straight through. Add the missing length check before frame_body is dereferenced. Fixes: 554c0a3abf216 ("staging: Add rtl8723bs sdio wifi driver") Cc: stable@vger.kernel.org Signed-off-by: Muhammad Bilal Link: https://patch.msgid.link/20260728125456.32359-3-meatuni001@gmail.com Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/sample.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 tools/perf/util/sample.c (limited to 'tools/perf/util/sample.c') diff --git a/tools/perf/util/sample.c b/tools/perf/util/sample.c new file mode 100644 index 000000000..bccc19e2a --- /dev/null +++ b/tools/perf/util/sample.c @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include "sample.h" + +#include +#include + +#include +#include + +#include "../../arch/x86/include/asm/insn.h" +#include "debug.h" +#include "evsel.h" +#include "thread.h" + +#ifndef EM_CSKY +#define EM_CSKY 252 +#endif +#ifndef EM_LOONGARCH +#define EM_LOONGARCH 258 +#endif + +void perf_sample__init(struct perf_sample *sample, bool all) +{ + if (all) { + memset(sample, 0, sizeof(*sample)); + } else { + sample->evsel = NULL; + sample->user_regs = NULL; + sample->intr_regs = NULL; + sample->merged_callchain = false; + sample->callchain = NULL; + } +} + +void perf_sample__exit(struct perf_sample *sample) +{ + evsel__put(sample->evsel); + sample->evsel = NULL; + zfree(&sample->user_regs); + zfree(&sample->intr_regs); + if (sample->merged_callchain) { + zfree(&sample->callchain); + sample->merged_callchain = false; + } +} + +struct regs_dump *perf_sample__user_regs(struct perf_sample *sample) +{ + if (!sample->user_regs) { + sample->user_regs = zalloc(sizeof(*sample->user_regs)); + if (!sample->user_regs) + pr_err("Failure to allocate sample user_regs"); + } + return sample->user_regs; +} + + +struct regs_dump *perf_sample__intr_regs(struct perf_sample *sample) +{ + if (!sample->intr_regs) { + sample->intr_regs = zalloc(sizeof(*sample->intr_regs)); + if (!sample->intr_regs) + pr_err("Failure to allocate sample intr_regs"); + } + return sample->intr_regs; +} + +static int elf_machine_max_instruction_length(uint16_t e_machine) +{ + switch (e_machine) { + /* Fixed 4-byte (32-bit) architectures */ + case EM_AARCH64: + case EM_PPC: + case EM_PPC64: + case EM_MIPS: + case EM_SPARC: + case EM_SPARCV9: + case EM_ALPHA: + case EM_LOONGARCH: + case EM_PARISC: + case EM_SH: + return 4; + + /* Variable length or mixed-mode architectures */ + case EM_ARM: /* Variable due to Thumb/Thumb-2 */ + case EM_RISCV: /* Variable due to Compressed (C) extension */ + case EM_CSKY: /* Variable (16 or 32 bit) */ + case EM_ARC: /* Variable (ARCompact) */ + return 4; + case EM_S390: /* Variable (2, 4, or 6 bytes) */ + return 6; + case EM_68K: + return 10; + case EM_386: + case EM_X86_64: + return 15; + case EM_XTENSA: /* Variable (FLIX) */ + return 16; + default: + return MAX_INSN; + } +} + +void perf_sample__fetch_insn(struct perf_sample *sample, + struct thread *thread, + struct machine *machine) +{ + int ret, len; + bool is64bit = false; + uint16_t e_machine; + + if (!sample->ip || sample->insn_len != 0) + return; + + e_machine = thread__e_machine(thread, machine, /*e_flags=*/NULL); + len = elf_machine_max_instruction_length(e_machine); + len = thread__memcpy(thread, machine, sample->insn, + sample->ip, len, + &is64bit); + if (len <= 0) + return; + + sample->insn_len = len; + + if (e_machine == EM_386 || e_machine == EM_X86_64) { + /* Refine the x86 instruction length with the decoder. */ + struct insn insn; + + ret = insn_decode(&insn, sample->insn, len, + is64bit ? INSN_MODE_64 : INSN_MODE_32); + if (ret >= 0 && insn.length <= len) + sample->insn_len = insn.length; + } +} -- cgit v1.3.1