File: stub_arm64.s

package info (click to toggle)
golang-gvisor-gvisor 0.0~20240729.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 21,276 kB
  • sloc: asm: 3,361; ansic: 1,197; cpp: 348; makefile: 92; python: 89; sh: 83
file content (227 lines) | stat: -rw-r--r-- 6,470 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
// Copyright 2019 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "funcdata.h"
#include "textflag.h"

#define SYS_GETPID       172 // +checkconst unix SYS_GETPID
#define SYS_EXIT	 93  // +checkconst unix SYS_EXIT
#define SYS_KILL	 129 // +checkconst unix SYS_KILL
#define SYS_GETPPID	 173 // +checkconst unix SYS_GETPPID
#define SIGKILL		 9   // +checkconst unix SIGKILL
#define SIGSTOP		 19  // +checkconst unix SIGSTOP
#define SYS_PRCTL	 167 // +checkconst unix SYS_PRCTL
#define SYS_EXIT_GROUP   94  // +checkconst unix SYS_EXIT_GROUP
#define PR_SET_PDEATHSIG 1   // +checkconst unix PR_SET_PDEATHSIG

#define SYS_FUTEX	 98 // +checkconst unix SYS_FUTEX
#define FUTEX_WAKE	 1  // +checkconst linux FUTEX_WAKE
#define FUTEX_WAIT	 0  // +checkconst linux FUTEX_WAIT

#define NEW_STUB	 1 // +checkconst . _NEW_STUB
#define RUN_SYSCALL_LOOP 5 // +checkconst . _RUN_SYSCALL_LOOP
#define RUN_SECCOMP_LOOP 6 // +checkconst . _RUN_SECCOMP_LOOP

// syscallSentryMessage offsets.
#define SENTRY_MESSAGE_STATE 0  // +checkoffset . syscallSentryMessage.state
#define SENTRY_MESSAGE_SYSNO 8  // +checkoffset . syscallSentryMessage.sysno
#define SENTRY_MESSAGE_ARGS  16 // +checkoffset . syscallSentryMessage.args
#define SENTRY_MESSAGE_ARG0  (SENTRY_MESSAGE_ARGS + 0*8)
#define SENTRY_MESSAGE_ARG1  (SENTRY_MESSAGE_ARGS + 1*8)
#define SENTRY_MESSAGE_ARG2  (SENTRY_MESSAGE_ARGS + 2*8)
#define SENTRY_MESSAGE_ARG3  (SENTRY_MESSAGE_ARGS + 3*8)
#define SENTRY_MESSAGE_ARG4  (SENTRY_MESSAGE_ARGS + 4*8)
#define SENTRY_MESSAGE_ARG5  (SENTRY_MESSAGE_ARGS + 5*8)

// syscallStubMessage offsets.
#define STUB_MESSAGE_OFFSET 4096 // +checkconst . syscallStubMessageOffset
#define STUB_MESSAGE_RET    0    // +checkoffset . syscallStubMessage.ret

// initStubProcess bootstraps the child and sends itself SIGSTOP to wait for attach.
//
// R7 contains the expected PPID.
//
// This should not be used outside the context of a new ptrace child (as the
// function is otherwise a bunch of nonsense).
TEXT ·initStubProcess(SB),NOSPLIT,$0
begin:
	// N.B. This loop only executes in the context of a single-threaded
	// fork child.

	MOVD $SYS_PRCTL, R8
	MOVD $PR_SET_PDEATHSIG, R0
	MOVD $SIGKILL, R1
	SVC

	CMN $4095, R0
	BCS error

	// If the parent already died before we called PR_SET_DEATHSIG then
	// we'll have an unexpected PPID.
	MOVD $SYS_GETPPID, R8
	SVC

	CMP R0, R7
	BNE parent_dead

	MOVD $SYS_GETPID, R8
	SVC

	CMP $0x0, R0
	BLT error

	MOVD $0, R9

	// SIGSTOP to wait for attach.
	//
	// The SYSCALL instruction will be used for future syscall injection by
	// thread.syscall.
	MOVD $SYS_KILL, R8
	MOVD $SIGSTOP, R1
	SVC

	// The sentry sets R9 to $NEW_STUB when creating stub process.
	CMP $NEW_STUB, R9
	BEQ clone

        // The sentry sets R9 to $RUN_SYSCALL_LOOP when creating a new syscall
        // thread.
	CMP $RUN_SYSCALL_LOOP, R9
	BEQ syscall_loop

	CMP $RUN_SECCOMP_LOOP, R9
	BEQ seccomp_loop
