github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/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 PR_SET_PDEATHSIG 1 // +checkconst unix PR_SET_PDEATHSIG 26 27 #define SYS_FUTEX 202 // +checkconst unix SYS_FUTEX 28 #define FUTEX_WAKE 1 // +checkconst linux FUTEX_WAKE 29 #define FUTEX_WAIT 0 // +checkconst linux FUTEX_WAIT 30 31 #define NEW_STUB 1 // +checkconst . _NEW_STUB 32 #define RUN_SYSCALL_LOOP 5 // +checkconst . _RUN_SYSCALL_LOOP 33 34 // syscallSentryMessage offsets. 35 #define SENTRY_MESSAGE_STATE 0 // +checkoffset . syscallSentryMessage.state 36 #define SENTRY_MESSAGE_SYSNO 8 // +checkoffset . syscallSentryMessage.sysno 37 #define SENTRY_MESSAGE_ARGS 16 // +checkoffset . syscallSentryMessage.args 38 #define SENTRY_MESSAGE_ARG0 (SENTRY_MESSAGE_ARGS + 0*8) 39 #define SENTRY_MESSAGE_ARG1 (SENTRY_MESSAGE_ARGS + 1*8) 40 #define SENTRY_MESSAGE_ARG2 (SENTRY_MESSAGE_ARGS + 2*8) 41 #define SENTRY_MESSAGE_ARG3 (SENTRY_MESSAGE_ARGS + 3*8) 42 #define SENTRY_MESSAGE_ARG4 (SENTRY_MESSAGE_ARGS + 4*8) 43 #define SENTRY_MESSAGE_ARG5 (SENTRY_MESSAGE_ARGS + 5*8) 44 45 // syscallStubMessage offsets. 46 #define STUB_MESSAGE_OFFSET 4096 // +checkconst . syscallStubMessageOffset 47 #define STUB_MESSAGE_RET 0 // +checkoffset . syscallStubMessage.ret 48 49 // initStubProcess bootstraps the child and sends itself SIGSTOP to wait for attach. 50 // 51 // R15 contains the expected PPID. R15 is used instead of a more typical DI 52 // since syscalls will clobber DI and createStub wants to pass a new PPID to 53 // grandchildren. 54 // 55 // This should not be used outside the context of a new ptrace child (as the 56 // function is otherwise a bunch of nonsense). 57 TEXT ·initStubProcess(SB),NOSPLIT|NOFRAME,$0 58 begin: 59 // N.B. This loop only executes in the context of a single-threaded 60 // fork child. 61 62 MOVQ $SYS_PRCTL, AX 63 MOVQ $PR_SET_PDEATHSIG, DI 64 MOVQ $SIGKILL, SI 65 SYSCALL 66 67 CMPQ AX, $0 68 JNE error 69 70 // If the parent already died before we called PR_SET_DEATHSIG then 71 // we'll have an unexpected PPID. 72 MOVQ $SYS_GETPPID, AX 73 SYSCALL 74 75 CMPQ AX, $0 76 JL error 77 78 CMPQ AX, R15 79 JNE parent_dead 80 81 MOVQ $SYS_GETPID, AX 82 SYSCALL 83 84 CMPQ AX, $0 85 JL error 86 87 MOVQ $0, BX 88 89 // SIGSTOP to wait for attach. 90 // 91 // The SYSCALL instruction will be used for future syscall injection by 92 // thread.syscall. 93 MOVQ AX, DI 94 MOVQ $SYS_KILL, AX 95 MOVQ $SIGSTOP, SI 96 SYSCALL 97 98 // The sentry sets BX to $NEW_STUB when creating stub process. 99 CMPQ BX, $NEW_STUB 100 JE clone 101 102 // The sentry sets BX to $RUN_SYSCALL_LOOP when requesting a syscall 103 // thread. 104 CMPQ BX, $RUN_SYSCALL_LOOP 105 JE syscall_loop 106 107 // Notify the Sentry that syscall exited. 108 done: 109 INT $3 110 // Be paranoid. 111 JMP done 112 clone: 113 // subprocess.createStub clones a new stub process that is untraced, 114 // thus executing this code. We setup the PDEATHSIG before SIGSTOPing 115 // ourselves for attach by the tracer. 116 // 117 // R15 has been updated with the expected PPID. 118 CMPQ AX, $0 119 JE begin 120 121 // The clone syscall returns a non-zero value. 122 JMP done 123 error: 124 // Exit with -errno. 125 MOVQ AX, DI 126 NEGQ DI 127 MOVQ $SYS_EXIT, AX 128 SYSCALL 129 HLT 130 131 parent_dead: 132 MOVQ $SYS_EXIT, AX 133 MOVQ $1, DI 134 SYSCALL 135 HLT 136 137 // syscall_loop handles requests from the Sentry to execute syscalls. 138 // Look at syscall_thread for more details. 139 // 140 // syscall_loop is running without using the stack because it can be 141 // compromised by sysmsg (guest) threads that run in the same address 142 // space. 143 syscall_loop: 144 // while (sentryMessage->state != R13) { 145 // futex(sentryMessage->state, FUTEX_WAIT, 0, NULL, NULL, 0); 146 // } 147 MOVQ R12, DI 148 MOVQ $FUTEX_WAIT, SI 149 MOVQ $0, R10 150 MOVQ $0, R8 151 MOVQ $0, R9 152 wait_for_syscall: 153 MOVL SENTRY_MESSAGE_STATE(DI), DX 154 CMPL DX, R13 155 JE execute_syscall 156 157 MOVQ $SYS_FUTEX, AX 158 SYSCALL 159 JMP wait_for_syscall 160 161 execute_syscall: 162 // ret = syscall(sysno, args...) 163 MOVQ SENTRY_MESSAGE_SYSNO(R12), AX 164 MOVQ SENTRY_MESSAGE_ARG0(R12), DI 165 MOVQ SENTRY_MESSAGE_ARG1(R12), SI 166 MOVQ SENTRY_MESSAGE_ARG2(R12), DX 167 MOVQ SENTRY_MESSAGE_ARG3(R12), R10 168 MOVQ SENTRY_MESSAGE_ARG4(R12), R8 169 MOVQ SENTRY_MESSAGE_ARG5(R12), R9 170 SYSCALL 171 172 // stubMessage->ret = ret 173 MOVQ AX, (STUB_MESSAGE_OFFSET + STUB_MESSAGE_RET)(R12) 174 175 // for { 176 // if futex(sentryMessage->state, FUTEX_WAKE, 1) == 1 { 177 // break; 178 // } 179 // } 180 MOVQ R12, DI 181 MOVQ $FUTEX_WAKE, SI 182 MOVQ $1, DX 183 MOVQ $0, R10 184 MOVQ $0, R8 185 MOVQ $0, R9 186 wake_up_sentry: 187 MOVQ $SYS_FUTEX, AX 188 SYSCALL 189 // futex returns the number of waiters that were woken up. If futex 190 // returns 0 here, it means that the Sentry has not called futex_wait 191 // yet and we need to try again. The value of sentryMessage->state 192 // isn't changed, so futex_wake is the only way to wake up the Sentry. 193 CMPQ AX, $1 194 JNE wake_up_sentry 195 196 INCL R13 197 JMP syscall_loop 198 199 // func addrOfInitStubProcess() uintptr 200 TEXT ·addrOfInitStubProcess(SB), $0-8 201 MOVQ $·initStubProcess(SB), AX 202 MOVQ AX, ret+0(FP) 203 RET 204 205 // stubCall calls the stub function at the given address with the given PPID. 206 // 207 // This is a distinct function because stub, above, may be mapped at any 208 // arbitrary location, and stub has a specific binary API (see above). 209 TEXT ·stubCall(SB),NOSPLIT|NOFRAME,$0-16 210 MOVQ addr+0(FP), AX 211 MOVQ pid+8(FP), R15 212 JMP AX