Hello,
Richard Henderson <[email protected]> writes:
> Based on Peter's tags/pull-target-arm-20250828.
> Tree: https://gitlab.com/rth7680/qemu/-/tree/tgt-arm-gcs
>
> This includes the prerequisite features, ATS1A and S1PIE, and
> not a prerequisite but closely related, S2PIE.
>
> This passes the linux kselftests for gcs, with a 48-bit VA.
> I also include a few smoke tests in tests/tcg/.
>
>
> This includes a best-effort linux-user implementation. Since we
> don't have softmmu in user-only (yet), gcs stack pages get normal
> read/write access. This means we cannot write-protect the pages
> in the same way the system implementation can. But all of the
> other parts of GCS work fine, which is good enough for testing.
I tried using GCS in current QEMU trunk (commit d8a9d97317d0 "Merge tag
'pull-target-arm-20260226' of https://gitlab.com/pm215/qemu into
staging"), but I get this kernel oops with a simple program (attached)
that just tries to enable GCS using prctl:
[ 226.334899] Unable to handle kernel paging request at virtual address
fffff1ffc36c8008
[ 226.335033] Mem abort info:
[ 226.335088] ESR = 0x0000000096000004
[ 226.335117] EC = 0x25: DABT (current EL), IL = 32 bits
[ 226.335137] SET = 0, FnV = 0
[ 226.335153] EA = 0, S1PTW = 0
[ 226.335172] FSC = 0x04: level 0 translation fault
[ 226.335192] Data abort info:
[ 226.335208] ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000
[ 226.335224] CM = 0, WnR = 0, TnD = 0, TagAccess = 0
[ 226.335241] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[ 226.335284] swapper pgtable: 4k pages, 52-bit VAs, pgdp=00000000dbe9b000
[ 226.335306] [fffff1ffc36c8008] pgd=10000000dcfcd003, p4d=0000000000000000
[ 226.335475] Internal error: Oops: 0000000096000004 [#1] SMP
[ 226.336917] Modules linked in: tpm_tis tpm_tis_core qrtr sha256 cfg80211
rfkill fuse dm_mod drm backlight ipv6 btrfs blake2b libblake2b xor xor_neon
raid6_pq zstd_compress sm3_ce
[ 226.337746] CPU: 0 UID: 1000 PID: 950 Comm: simple-gcs Tainted: G M
6.19.0 #2 PREEMPT
[ 226.337963] Tainted: [M]=MACHINE_CHECK
[ 226.338035] Hardware name: QEMU QEMU Virtual Machine, BIOS
edk2-stable202408-prebuilt.qemu.org 08/13/2024
[ 226.338281] pstate: 21402005 (nzCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--)
[ 226.338411] pc : __get_user_pages+0x4a4/0xc0c
[ 226.338889] lr : __get_user_pages+0x3fc/0xc0c
[ 226.338977] sp : ffff800080e236f0
[ 226.339042] x29: ffff800080e236f0 x28: fff00000c3c21e80 x27: 0000000000000000
[ 226.339203] x26: 0000000000000000 x25: fff00000c1a988c8 x24: 0000000000000000
[ 226.339327] x23: 0000ffffa3200000 x22: 000000000000000e x21: 0000000000000000
[ 226.339453] x20: fff00000c80bc300 x19: 0008000000000000 x18: 0000000000000000
[ 226.339573] x17: 0000000000000000 x16: ffff95c0712386b8 x15: 0000ffffa363bfff
[ 226.339699] x14: 0000000000000000 x13: 1ffe000018271e21 x12: fff00000c138f10c
[ 226.339824] x11: fff00000c138f100 x10: 0000000000000001 x9 : 0000000000000001
[ 226.339962] x8 : 00c800011b200f41 x7 : fff00000c138f108 x6 : 00000000000008c8
[ 226.340086] x5 : fffff1ffc36c8000 x4 : ffffc1ffc0000000 x3 : 0000000000000000
[ 226.340207] x2 : 0000000000104a00 x1 : 0040000000000841 x0 : 0040000000000800
[ 226.340392] Call trace:
[ 226.340554] __get_user_pages+0x4a4/0xc0c (P)
[ 226.340701] get_dump_page+0xe4/0x150
[ 226.340797] dump_user_range+0x64/0x2e8
[ 226.340886] elf_core_dump+0xbf8/0xe10
[ 226.340955] vfs_coredump+0xea0/0x1c80
[ 226.341026] get_signal+0x644/0x82c
[ 226.341097] arch_do_signal_or_restart+0x118/0x3c4
[ 226.341184] exit_to_user_mode_loop+0x104/0x16c
[ 226.341269] el0_da+0x8c/0x90
[ 226.341344] el0t_64_sync_handler+0xd0/0xe4
[ 226.341419] el0t_64_sync+0x198/0x19c
[ 226.341626] Code: eb00003f 540029a0 924d0113 b6982d88 (f94004a4)
[ 226.341893] ---[ end trace 0000000000000000 ]---
[ 226.851631] note: simple-gcs[950] exited with preempt_count 1
This is using Linux kernel v6.19 built with defconfig.
I also tried the QEMU commit corresponding to the last patch in this
series (af0bd678df72 "tests/tcg/aarch64: Add gcsss") but had the same
result.
The same binaries work as expected using Arm FVP, so it seems to be
something in QEMU.
The command line I used was:
$QEMU_PREFIX/bin/qemu-system-aarch64 \
-M virt \
-cpu max \
-m 4g \
-drive
if=none,file=$HOME/VMs/ubuntu-25.10-aarch64.img,id=hd1,format=raw,cache=writeback,discard=on
\
-device virtio-blk-device,drive=hd1 \
-netdev user,id=mynet0,hostfwd=tcp::8222-:22 -device
virtio-net-pci,netdev=mynet0 \
-bios $QEMU_PREFIX/share/qemu/edk2-aarch64-code.fd \
-nographic
--
Thiago
#include <stdlib.h>
#include <sys/syscall.h>
#include <linux/prctl.h>
#ifndef PR_SET_SHADOW_STACK_STATUS
#define PR_SET_SHADOW_STACK_STATUS 75
#define PR_SHADOW_STACK_ENABLE (1UL << 0)
#endif
/* We need to use a macro to call prctl because after GCS is enabled, it's not
possible to return from the function which enabled it. This is because the
return address of the calling function isn't on the GCS. */
#define my_syscall2(num, arg1, arg2) \
({ \
register long _num __asm__("x8") = (num); \
register long _arg1 __asm__("x0") = (long)(arg1); \
register long _arg2 __asm__("x1") = (long)(arg2); \
register long _arg3 __asm__("x2") = 0; \
register long _arg4 __asm__("x3") = 0; \
register long _arg5 __asm__("x4") = 0; \
\
asm volatile ("svc #0\n" \
: "=r"(_arg1) \
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
"r"(_arg5), "r"(_num) \
: "memory", "cc"); \
_arg1; \
})
int main (void)
{
int ret;
ret = my_syscall2 (__NR_prctl, PR_SET_SHADOW_STACK_STATUS,
PR_SHADOW_STACK_ENABLE);
/* Don't return from main to avoid segmentation fault. */
exit (ret);
}