done:
	// Notify the Sentry that syscall exited.
	BRK $3
	B done // Be paranoid.
clone:
	// subprocess.createStub clones a new stub process that is untraced,
	// thus executing this code. We setup the PDEATHSIG before SIGSTOPing
	// ourselves for attach by the tracer.
	//
	// R7 has been updated with the expected PPID.
	CMP $0, R0
	BEQ begin

	// The clone system call returned a non-zero value.
	B done

error:
	// Exit with -errno.
	NEG R0, R0
	MOVD $SYS_EXIT, R8
	SVC
	HLT

parent_dead:
	MOVD $SYS_EXIT, R8
	MOVD $1, R0
	SVC
	HLT

	// syscall_loop handles requests from the Sentry to execute syscalls.
	// Look at syscall_thread for more details.
	//
	// syscall_loop is running without using the stack because it can be
	// compromised by sysmsg (guest) threads that run in the same address
	// space.
syscall_loop:
	// while (sentryMessage->state != R13) {
	// 	futex(sentryMessage->state, FUTEX_WAIT, 0, NULL, NULL, 0);
	// }
        MOVD R12, R0
	MOVD $FUTEX_WAIT, R1
	MOVD $0, R3
	MOVD $0, R4
	MOVD $0, R5
wait_for_syscall:
	// Move the sentry message state to R2.
	MOVW SENTRY_MESSAGE_STATE(R12), R2
	CMPW R2, R13
	BEQ execute_syscall

	MOVD $SYS_FUTEX, R8
	SVC
	JMP wait_for_syscall

execute_syscall:
	MOVD SENTRY_MESSAGE_SYSNO(R12), R8
	MOVD SENTRY_MESSAGE_ARG0(R12), R0
	MOVD SENTRY_MESSAGE_ARG1(R12), R1
	MOVD SENTRY_MESSAGE_ARG2(R12), R2
	MOVD SENTRY_MESSAGE_ARG3(R12), R3
	MOVD SENTRY_MESSAGE_ARG4(R12), R4
	MOVD SENTRY_MESSAGE_ARG5(R12), R5
        SVC

	// stubMessage->ret = ret
	MOVD R0, (STUB_MESSAGE_OFFSET + STUB_MESSAGE_RET)(R12)

	// for {
	//   if futex(sentryMessage->state, FUTEX_WAKE, 1) == 1 {
	//     break;
	//   }
	// }
	MOVD $FUTEX_WAKE, R1
	MOVD $1, R2
	MOVD $0, R3
	MOVD $0, R4
	MOVD $0, R5
	MOVD $SYS_FUTEX, R8
wake_up_sentry:
	MOVD R12, R0
	SVC

	// futex returns the number of waiters that were woken up.  If futex
	// returns 0 here, it means that the Sentry has not called futex_wait
	// yet and we need to try again. The value of sentryMessage->state
	// isn't changed, so futex_wake is the only way to wake up the Sentry.
	CMP $1, R0
	BNE wake_up_sentry

	ADDW $1, R13, R13
	JMP syscall_loop
seccomp_loop:
	// SYS_EXIT_GROUP triggers seccomp notifications.
	MOVD $SYS_EXIT_GROUP, R8
	SVC

	MOVD SENTRY_MESSAGE_SYSNO(R12), R8
	MOVD SENTRY_MESSAGE_ARG0(R12), R0
	MOVD SENTRY_MESSAGE_ARG1(R12), R1
	MOVD SENTRY_MESSAGE_ARG2(R12), R2
	MOVD SENTRY_MESSAGE_ARG3(R12), R3
	MOVD SENTRY_MESSAGE_ARG4(R12), R4
	MOVD SENTRY_MESSAGE_ARG5(R12), R5
	SVC

	// stubMessage->ret = ret
	MOVD R0, (STUB_MESSAGE_OFFSET + STUB_MESSAGE_RET)(R12)
	JMP seccomp_loop

// func addrOfInitStubProcess() uintptr
TEXT ·addrOfInitStubProcess(SB), $0-8
	MOVD	$·initStubProcess(SB), R0
	MOVD	R0, ret+0(FP)
	RET

// stubCall calls the stub function at the given address with the given PPID.
//
// This is a distinct function because stub, above, may be mapped at any
// arbitrary location, and stub has a specific binary API (see above).
TEXT ·stubCall(SB),NOSPLIT,$0-16
	MOVD addr+0(FP), R0
	MOVD pid+8(FP), R7
	B (R0)