← Our Research

ASI-2026-0014

tOS Syscall Layer — Unvalidated Ring3 Pointers Allow Arbitrary Kernel Memory Read/Write

HIGH FIXED CVSS: 8.4 Published: 2026-08-14

Summary

syscall_handler() in syscall.c ignores the page tables' PTE_USER bit entirely once execution reaches ring0, meaning nothing in the paging setup stops the kernel from dereferencing any address a ring3 .t program passes as a syscall argument. SYS_INFLATE, SYS_GFX_BLIT, and SYS_AUDIO_SUBMIT each took a pointer (or a pointer embedded in an argument struct) straight from ring3 without checking it actually belonged to the calling program's own memory before using it. SYS_INFLATE's args->out is the raw-DEFLATE decompression output target: with no validation, a ring3 program could point it at arbitrary kernel memory (page tables, function pointers, the syscall dispatch table) and supply crafted compressed input it fully controls, giving an arbitrary kernel-memory write of fully attacker-chosen content from a single syscall — a direct path to local privilege escalation. SYS_GFX_BLIT's args->pixels (bulk-copied into the visible linear framebuffer) and SYS_AUDIO_SUBMIT's source buffer (copied into an audio DMA buffer) are read-side equivalents: pointed at kernel memory, their contents become observable via the screen or, in principle, audio output, an information-disclosure primitive of arbitrary kernel memory. All three syscalls are reachable by any unprivileged ring3 .t executable with no special permissions.

How We Found It

While automatically scanning for the same 'no kernel/user memory isolation' architectural gap first found in ASI-2026-0001, ArtficalAI tAI 4.2 found that the issue was not yet fully closed and persisted concretely at the syscall layer itself. Reviewing syscall_handler() in syscall.c, it found that the PTE_USER bit in the page tables is entirely ignored once ring0 is reached, and that this turned into a concrete exploitation surface in SYS_INFLATE, SYS_GFX_BLIT, and SYS_AUDIO_SUBMIT.

Technical Detail

syscall_handler() ignores the page tables' PTE_USER bit entirely once execution reaches ring0, meaning nothing in the paging setup stops the kernel from dereferencing any address a ring3 .t program passes as a syscall argument. SYS_INFLATE, SYS_GFX_BLIT, and SYS_AUDIO_SUBMIT each took a pointer straight from ring3 without checking it belonged to the calling program's own memory. SYS_INFLATE's args->out is the raw-DEFLATE decompression output target: pointed at arbitrary kernel memory with attacker-controlled compressed input, this gives an arbitrary kernel-memory write of fully attacker-chosen content from a single syscall. SYS_GFX_BLIT's args->pixels and SYS_AUDIO_SUBMIT's source buffer are read-side equivalents, providing an information-disclosure primitive of arbitrary kernel memory via the screen or audio output.

Attack Scenario

An attacker writes an ordinary ring3 .t program requiring no special permissions. When calling SYS_INFLATE, it sets args->out to point at an arbitrary kernel address (e.g. the syscall dispatch table) and supplies fully attacker-controlled crafted compressed input. A single syscall call writes attacker-chosen content directly into kernel memory — a direct path to local privilege escalation. Similarly, passing a source buffer pointing at kernel memory to SYS_GFX_BLIT or SYS_AUDIO_SUBMIT lets the attacker leak arbitrary kernel memory by observing its contents on screen or through audio output.

Root Cause

syscall_handler() ignores the page tables' PTE_USER bit entirely once execution reaches ring0. SYS_INFLATE, SYS_GFX_BLIT, and SYS_AUDIO_SUBMIT each took a pointer straight from ring3 without checking it actually belonged to the calling program's own memory before using it.

Fix

Adds user_range_ok(ptr, len) to syscall.c, which rejects zero-length and integer-overflowing ranges and requires the entire [ptr, ptr+len) range to fall within the calling program's own code/data region ([USER_CODE_BASE, USER_CODE_BASE+USER_CODE_MAX_SIZE)) or its own stack ([USER_STACK_TOP - USER_STACK_PAGES*4096, USER_STACK_TOP)). Applied to the struct-pointer argument itself and every pointer field inside it for all three affected syscalls before any of them are dereferenced.

Affected Platforms

Artfical tOS 0.9.156 (< 90bdc6a)

Weakness Type

CWE-787, CWE-125, CWE-284

Discovered By

ArtficalAI tAI 4.2

References