authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2024-11-04 18:30:36+01:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2024-12-11 00:10:17+01:00
logda018f972619377e8c044c5c27ebf231be262bb3
tree00faa647aca74f648677b74828301ab0f8c14fc0
parent7d0087707634028308d3a870883249bfa59d94b8
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

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

14 files changed, 98 insertions(+), 44 deletions(-)

lib/std/os/linux/aarch64.zig+6-1
...@@ -120,8 +120,13 @@ pub fn clone() callconv(.Naked) usize {...@@ -120,8 +120,13 @@ pub fn clone() callconv(.Naked) usize {
120 \\ cbz x0,1f120 \\ cbz x0,1f
121 \\ // parent121 \\ // parent
122 \\ ret122 \\ ret
123 \\
123 \\ // child124 \\ // child
124 \\1: ldp x1,x0,[sp],#16125 \\1: .cfi_undefined lr
126 \\ mov fp, 0
127 \\ mov lr, 0
128 \\
129 \\ ldp x1,x0,[sp],#16
125 \\ blr x1130 \\ blr x1
126 \\ mov x8,#93 // SYS_exit131 \\ mov x8,#93 // SYS_exit
127 \\ svc #0132 \\ svc #0
lib/std/os/linux/arm.zig+8-3
...@@ -120,11 +120,16 @@ pub fn clone() callconv(.Naked) usize {...@@ -120,11 +120,16 @@ pub fn clone() callconv(.Naked) usize {
120 \\ ldmfd sp!,{r4,r5,r6,r7}120 \\ ldmfd sp!,{r4,r5,r6,r7}
121 \\ bx lr121 \\ bx lr
122 \\122 \\
123 \\1: mov r0,r6123 \\ // https://github.com/llvm/llvm-project/issues/115891
124 \\1: mov r7, #0
125 \\ mov r11, #0
126 \\ mov lr, #0
127 \\
128 \\ mov r0,r6
124 \\ bl 3f129 \\ bl 3f
125 \\2: mov r7,#1 // SYS_exit130 \\ mov r7,#1 // SYS_exit
126 \\ svc 0131 \\ svc 0
127 \\ b 2b132 \\
128 \\3: bx r5133 \\3: bx r5
129 );134 );
130}135}
lib/std/os/linux/hexagon.zig+4
...@@ -118,6 +118,10 @@ pub fn clone() callconv(.Naked) usize {...@@ -118,6 +118,10 @@ pub fn clone() callconv(.Naked) usize {
118 \\ p0 = cmp.eq(r0, #0)118 \\ p0 = cmp.eq(r0, #0)
119 \\ if (!p0) dealloc_return119 \\ if (!p0) dealloc_return
120 \\120 \\
121 \\ .cfi_undefined r31
122 \\ r30 = #0
123 \\ r31 = #0
124 \\
121 \\ r0 = r10125 \\ r0 = r10
122 \\ callr r11126 \\ callr r11
123 \\127 \\
lib/std/os/linux/loongarch64.zig+4
...@@ -121,6 +121,10 @@ pub fn clone() callconv(.Naked) usize {...@@ -121,6 +121,10 @@ pub fn clone() callconv(.Naked) usize {
121 \\ beqz $a0, 1f # whether child process121 \\ beqz $a0, 1f # whether child process
122 \\ jirl $zero, $ra, 0 # parent process return122 \\ jirl $zero, $ra, 0 # parent process return
123 \\1:123 \\1:
124 \\ .cfi_undefined 1
125 \\ move $fp, $zero
126 \\ move $ra, $zero
127 \\
124 \\ ld.d $t8, $sp, 0 # function pointer128 \\ ld.d $t8, $sp, 0 # function pointer
125 \\ ld.d $a0, $sp, 8 # argument pointer129 \\ ld.d $a0, $sp, 8 # argument pointer
126 \\ jirl $ra, $t8, 0 # call the user's function130 \\ jirl $ra, $t8, 0 # call the user's function
lib/std/os/linux/mips.zig+4
...@@ -231,6 +231,10 @@ pub fn clone() callconv(.Naked) usize {...@@ -231,6 +231,10 @@ pub fn clone() callconv(.Naked) usize {
231 \\ jr $ra231 \\ jr $ra
232 \\ nop232 \\ nop
233 \\1:233 \\1:
234 \\ .cfi_undefined $ra
235 \\ move $fp, $zero
236 \\ move $ra, $zero
237 \\
234 \\ lw $25, 0($sp)238 \\ lw $25, 0($sp)
235 \\ lw $4, 4($sp)239 \\ lw $4, 4($sp)
236 \\ jalr $25240 \\ jalr $25
lib/std/os/linux/mips64.zig+4
...@@ -210,6 +210,10 @@ pub fn clone() callconv(.Naked) usize {...@@ -210,6 +210,10 @@ pub fn clone() callconv(.Naked) usize {
210 \\ jr $ra210 \\ jr $ra
211 \\ nop211 \\ nop
212 \\1:212 \\1:
213 \\ .cfi_undefined $ra
214 \\ move $fp, $zero
215 \\ move $ra, $zero
216 \\
213 \\ ld $25, 0($sp)217 \\ ld $25, 0($sp)
214 \\ ld $4, 8($sp)218 \\ ld $4, 8($sp)
215 \\ jalr $25219 \\ jalr $25
lib/std/os/linux/powerpc.zig+20-20
...@@ -133,14 +133,14 @@ pub fn clone() callconv(.Naked) usize {...@@ -133,14 +133,14 @@ pub fn clone() callconv(.Naked) usize {
133 // syscall(SYS_clone, flags, stack, ptid, tls, ctid)133 // syscall(SYS_clone, flags, stack, ptid, tls, ctid)
134 // 0 3, 4, 5, 6, 7134 // 0 3, 4, 5, 6, 7
135 asm volatile (135 asm volatile (
136 \\ # store non-volatile regs r30, r31 on stack in order to put our136 \\ # store non-volatile regs r29, r30 on stack in order to put our
137 \\ # start func and its arg there137 \\ # start func and its arg there
138 \\ stwu 30, -16(1)138 \\ stwu 29, -16(1)
139 \\ stw 31, 4(1)139 \\ stw 30, 4(1)
140 \\140 \\
141 \\ # save r3 (func) into r30, and r6(arg) into r31141 \\ # save r3 (func) into r29, and r6(arg) into r30
142 \\ mr 30, 3142 \\ mr 29, 3
143 \\ mr 31, 6143 \\ mr 30, 6
144 \\144 \\
145 \\ # create initial stack frame for new thread145 \\ # create initial stack frame for new thread
146 \\ clrrwi 4, 4, 4146 \\ clrrwi 4, 4, 4
...@@ -167,28 +167,28 @@ pub fn clone() callconv(.Naked) usize {...@@ -167,28 +167,28 @@ pub fn clone() callconv(.Naked) usize {
167 \\ # compare sc result with 0167 \\ # compare sc result with 0
168 \\ cmpwi cr7, 3, 0168 \\ cmpwi cr7, 3, 0
169 \\169 \\
170 \\ # if not 0, jump to end170 \\ # if not 0, restore stack and return
171 \\ bne cr7, 2f171 \\ beq cr7, 2f
172 \\ lwz 29, 0(1)
173 \\ lwz 30, 4(1)
174 \\ addi 1, 1, 16
175 \\ blr
172 \\176 \\
173 \\ #else: we're the child177 \\ #else: we're the child
178 \\ 2:
179 \\ .cfi_undefined lr
180 \\ li 31, 0
181 \\ mtlr 0
182 \\
174 \\ #call funcptr: move arg (d) into r3183 \\ #call funcptr: move arg (d) into r3
175 \\ mr 3, 31184 \\ mr 3, 30
176 \\ #move r30 (funcptr) into CTR reg185 \\ #move r29 (funcptr) into CTR reg
177 \\ mtctr 30186 \\ mtctr 29
178 \\ # call CTR reg187 \\ # call CTR reg
179 \\ bctrl188 \\ bctrl
180 \\ # mov SYS_exit into r0 (the exit param is already in r3)189 \\ # mov SYS_exit into r0 (the exit param is already in r3)
181 \\ li 0, 1190 \\ li 0, 1
182 \\ sc191 \\ sc
183 \\
184 \\ 2:
185 \\
186 \\ # restore stack
187 \\ lwz 30, 0(1)
188 \\ lwz 31, 4(1)
189 \\ addi 1, 1, 16
190 \\
191 \\ blr
192 );192 );
193}193}
194194
lib/std/os/linux/powerpc64.zig+6-1
...@@ -160,7 +160,12 @@ pub fn clone() callconv(.Naked) usize {...@@ -160,7 +160,12 @@ pub fn clone() callconv(.Naked) usize {
160 \\ cmpwi cr7, 3, 0160 \\ cmpwi cr7, 3, 0
161 \\ bnelr cr7161 \\ bnelr cr7
162 \\162 \\
163 \\ # we're the child. call fn(arg)163 \\ # we're the child
164 \\ .cfi_undefined lr
165 \\ li 31, 0
166 \\ mtlr 0
167 \\
168 \\ # call fn(arg)
164 \\ ld 3, 16(1)169 \\ ld 3, 16(1)
165 \\ ld 12, 8(1)170 \\ ld 12, 8(1)
166 \\ mtctr 12171 \\ mtctr 12
lib/std/os/linux/riscv32.zig+5-1
...@@ -120,7 +120,11 @@ pub fn clone() callconv(.Naked) usize {...@@ -120,7 +120,11 @@ pub fn clone() callconv(.Naked) usize {
120 \\ ret120 \\ ret
121 \\121 \\
122 \\ # Child122 \\ # Child
123 \\1: lw a1, 0(sp)123 \\1: .cfi_undefined ra
124 \\ mv fp, zero
125 \\ mv ra, zero
126 \\
127 \\ lw a1, 0(sp)
124 \\ lw a0, 4(sp)128 \\ lw a0, 4(sp)
125 \\ jalr a1129 \\ jalr a1
126 \\130 \\
lib/std/os/linux/riscv64.zig+5-1
...@@ -120,7 +120,11 @@ pub fn clone() callconv(.Naked) usize {...@@ -120,7 +120,11 @@ pub fn clone() callconv(.Naked) usize {
120 \\ ret120 \\ ret
121 \\121 \\
122 \\ # Child122 \\ # Child
123 \\1: ld a1, 0(sp)123 \\1: .cfi_undefined ra
124 \\ mv fp, zero
125 \\ mv ra, zero
126 \\
127 \\ ld a1, 0(sp)
124 \\ ld a0, 8(sp)128 \\ ld a0, 8(sp)
125 \\ jalr a1129 \\ jalr a1
126 \\130 \\
lib/std/os/linux/s390x.zig+6-1
...@@ -133,7 +133,12 @@ pub fn clone() callconv(.Naked) usize {...@@ -133,7 +133,12 @@ pub fn clone() callconv(.Naked) usize {
133 \\ltgr %%r2, %%r2133 \\ltgr %%r2, %%r2
134 \\bnzr %%r14134 \\bnzr %%r14
135 \\135 \\
136 \\# we're the child. call fn(arg)136 \\# we're the child
137 \\.cfi_undefined %%r14
138 \\lghi %%r11, 0
139 \\lghi %%r14, 0
140 \\
141 \\# call fn(arg)
137 \\lg %%r1, 8(%%r15)142 \\lg %%r1, 8(%%r15)
138 \\lg %%r2, 16(%%r15)143 \\lg %%r2, 16(%%r15)
139 \\basr %%r14, %%r1144 \\basr %%r14, %%r1
lib/std/os/linux/sparc64.zig+13-8
...@@ -198,29 +198,34 @@ pub fn clone() callconv(.Naked) usize {...@@ -198,29 +198,34 @@ pub fn clone() callconv(.Naked) usize {
198 \\ mov %%i5, %%o3198 \\ mov %%i5, %%o3
199 \\ ldx [%%fp + 0x8af], %%o4199 \\ ldx [%%fp + 0x8af], %%o4
200 \\ t 0x6d200 \\ t 0x6d
201 \\ bcs,pn %%xcc, 2f201 \\ bcs,pn %%xcc, 1f
202 \\ nop202 \\ nop
203 \\ # The child pid is returned in o0 while o1 tells if this203 \\ # The child pid is returned in o0 while o1 tells if this
204 \\ # process is # the child (=1) or the parent (=0).204 \\ # process is # the child (=1) or the parent (=0).
205 \\ brnz %%o1, 1f205 \\ brnz %%o1, 2f
206 \\ nop206 \\ nop
207 \\ # Parent process, return the child pid207 \\ # Parent process, return the child pid
208 \\ mov %%o0, %%i0208 \\ mov %%o0, %%i0
209 \\ ret209 \\ ret
210 \\ restore210 \\ restore
211 \\1:211 \\1:
212 \\ # Child process, call func(arg)212 \\ # The syscall failed
213 \\ sub %%g0, %%o0, %%i0
214 \\ ret
215 \\ restore
216 \\2:
217 \\ # Child process
218 \\ .cfi_undefined %%i7
219 \\ mov %%g0, %%fp
220 \\ mov %%g0, %%i7
221 \\
222 \\ # call func(arg)
213 \\ mov %%g0, %%fp223 \\ mov %%g0, %%fp
214 \\ call %%g2224 \\ call %%g2
215 \\ mov %%g3, %%o0225 \\ mov %%g3, %%o0
216 \\ # Exit226 \\ # Exit
217 \\ mov 1, %%g1 // SYS_exit227 \\ mov 1, %%g1 // SYS_exit
218 \\ t 0x6d228 \\ t 0x6d
219 \\2:
220 \\ # The syscall failed
221 \\ sub %%g0, %%o0, %%i0
222 \\ ret
223 \\ restore
224 );229 );
225}230}
226231
lib/std/os/linux/x86.zig+11-8
...@@ -148,19 +148,22 @@ pub fn clone() callconv(.Naked) usize {...@@ -148,19 +148,22 @@ pub fn clone() callconv(.Naked) usize {
148 \\ movl $120,%%eax // SYS_clone148 \\ movl $120,%%eax // SYS_clone
149 \\ int $128149 \\ int $128
150 \\ testl %%eax,%%eax150 \\ testl %%eax,%%eax
151 \\ jnz 1f151 \\ jz 1f
152 \\ popl %%eax
153 \\ xorl %%ebp,%%ebp
154 \\ calll *%%eax
155 \\ movl %%eax,%%ebx
156 \\ movl $1,%%eax // SYS_exit
157 \\ int $128
158 \\1:
159 \\ popl %%edi152 \\ popl %%edi
160 \\ popl %%esi153 \\ popl %%esi
161 \\ popl %%ebx154 \\ popl %%ebx
162 \\ popl %%ebp155 \\ popl %%ebp
163 \\ retl156 \\ retl
157 \\
158 \\1:
159 \\ .cfi_undefined %%eip
160 \\ xorl %%ebp,%%ebp
161 \\
162 \\ popl %%eax
163 \\ calll *%%eax
164 \\ movl %%eax,%%ebx
165 \\ movl $1,%%eax // SYS_exit
166 \\ int $128
164 );167 );
165}168}
166169
lib/std/os/linux/x86_64.zig+2
...@@ -116,8 +116,10 @@ pub fn clone() callconv(.Naked) usize {...@@ -116,8 +116,10 @@ pub fn clone() callconv(.Naked) usize {
116 \\ testq %%rax,%%rax116 \\ testq %%rax,%%rax
117 \\ jz 1f117 \\ jz 1f
118 \\ retq118 \\ retq
119 \\
119 \\1: .cfi_undefined %%rip120 \\1: .cfi_undefined %%rip
120 \\ xorl %%ebp,%%ebp121 \\ xorl %%ebp,%%ebp
122 \\
121 \\ popq %%rdi123 \\ popq %%rdi
122 \\ callq *%%r9124 \\ callq *%%r9
123 \\ movl %%eax,%%edi125 \\ movl %%eax,%%edi