github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/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