diff options
| author | Alex Rønne Petersen <alex@alexrp.com> | 2024-11-04 18:30:36 +0100 |
|---|---|---|
| committer | Alex Rønne Petersen <alex@alexrp.com> | 2024-12-11 00:10:17 +0100 |
| commit | da018f972619377e8c044c5c27ebf231be262bb3 (patch) | |
| tree | 00faa647aca74f648677b74828301ab0f8c14fc0 /lib/std | |
| parent | 7d0087707634028308d3a870883249bfa59d94b8 (diff) | |
| download | zig-da018f972619377e8c044c5c27ebf231be262bb3.tar.gz zig-da018f972619377e8c044c5c27ebf231be262bb3.zip | |
std.os.linux: Add unwinding protection in clone() implementations.
Whatever was in the frame pointer register prior to clone() will no longer be
valid in the child process, so zero it to protect FP-based unwinders. Similarly,
mark the link register as undefined to protect DWARF-based unwinders.
This is only zeroing the frame pointer(s) on Arm/Thumb because of an LLVM
assembler bug: https://github.com/llvm/llvm-project/issues/115891
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/os/linux/aarch64.zig | 7 | ||||
| -rw-r--r-- | lib/std/os/linux/arm.zig | 11 | ||||
| -rw-r--r-- | lib/std/os/linux/hexagon.zig | 4 | ||||
| -rw-r--r-- | lib/std/os/linux/loongarch64.zig | 4 | ||||
| -rw-r--r-- | lib/std/os/linux/mips.zig | 4 | ||||
| -rw-r--r-- | lib/std/os/linux/mips64.zig | 4 | ||||
| -rw-r--r-- | lib/std/os/linux/powerpc.zig | 40 | ||||
| -rw-r--r-- | lib/std/os/linux/powerpc64.zig | 7 | ||||
| -rw-r--r-- | lib/std/os/linux/riscv32.zig | 6 | ||||
| -rw-r--r-- | lib/std/os/linux/riscv64.zig | 6 | ||||
| -rw-r--r-- | lib/std/os/linux/s390x.zig | 7 | ||||
| -rw-r--r-- | lib/std/os/linux/sparc64.zig | 21 | ||||
| -rw-r--r-- | lib/std/os/linux/x86.zig | 19 | ||||
| -rw-r--r-- | lib/std/os/linux/x86_64.zig | 2 |
14 files changed, 98 insertions, 44 deletions
diff --git a/lib/std/os/linux/aarch64.zig b/lib/std/os/linux/aarch64.zig index 9248360ae9..db304a3a33 100644 --- a/lib/std/os/linux/aarch64.zig +++ b/lib/std/os/linux/aarch64.zig @@ -120,8 +120,13 @@ pub fn clone() callconv(.Naked) usize { \\ cbz x0,1f \\ // parent \\ ret + \\ \\ // child - \\1: ldp x1,x0,[sp],#16 + \\1: .cfi_undefined lr + \\ mov fp, 0 + \\ mov lr, 0 + \\ + \\ ldp x1,x0,[sp],#16 \\ blr x1 \\ mov x8,#93 // SYS_exit \\ svc #0 diff --git a/lib/std/os/linux/arm.zig b/lib/std/os/linux/arm.zig index 1d22b8c3db..e9263b5cea 100644 --- a/lib/std/os/linux/arm.zig +++ b/lib/std/os/linux/arm.zig @@ -120,11 +120,16 @@ pub fn clone() callconv(.Naked) usize { \\ ldmfd sp!,{r4,r5,r6,r7} \\ bx lr \\ - \\1: mov r0,r6 + \\ // https://github.com/llvm/llvm-project/issues/115891 + \\1: mov r7, #0 + \\ mov r11, #0 + \\ mov lr, #0 + \\ + \\ mov r0,r6 \\ bl 3f - \\2: mov r7,#1 // SYS_exit + \\ mov r7,#1 // SYS_exit \\ svc 0 - \\ b 2b + \\ \\3: bx r5 ); } diff --git a/lib/std/os/linux/hexagon.zig b/lib/std/os/linux/hexagon.zig index e9bf9ab57c..0839ea8297 100644 --- a/lib/std/os/linux/hexagon.zig +++ b/lib/std/os/linux/hexagon.zig @@ -118,6 +118,10 @@ pub fn clone() callconv(.Naked) usize { \\ p0 = cmp.eq(r0, #0) \\ if (!p0) dealloc_return \\ + \\ .cfi_undefined r31 + \\ r30 = #0 + \\ r31 = #0 + \\ \\ r0 = r10 \\ callr r11 \\ diff --git a/lib/std/os/linux/loongarch64.zig b/lib/std/os/linux/loongarch64.zig index def3915494..b52f1d10b1 100644 --- a/lib/std/os/linux/loongarch64.zig +++ b/lib/std/os/linux/loongarch64.zig @@ -121,6 +121,10 @@ pub fn clone() callconv(.Naked) usize { \\ beqz $a0, 1f # whether child process \\ jirl $zero, $ra, 0 # parent process return \\1: + \\ .cfi_undefined 1 + \\ move $fp, $zero + \\ move $ra, $zero + \\ \\ ld.d $t8, $sp, 0 # function pointer \\ ld.d $a0, $sp, 8 # argument pointer \\ jirl $ra, $t8, 0 # call the user's function diff --git a/lib/std/os/linux/mips.zig b/lib/std/os/linux/mips.zig index e6cb5f7900..5d786ccde7 100644 --- a/lib/std/os/linux/mips.zig +++ b/lib/std/os/linux/mips.zig @@ -231,6 +231,10 @@ pub fn clone() callconv(.Naked) usize { \\ jr $ra \\ nop \\1: + \\ .cfi_undefined $ra + \\ move $fp, $zero + \\ move $ra, $zero + \\ \\ lw $25, 0($sp) \\ lw $4, 4($sp) \\ jalr $25 diff --git a/lib/std/os/linux/mips64.zig b/lib/std/os/linux/mips64.zig index 5e6661eae5..256c911bbe 100644 --- a/lib/std/os/linux/mips64.zig +++ b/lib/std/os/linux/mips64.zig @@ -210,6 +210,10 @@ pub fn clone() callconv(.Naked) usize { \\ jr $ra \\ nop \\1: + \\ .cfi_undefined $ra + \\ move $fp, $zero + \\ move $ra, $zero + \\ \\ ld $25, 0($sp) \\ ld $4, 8($sp) \\ jalr $25 diff --git a/lib/std/os/linux/powerpc.zig b/lib/std/os/linux/powerpc.zig index 7b56b94823..9dde326e1b 100644 --- a/lib/std/os/linux/powerpc.zig +++ b/lib/std/os/linux/powerpc.zig @@ -133,14 +133,14 @@ pub fn clone() callconv(.Naked) usize { // syscall(SYS_clone, flags, stack, ptid, tls, ctid) // 0 3, 4, 5, 6, 7 asm volatile ( - \\ # store non-volatile regs r30, r31 on stack in order to put our + \\ # store non-volatile regs r29, r30 on stack in order to put our \\ # start func and its arg there - \\ stwu 30, -16(1) - \\ stw 31, 4(1) + \\ stwu 29, -16(1) + \\ stw 30, 4(1) \\ - \\ # save r3 (func) into r30, and r6(arg) into r31 - \\ mr 30, 3 - \\ mr 31, 6 + \\ # save r3 (func) into r29, and r6(arg) into r30 + \\ mr 29, 3 + \\ mr 30, 6 \\ \\ # create initial stack frame for new thread \\ clrrwi 4, 4, 4 @@ -167,28 +167,28 @@ pub fn clone() callconv(.Naked) usize { \\ # compare sc result with 0 \\ cmpwi cr7, 3, 0 \\ - \\ # if not 0, jump to end - \\ bne cr7, 2f + \\ # if not 0, restore stack and return + \\ beq cr7, 2f + \\ lwz 29, 0(1) + \\ lwz 30, 4(1) + \\ addi 1, 1, 16 + \\ blr \\ \\ #else: we're the child + \\ 2: + \\ .cfi_undefined lr + \\ li 31, 0 + \\ mtlr 0 + \\ \\ #call funcptr: move arg (d) into r3 - \\ mr 3, 31 - \\ #move r30 (funcptr) into CTR reg - \\ mtctr 30 + \\ mr 3, 30 + \\ #move r29 (funcptr) into CTR reg + \\ mtctr 29 \\ # call CTR reg \\ bctrl \\ # mov SYS_exit into r0 (the exit param is already in r3) \\ li 0, 1 \\ sc - \\ - \\ 2: - \\ - \\ # restore stack - \\ lwz 30, 0(1) - \\ lwz 31, 4(1) - \\ addi 1, 1, 16 - \\ - \\ blr ); } diff --git a/lib/std/os/linux/powerpc64.zig b/lib/std/os/linux/powerpc64.zig index 06b67c17f1..6a1f98a65f 100644 --- a/lib/std/os/linux/powerpc64.zig +++ b/lib/std/os/linux/powerpc64.zig @@ -160,7 +160,12 @@ pub fn clone() callconv(.Naked) usize { \\ cmpwi cr7, 3, 0 \\ bnelr cr7 \\ - \\ # we're the child. call fn(arg) + \\ # we're the child + \\ .cfi_undefined lr + \\ li 31, 0 + \\ mtlr 0 + \\ + \\ # call fn(arg) \\ ld 3, 16(1) \\ ld 12, 8(1) \\ mtctr 12 diff --git a/lib/std/os/linux/riscv32.zig b/lib/std/os/linux/riscv32.zig index 457d7e50b4..dc444a1956 100644 --- a/lib/std/os/linux/riscv32.zig +++ b/lib/std/os/linux/riscv32.zig @@ -120,7 +120,11 @@ pub fn clone() callconv(.Naked) usize { \\ ret \\ \\ # Child - \\1: lw a1, 0(sp) + \\1: .cfi_undefined ra + \\ mv fp, zero + \\ mv ra, zero + \\ + \\ lw a1, 0(sp) \\ lw a0, 4(sp) \\ jalr a1 \\ diff --git a/lib/std/os/linux/riscv64.zig b/lib/std/os/linux/riscv64.zig index e33169c5b1..45ba568c1b 100644 --- a/lib/std/os/linux/riscv64.zig +++ b/lib/std/os/linux/riscv64.zig @@ -120,7 +120,11 @@ pub fn clone() callconv(.Naked) usize { \\ ret \\ \\ # Child - \\1: ld a1, 0(sp) + \\1: .cfi_undefined ra + \\ mv fp, zero + \\ mv ra, zero + \\ + \\ ld a1, 0(sp) \\ ld a0, 8(sp) \\ jalr a1 \\ diff --git a/lib/std/os/linux/s390x.zig b/lib/std/os/linux/s390x.zig index efc48af4ff..8fbe1c930b 100644 --- a/lib/std/os/linux/s390x.zig +++ b/lib/std/os/linux/s390x.zig @@ -133,7 +133,12 @@ pub fn clone() callconv(.Naked) usize { \\ltgr %%r2, %%r2 \\bnzr %%r14 \\ - \\# we're the child. call fn(arg) + \\# we're the child + \\.cfi_undefined %%r14 + \\lghi %%r11, 0 + \\lghi %%r14, 0 + \\ + \\# call fn(arg) \\lg %%r1, 8(%%r15) \\lg %%r2, 16(%%r15) \\basr %%r14, %%r1 diff --git a/lib/std/os/linux/sparc64.zig b/lib/std/os/linux/sparc64.zig index c146ed17cf..d81e6fb40a 100644 --- a/lib/std/os/linux/sparc64.zig +++ b/lib/std/os/linux/sparc64.zig @@ -198,29 +198,34 @@ pub fn clone() callconv(.Naked) usize { \\ mov %%i5, %%o3 \\ ldx [%%fp + 0x8af], %%o4 \\ t 0x6d - \\ bcs,pn %%xcc, 2f + \\ bcs,pn %%xcc, 1f \\ nop \\ # The child pid is returned in o0 while o1 tells if this \\ # process is # the child (=1) or the parent (=0). - \\ brnz %%o1, 1f + \\ brnz %%o1, 2f \\ nop \\ # Parent process, return the child pid \\ mov %%o0, %%i0 \\ ret \\ restore \\1: - \\ # Child process, call func(arg) + \\ # The syscall failed + \\ sub %%g0, %%o0, %%i0 + \\ ret + \\ restore + \\2: + \\ # Child process + \\ .cfi_undefined %%i7 + \\ mov %%g0, %%fp + \\ mov %%g0, %%i7 + \\ + \\ # call func(arg) \\ mov %%g0, %%fp \\ call %%g2 \\ mov %%g3, %%o0 \\ # Exit \\ mov 1, %%g1 // SYS_exit \\ t 0x6d - \\2: - \\ # The syscall failed - \\ sub %%g0, %%o0, %%i0 - \\ ret - \\ restore ); } diff --git a/lib/std/os/linux/x86.zig b/lib/std/os/linux/x86.zig index abcfb99b37..cb746e52a8 100644 --- a/lib/std/os/linux/x86.zig +++ b/lib/std/os/linux/x86.zig @@ -148,19 +148,22 @@ pub fn clone() callconv(.Naked) usize { \\ movl $120,%%eax // SYS_clone \\ int $128 \\ testl %%eax,%%eax - \\ jnz 1f - \\ popl %%eax - \\ xorl %%ebp,%%ebp - \\ calll *%%eax - \\ movl %%eax,%%ebx - \\ movl $1,%%eax // SYS_exit - \\ int $128 - \\1: + \\ jz 1f \\ popl %%edi \\ popl %%esi \\ popl %%ebx \\ popl %%ebp \\ retl + \\ + \\1: + \\ .cfi_undefined %%eip + \\ xorl %%ebp,%%ebp + \\ + \\ popl %%eax + \\ calll *%%eax + \\ movl %%eax,%%ebx + \\ movl $1,%%eax // SYS_exit + \\ int $128 ); } diff --git a/lib/std/os/linux/x86_64.zig b/lib/std/os/linux/x86_64.zig index cef15105ee..44a37345f0 100644 --- a/lib/std/os/linux/x86_64.zig +++ b/lib/std/os/linux/x86_64.zig @@ -116,8 +116,10 @@ pub fn clone() callconv(.Naked) usize { \\ testq %%rax,%%rax \\ jz 1f \\ retq + \\ \\1: .cfi_undefined %%rip \\ xorl %%ebp,%%ebp + \\ \\ popq %%rdi \\ callq *%%r9 \\ movl %%eax,%%edi |
