{ "dataType": "CVE_RECORD", "dataVersion": "5.2", "cveMetadata": { "cveId": "CVE-2025-21965", "assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67", "state": "PUBLISHED", "assignerShortName": "Linux", "dateReserved": "2024-12-29T08:45:45.796Z", "datePublished": "2025-04-01T15:47:01.129Z", "dateUpdated": "2026-08-05T11:55:41.135Z" }, "containers": { "cna": { "providerMetadata": { "orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67", "shortName": "Linux", "dateUpdated": "2026-08-05T11:55:41.135Z" }, "descriptions": [ { "lang": "en", "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nsched_ext: Validate prev_cpu in scx_bpf_select_cpu_dfl()\n\nIf a BPF scheduler provides an invalid CPU (outside the nr_cpu_ids\nrange) as prev_cpu to scx_bpf_select_cpu_dfl() it can cause a kernel\ncrash.\n\nTo prevent this, validate prev_cpu in scx_bpf_select_cpu_dfl() and\ntrigger an scx error if an invalid CPU is specified." } ], "metrics": [ { "cvssV3_1": { "version": "3.1", "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "baseScore": 7.8, "baseSeverity": "HIGH" }, "scenarios": [ { "lang": "en", "value": "AV:L - The vulnerable kfunc is only reachable from a sched_ext BPF scheduler attached via the bpf() syscall and struct_ops link, executed in local task-wakeup context. No remote or adjacent peer supplies data to this path, matching the guidance that BPF/scheduler bugs are Local.\nAC:L - The attacker directly supplies the out-of-range prev_cpu as a plain scalar argument to scx_bpf_select_cpu_dfl(); the BPF verifier does not range-check kfunc scalar arguments, so the OOB access is fully deterministic. There is no race, no memory-layout dependency, and no state outside the attacker's control.\nPR:L - Loading the sched_ext struct_ops program nominally requires CAP_BPF/CAP_PERFMON, but BPF token delegation (bpffs delegate_progs=struct_ops) grants exactly these inside a user namespace, and sched_ext's pervasive ops_cpu_valid()/scx_kf_allowed() validation exists precisely because the BPF scheduler is treated as an untrusted, containable component whose bad input must not corrupt the kernel. This matches the scoring of the directly analogous CVE-2025-38012 in the same subsystem.\nUI:N - The invalid CPU is passed during ordinary task wakeup processing driven by the attacker's own workload; no victim action such as mounting a filesystem or opening a file is required.\nS:U - The out-of-bounds reads and the bit-clear write both land in kernel memory within the same security authority as the running kernel. No VM, IOMMU, or sandbox boundary is crossed.\nC:H - per_cpu(sd_numa/sd_llc/sd_llc_id, prev_cpu) and cpu_smt_mask(prev_cpu) index __per_cpu_offset[] with an attacker-chosen s32, yielding an out-of-bounds read that produces a wild base pointer which is then dereferenced by cpumask_intersects()/cpumask_andnot(). This is an unbounded arbitrary kernel read whose results steer subsequent behavior.\nI:H - cpumask_test_and_clear_cpu(prev_cpu, idle_masks.cpu) resolves to test_and_clear_bit() with no effective bounds check outside CONFIG_DEBUG_PER_CPU_MAPS, giving an out-of-bounds write that clears any single bit at an attacker-chosen offset (up to ~512 MB via the int-to-unsigned conversion), plus __cpumask_clear_cpu()/cpumask_andnot() writes driven by the wild sibling mask. A controlled bit-clear primitive over adjacent heap/percpu structures is exploitable for privilege escalation and control-flow corruption.\nA:H - The commit states outright that an invalid prev_cpu \"can cause a kernel crash\" — the wild per-cpu pointer dereference and the far out-of-bounds bit access reliably oops or panic the kernel. Any resulting corruption of the scheduler's idle masks additionally destabilizes CPU selection system-wide." } ] } ], "affected": [ { "product": "Linux", "vendor": "Linux", "defaultStatus": "unaffected", "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git", "programFiles": [ "kernel/sched/ext.c" ], "versions": [ { "version": "f0e1a0643a59bf1f922fa209cec86a170b784f3f", "lessThan": "752b56bb76e2471197d25d6948d85753043b10da", "status": "affected", "versionType": "git" }, { "version": "f0e1a0643a59bf1f922fa209cec86a170b784f3f", "lessThan": "515680e76c536dd4aa8e2b5d674b0d441baddf5b", "status": "affected", "versionType": "git" }, { "version": "f0e1a0643a59bf1f922fa209cec86a170b784f3f", "lessThan": "9360dfe4cbd62ff1eb8217b815964931523b75b3", "status": "affected", "versionType": "git" } ] }, { "product": "Linux", "vendor": "Linux", "defaultStatus": "affected", "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git", "programFiles": [ "kernel/sched/ext.c" ], "versions": [ { "version": "6.12", "status": "affected" }, { "version": "0", "lessThan": "6.12", "status": "unaffected", "versionType": "semver" }, { "version": "6.12.20", "lessThanOrEqual": "6.12.*", "status": "unaffected", "versionType": "semver" }, { "version": "6.13.8", "lessThanOrEqual": "6.13.*", "status": "unaffected", "versionType": "semver" }, { "version": "6.14", "lessThanOrEqual": "*", "status": "unaffected", "versionType": "original_commit_for_fix" } ] } ], "cpeApplicability": [ { "nodes": [ { "operator": "OR", "negate": false, "cpeMatch": [ { "vulnerable": true, "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "versionStartIncluding": "6.12", "versionEndExcluding": "6.12.20" }, { "vulnerable": true, "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "versionStartIncluding": "6.12", "versionEndExcluding": "6.13.8" }, { "vulnerable": true, "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "versionStartIncluding": "6.12", "versionEndExcluding": "6.14" } ] } ] } ], "references": [ { "url": "https://git.kernel.org/stable/c/752b56bb76e2471197d25d6948d85753043b10da" }, { "url": "https://git.kernel.org/stable/c/515680e76c536dd4aa8e2b5d674b0d441baddf5b" }, { "url": "https://git.kernel.org/stable/c/9360dfe4cbd62ff1eb8217b815964931523b75b3" } ], "title": "sched_ext: Validate prev_cpu in scx_bpf_select_cpu_dfl()", "x_generator": { "engine": "bippy-1.2.0" } } } }