Relocation r_offset never bounds-checked against target section size (OOB / wild kernel write)
| Field | Value |
|---|---|
| ID | DF-0042 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:H |
| CWE | CWE-787 Out-of-bounds Write |
| File | sys/kern/link_elf_obj.c |
| Lines | 940-953 (findbase), 975-1020 (relocate_file), 1246-1278 (reloc_local); sink in sys/cpu/x86_64/misc/elf_machdep.c:90,108,127,164,171 |
| Area | kern |
| Confidence | likely |
| Discovered | 2026-06-29 |
| Reported | pending |
Summary
relocate_file and link_elf_obj_reloc_local iterate attacker-supplied
SHT_REL/SHT_RELA entries and dispatch each to elf_reloc/elf_reloc_local
with only the section base (findbase). The relocation's r_offset
(Elf64_Addr) is never validated to lie within the target section's
[0, size) extent. The arch helper computes where = relocbase + r_offset and
writes *where (sys/cpu/x86_64/misc/elf_machdep.c:90,108,127,164,171), so a
crafted r_offset yields an out-of-bounds / wild write into kernel memory (or a
page-fault panic).
Root cause
sys/kern/link_elf_obj.c:940-953 โ findbase returns only the section start
address (no size); ef->reltab[i] carries no size, and the per-relocation
r_offset is never compared to the matching progtab[].size:
static Elf_Addr findbase(elf_file_t ef, int sec) {
...
base = (Elf_Addr)ef->progtab[i].addr; /* size available here but not returned */
...
}
...
base = findbase(ef, ef->reltab[i].sec); /* :975 -- base only, no size */
...
elf_reloc(... rel ...); /* r_offset unchecked */
elf_machdep.c:90: where = (Elf_Addr *)(relocbase + rel->r_offset); then
:127/:164/:171: *where = val;.
Threat model & preconditions
- Attacker position: root via
kldload(2)(SYSCAP_NOKLD, securelevel 0). Root already owns the kernel (a valid.ko'sSYSINITruns in kernel context), so this grants no new privilege โ it is robustness/defense-in- depth (matters for verified-boot / securelevel / restricted-module scenarios). - Privileges gained or impact: wild write of a symbol-derived value to an attacker-chosen kernel address (state corruption / control-flow-hijack primitive), or page-fault panic (local DoS). Highest-impact class of the three link_elf_obj findings (write, not read) but root-only.
- Reachability:
kldload(2)of a crafted.kowith a relocation whoser_offsetis outside its target section.
Recommended fix
Have findbase return the section size too, and skip relocations whose
r_offset is outside [0, size):
@@ -941
-static Elf_Addr findbase(elf_file_t ef, int sec)
+static Elf_Addr findbase(elf_file_t ef, int sec, Elf_Off *sizep)
{
...
if (sec == ef->progtab[i].sec) {
base = (Elf_Addr)ef->progtab[i].addr;
+ if (sizep) *sizep = ef->progtab[i].size;
break;
@@ -975
- base = findbase(ef, ef->reltab[i].sec);
+ Elf_Off secsize = 0;
+ base = findbase(ef, ef->reltab[i].sec, &secsize);
...
- for ( ; rel < rellim; rel++) {
+ for ( ; rel < rellim; rel++) {
+ if (secsize == 0 || rel->r_offset >= secsize)
+ continue;
(apply the analogous r_offset >= secsize guard in the RELA loop :1005-1020
and both link_elf_obj_reloc_local loops :1246,:1268).
References
sys/kern/link_elf_obj.c:940-953,975-1020โ nor_offsetbound.sys/cpu/x86_64/misc/elf_machdep.c:90,108,127,164,171โ the*wheresink.- CWE-787 Out-of-bounds Write.
Timeline
- 2026-06-29 Discovered during automated file-by-file audit of
sys/kern/link_elf_obj.c. - pending Reported to DragonFlyBSD security contact.