gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/platform/systrap/stub_amd64.s (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "funcdata.h" 16 #include "textflag.h" 17 18 #define SYS_GETPID 39 // +checkconst unix SYS_GETPID 19 #define SYS_EXIT 60 // +checkconst unix SYS_EXIT 20 #define SYS_KILL 62 // +checkconst unix SYS_KILL 21 #define SYS_GETPPID 110 // +checkconst unix SYS_GETPPID 22 #define SIGKILL 9 // +checkconst unix SIGKILL 23 #define SIGSTOP 19 // +checkconst unix SIGSTOP 24 #define SYS_PRCTL 157 // +checkconst unix SYS_PRCTL 25 #define SYS_EXIT_GROUP 231 // +checkconst unix SYS_EXIT_GROUP 26 #define PR_SET_PDEATHSIG 1 // +checkconst unix PR_SET_PDEATHSIG 27 28 #define SYS_FUTEX 202 // +checkconst unix SYS_FUTEX 29 #define FUTEX_WAKE 1 // +checkconst linux FUTEX_WAKE 30 #define FUTEX_WAIT 0 // +checkconst linux FUTEX_WAIT 31 32 #define NEW_STUB 1 // +checkconst . _NEW_STUB 33 #define RUN_SYSCALL_LOOP 5 // +checkconst . _RUN_SYSCALL_LOOP 34 #define RUN_SECCOMP_LOOP 6 // +checkconst . _RUN_SECCOMP_LOOP 35 36 // syscallSentryMessage offsets. 37 #define SENTRY_MESSAGE_STATE 0 // +checkoffset . syscallSentryMessage.state 38 #define SENTRY_MESSAGE_SYSNO 8 // +checkoffset . syscallSentryMessage.sysno 39 #define SENTRY_MESSAGE_ARGS 16 // +checkoffset . syscallSentryMessage.args 40 #define SENTRY_MESSAGE_ARG0 (SENTRY_MESSAGE_ARGS + 0*8) 41 #define SENTRY_MESSAGE_ARG1 (SENTRY_MESSAGE_ARGS + 1*8) 42 #define SENTRY_MESSAGE_ARG2 (SENTRY_MESSAGE_ARGS + 2*8) 43 #define SENTRY_MESSAGE_ARG3 (SENTRY_MESSAGE_ARGS + 3*8) 44 #define SENTRY_MESSAGE_ARG4 (SENTRY_MESSAGE_ARGS + 4*8) 45 #define SENTRY_MESSAGE_ARG5 (SENTRY_MESSAGE_ARGS + 5*8) 46 47 // syscallStubMessage offsets. 48 #define STUB_MESSAGE_OFFSET 4096 // +checkconst . syscallStubMessageOffset 49 #define STUB_MESSAGE_RET 0 // +checkoffset . syscallStubMessage.ret 50 51 // initStubProcess bootstraps the child and sends itself SIGSTOP to wait for attach. 52 // 53 // R15 contains the expected PPID. R15 is used instead of a more typical DI 54 // since syscalls will clobber DI and createStub wants to pass a new PPID to 55 // grandchildren. 56 // 57 // This should not be used outside the context of a new ptrace child (as the 58 // function is otherwise a bunch of nonsense). 59 TEXT ·initStubProcess(SB),NOSPLIT|NOFRAME,$0 60 begin: 61 // N.B. This loop only executes in the context of a single-threaded 62 // fork child. 63 64 MOVQ $SYS_PRCTL, AX 65 MOVQ $PR_SET_PDEATHSIG, DI 66 MOVQ $SIGKILL, SI 67 SYSCALL 68 69 CMPQ AX, $0 70 JNE error 71 72 // If the parent already died before we called PR_SET_DEATHSIG then 73 // we'll have an unexpected PPID. 74 MOVQ $SYS_GETPPID, AX 75 SYSCALL 76 77 CMPQ AX, $0 78 JL error 79 80 CMPQ AX, R15 81 JNE parent_dead 82 83 MOVQ $SYS_GETPID, AX 84 SYSCALL 85 86 CMPQ AX, $0 87 JL error 88 89 MOVQ $0, BX 90 91 // SIGSTOP to wait for attach. 92 // 93 // The SYSCALL instruction will be used for future syscall injection by 94 // thread.syscall. 95 MOVQ AX, DI 96 MOVQ $SYS_KILL, AX 97 MOVQ $SIGSTOP, SI 98 SYSCALL 99 100 // The sentry sets BX to $NEW_STUB when creating stub process. 101 CMPQ BX, $NEW_STUB 102 JE clone 103 104 // The sentry sets BX to $RUN_SYSCALL_LOOP when requesting a syscall 105 // thread. 106 CMPQ BX, $RUN_SYSCALL_LOOP 107 JE syscall_loop 108 109 CMPQ BX, $RUN_SECCOMP_LOOP 110 JE seccomp_loop 111 112 // Notify the Sentry that syscall exited. 113 done: 114 INT $3 115 // Be paranoid. 116 JMP done 117 clone: 118 // subprocess.createStub clones a new stub process that is untraced, 119 // thus executing this code. We setup the PDEATHSIG before SIGSTOPing 120 // ourselves for attach by the tracer. 121 // 122 // R15 has been updated with the expected PPID. 123 CMPQ AX, $0 124 JE begin 125 126 // The clone syscall returns a non-zero value. 127 JMP done 128 error: 129 // Exit with -errno. 130 MOVQ AX, DI 131 NEGQ DI 132 MOVQ $SYS_EXIT, AX 133 SYSCALL 134 HLT 135 136 parent_dead: 137 MOVQ $SYS_EXIT, AX 138 MOVQ $1, DI 139 SYSCALL 140 HLT 141 142 // syscall_loop handles requests from the Sentry to execute syscalls. 143 // Look at syscall_thread for more details. 144 // 145 // syscall_loop is running without using the stack because it can be 146 // compromised by sysmsg (guest) threads that run in the same address 147 // space. 148 syscall_loop: 149 // while (sentryMessage->state != R13) { 150 // futex(sentryMessage->state, FUTEX_WAIT, 0, NULL, NULL, 0); 151 // } 152 MOVQ R12, DI 153 MOVQ $FUTEX_WAIT, SI 154 MOVQ $0, R10 155 MOVQ $0, R8 156 MOVQ $0, R9 157 wait_for_syscall: 158 MOVL SENTRY_MESSAGE_STATE(DI), DX 159 CMPL DX, R13 160 JE execute_syscall 161 162 MOVQ $SYS_FUTEX, AX 163 SYSCALL 164 JMP wait_for_syscall 165 166 execute_syscall: 167 // ret = syscall(sysno, args...) 168 MOVQ SENTRY_MESSAGE_SYSNO(R12), AX 169 MOVQ SENTRY_MESSAGE_ARG0(R12), DI 170 MOVQ SENTRY_MESSAGE_ARG1(R12), SI 171 MOVQ SENTRY_MESSAGE_ARG2(R12), DX 172 MOVQ SENTRY_MESSAGE_ARG3(R12), R10 173 MOVQ SENTRY_MESSAGE_ARG4(R12), R8 174 MOVQ SENTRY_MESSAGE_ARG5(R12), R9 175 SYSCALL 176 177 // stubMessage->ret = ret 178 MOVQ AX, (STUB_MESSAGE_OFFSET + STUB_MESSAGE_RET)(R12) 179 180 // for { 181 // if futex(sentryMessage->state, FUTEX_WAKE, 1) == 1 { 182 // break; 183 // } 184 // } 185 MOVQ R12, DI 186 MOVQ $FUTEX_WAKE, SI 187 MOVQ $1, DX 188 MOVQ $0, R10 189 MOVQ $0, R8 190 MOVQ $0, R9 191 wake_up_sentry: 192 MOVQ $SYS_FUTEX, AX 193 SYSCALL 194 // futex returns the number of waiters that were woken up. If futex 195 // returns 0 here, it means that the Sentry has not called futex_wait 196 // yet and we need to try again. The value of sentryMessage->state 197 // isn't changed, so futex_wake is the only way to wake up the Sentry. 198 CMPQ AX, $1 199 JNE wake_up_sentry 200 201 INCL R13 202 JMP syscall_loop 203 seccomp_loop: 204 // SYS_EXIT_GROUP triggers seccomp notifications. 205 MOVQ $SYS_EXIT_GROUP, AX 206 SYSCALL 207 208 // ret = syscall(sysno, args...) 209 MOVQ SENTRY_MESSAGE_SYSNO(R12), AX 210 MOVQ SENTRY_MESSAGE_ARG0(R12), DI 211 MOVQ SENTRY_MESSAGE_ARG1(R12), SI 212 MOVQ SENTRY_MESSAGE_ARG2(R12), DX 213 MOVQ SENTRY_MESSAGE_ARG3(R12), R10 214 MOVQ SENTRY_MESSAGE_ARG4(R12), R8 215 MOVQ SENTRY_MESSAGE_ARG5(R12), R9 216 SYSCALL 217 218 // stubMessage->ret = ret 219 MOVQ AX, (STUB_MESSAGE_OFFSET + STUB_MESSAGE_RET)(R12) 220 221 // for { 222 // if futex(sentryMessage->state, FUTEX_WAKE, 1) == 1 { 223 // break; 224 // } 225 // } 226 MOVQ R12, DI 227 MOVQ $FUTEX_WAKE, SI 228 MOVQ $1, DX 229 MOVQ $0, R10 230 MOVQ $0, R8 231 MOVQ $0, R9 232 JMP seccomp_loop 233 234 // func addrOfInitStubProcess() uintptr 235 TEXT ·addrOfInitStubProcess(SB), $0-8 236 MOVQ $·initStubProcess(SB), AX 237 MOVQ AX, ret+0(FP) 238 RET 239 240 // stubCall calls the stub function at the given address with the given PPID. 241 // 242 // This is a distinct function because stub, above, may be mapped at any 243 // arbitrary location, and stub has a specific binary API (see above). 244 TEXT ·stubCall(SB),NOSPLIT|NOFRAME,$0-16 245 MOVQ addr+0(FP), AX 246 MOVQ pid+8(FP), R15 247 JMP AX