Skip to content
/ zig Public
forked from ziglang/zig

Commit

Permalink
std.os.linux: Add unwinding protection in clone() implementations.
Browse files Browse the repository at this point in the history
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: llvm/llvm-project#115891
  • Loading branch information
alexrp committed Dec 6, 2024
1 parent 9f4c0d9 commit 8c750e3
Show file tree
Hide file tree
Showing 14 changed files with 98 additions and 44 deletions.
7 changes: 6 additions & 1 deletion lib/std/os/linux/aarch64.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 8 additions & 3 deletions lib/std/os/linux/arm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
}
Expand Down
4 changes: 4 additions & 0 deletions lib/std/os/linux/hexagon.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
\\
Expand Down
4 changes: 4 additions & 0 deletions lib/std/os/linux/loongarch64.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions lib/std/os/linux/mips.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions lib/std/os/linux/mips64.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
40 changes: 20 additions & 20 deletions lib/std/os/linux/powerpc.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
);
}

Expand Down
7 changes: 6 additions & 1 deletion lib/std/os/linux/powerpc64.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion lib/std/os/linux/riscv32.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
\\
Expand Down
6 changes: 5 additions & 1 deletion lib/std/os/linux/riscv64.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
\\
Expand Down
7 changes: 6 additions & 1 deletion lib/std/os/linux/s390x.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 13 additions & 8 deletions lib/std/os/linux/sparc64.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
}

Expand Down
19 changes: 11 additions & 8 deletions lib/std/os/linux/x86.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
}

Expand Down
2 changes: 2 additions & 0 deletions lib/std/os/linux/x86_64.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 8c750e3

Please sign in to comment.