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