xref: /linux/arch/x86/um/os-Linux/mcontext.c (revision 5ea5880764cbb164afb17a62e76ca75dc371409d)
1 // SPDX-License-Identifier: GPL-2.0
2 #define __FRAME_OFFSETS
3 #include <linux/errno.h>
4 #include <linux/string.h>
5 #include <sys/ucontext.h>
6 #include <asm/ptrace.h>
7 /*
8  * musl defines struct sigcontext in <bits/signal.h>.  Rename the kernel's
9  * copy to avoid redefinition while keeping the FP-state types available.
10  */
11 #define sigcontext __kernel_sigcontext
12 #include <asm/sigcontext.h>
13 #undef sigcontext
14 #include <sysdep/ptrace.h>
15 #include <sysdep/mcontext.h>
16 #include <arch.h>
17 
18 void get_regs_from_mc(struct uml_pt_regs *regs, mcontext_t *mc)
19 {
20 #ifdef __i386__
21 #define COPY2(X,Y) regs->gp[X] = mc->gregs[REG_##Y]
22 #define COPY(X) regs->gp[X] = mc->gregs[REG_##X]
23 #define COPY_SEG(X) regs->gp[X] = mc->gregs[REG_##X] & 0xffff;
24 #define COPY_SEG_CPL3(X) regs->gp[X] = (mc->gregs[REG_##X] & 0xffff) | 3;
25 	COPY_SEG(GS); COPY_SEG(FS); COPY_SEG(ES); COPY_SEG(DS);
26 	COPY(EDI); COPY(ESI); COPY(EBP);
27 	COPY2(UESP, ESP); /* sic */
28 	COPY(EBX); COPY(EDX); COPY(ECX); COPY(EAX);
29 	COPY(EIP); COPY_SEG_CPL3(CS); COPY(EFL); COPY_SEG_CPL3(SS);
30 #undef COPY2
31 #undef COPY
32 #undef COPY_SEG
33 #undef COPY_SEG_CPL3
34 #else
35 #define COPY2(X,Y) regs->gp[X/sizeof(unsigned long)] = mc->gregs[REG_##Y]
36 #define COPY(X) regs->gp[X/sizeof(unsigned long)] = mc->gregs[REG_##X]
37 	COPY(R8); COPY(R9); COPY(R10); COPY(R11);
38 	COPY(R12); COPY(R13); COPY(R14); COPY(R15);
39 	COPY(RDI); COPY(RSI); COPY(RBP); COPY(RBX);
40 	COPY(RDX); COPY(RAX); COPY(RCX); COPY(RSP);
41 	COPY(RIP);
42 	COPY2(EFLAGS, EFL);
43 	COPY2(CS, CSGSFS);
44 	regs->gp[SS / sizeof(unsigned long)] = mc->gregs[REG_CSGSFS] >> 48;
45 #undef COPY2
46 #undef COPY
47 #endif
48 }
49 
50 void mc_set_rip(void *_mc, void *target)
51 {
52 	mcontext_t *mc = _mc;
53 
54 #ifdef __i386__
55 	mc->gregs[REG_EIP] = (unsigned long)target;
56 #else
57 	mc->gregs[REG_RIP] = (unsigned long)target;
58 #endif
59 }
60 
61 /* Same thing, but the copy macros are turned around. */
62 void get_mc_from_regs(struct uml_pt_regs *regs, mcontext_t *mc, int single_stepping)
63 {
64 #ifdef __i386__
65 #define COPY2(X,Y) mc->gregs[REG_##Y] = regs->gp[X]
66 #define COPY(X) mc->gregs[REG_##X] = regs->gp[X]
67 #define COPY_SEG(X) mc->gregs[REG_##X] = regs->gp[X] & 0xffff;
68 #define COPY_SEG_CPL3(X) mc->gregs[REG_##X] = (regs->gp[X] & 0xffff) | 3;
69 	COPY_SEG(GS); COPY_SEG(FS); COPY_SEG(ES); COPY_SEG(DS);
70 	COPY(EDI); COPY(ESI); COPY(EBP);
71 	COPY2(UESP, ESP); /* sic */
72 	COPY(EBX); COPY(EDX); COPY(ECX); COPY(EAX);
73 	COPY(EIP); COPY_SEG_CPL3(CS); COPY(EFL); COPY_SEG_CPL3(SS);
74 #else
75 #define COPY2(X,Y) mc->gregs[REG_##Y] = regs->gp[X/sizeof(unsigned long)]
76 #define COPY(X) mc->gregs[REG_##X] = regs->gp[X/sizeof(unsigned long)]
77 	COPY(R8); COPY(R9); COPY(R10); COPY(R11);
78 	COPY(R12); COPY(R13); COPY(R14); COPY(R15);
79 	COPY(RDI); COPY(RSI); COPY(RBP); COPY(RBX);
80 	COPY(RDX); COPY(RAX); COPY(RCX); COPY(RSP);
81 	COPY(RIP);
82 	COPY2(EFLAGS, EFL);
83 	mc->gregs[REG_CSGSFS] = mc->gregs[REG_CSGSFS] & 0xffffffffffffl;
84 	mc->gregs[REG_CSGSFS] |= (regs->gp[SS / sizeof(unsigned long)] & 0xffff) << 48;
85 #endif
86 
87 	if (single_stepping)
88 		mc->gregs[REG_EFL] |= X86_EFLAGS_TF;
89 	else
90 		mc->gregs[REG_EFL] &= ~X86_EFLAGS_TF;
91 }
92 
93 #ifdef CONFIG_X86_32
94 struct _xstate_64 {
95 	struct _fpstate_64		fpstate;
96 	struct _header			xstate_hdr;
97 	struct _ymmh_state		ymmh;
98 	/* New processor state extensions go here: */
99 };
100 
101 /* Not quite the right structures as these contain more information */
102 int um_i387_from_fxsr(struct _fpstate_32 *i387,
103 		      const struct _fpstate_64 *fxsave);
104 int um_fxsr_from_i387(struct _fpstate_64 *fxsave,
105 		      const struct _fpstate_32 *from);
106 #else
107 #define _xstate_64 _xstate
108 #endif
109 
110 static struct _fpstate *get_fpstate(struct stub_data *data,
111 				    mcontext_t *mcontext,
112 				    int *fp_size)
113 {
114 	struct _fpstate *res;
115 
116 	/* Assume floating point registers are on the same page */
117 	res = (void *)(((unsigned long)mcontext->fpregs &
118 			(UM_KERN_PAGE_SIZE - 1)) +
119 		       (unsigned long)&data->sigstack[0]);
120 
121 	if ((void *)res + sizeof(struct _fpstate) >
122 	    (void *)data->sigstack + sizeof(data->sigstack))
123 		return NULL;
124 
125 	if (res->sw_reserved.magic1 != FP_XSTATE_MAGIC1) {
126 		*fp_size = sizeof(struct _fpstate);
127 	} else {
128 		char *magic2_addr;
129 
130 		magic2_addr = (void *)res;
131 		magic2_addr += res->sw_reserved.extended_size;
132 		magic2_addr -= FP_XSTATE_MAGIC2_SIZE;
133 
134 		/* We still need to be within our stack */
135 		if ((void *)magic2_addr >
136 		    (void *)data->sigstack + sizeof(data->sigstack))
137 			return NULL;
138 
139 		/* If we do not read MAGIC2, then we did something wrong */
140 		if (*(__u32 *)magic2_addr != FP_XSTATE_MAGIC2)
141 			return NULL;
142 
143 		/* Remove MAGIC2 from the size, we do not save/restore it */
144 		*fp_size = res->sw_reserved.extended_size -
145 			   FP_XSTATE_MAGIC2_SIZE;
146 	}
147 
148 	return res;
149 }
150 
151 int get_stub_state(struct uml_pt_regs *regs, struct stub_data *data,
152 		   unsigned long *fp_size_out)
153 {
154 	mcontext_t *mcontext;
155 	struct _fpstate *fpstate_stub;
156 	struct _xstate_64 *xstate_stub;
157 	int fp_size, xstate_size;
158 
159 	/* mctx_offset is verified by wait_stub_done_seccomp */
160 	mcontext = (void *)&data->sigstack[data->mctx_offset];
161 
162 	get_regs_from_mc(regs, mcontext);
163 
164 	fpstate_stub = get_fpstate(data, mcontext, &fp_size);
165 	if (!fpstate_stub)
166 		return -EINVAL;
167 
168 #ifdef CONFIG_X86_32
169 	xstate_stub = (void *)&fpstate_stub->_fxsr_env;
170 	xstate_size = fp_size - offsetof(struct _fpstate_32, _fxsr_env);
171 #else
172 	xstate_stub = (void *)fpstate_stub;
173 	xstate_size = fp_size;
174 #endif
175 
176 	if (fp_size_out)
177 		*fp_size_out = xstate_size;
178 
179 	if (xstate_size > host_fp_size)
180 		return -ENOSPC;
181 
182 	memcpy(&regs->fp, xstate_stub, xstate_size);
183 
184 	/* We do not need to read the x86_64 FS_BASE/GS_BASE registers as
185 	 * we do not permit userspace to set them directly.
186 	 */
187 
188 #ifdef CONFIG_X86_32
189 	/* Read the i387 legacy FP registers */
190 	if (um_fxsr_from_i387((void *)&regs->fp, fpstate_stub))
191 		return -EINVAL;
192 #endif
193 
194 	return 0;
195 }
196 
197 /* Copied because we cannot include regset.h here. */
198 struct task_struct;
199 struct user_regset;
200 struct membuf {
201 	void *p;
202 	size_t left;
203 };
204 
205 int fpregs_legacy_get(struct task_struct *target,
206 		      const struct user_regset *regset,
207 		      struct membuf to);
208 
209 int set_stub_state(struct uml_pt_regs *regs, struct stub_data *data,
210 		   int single_stepping)
211 {
212 	mcontext_t *mcontext;
213 	struct _fpstate *fpstate_stub;
214 	struct _xstate_64 *xstate_stub;
215 	int fp_size, xstate_size;
216 
217 	/* mctx_offset is verified by wait_stub_done_seccomp */
218 	mcontext = (void *)&data->sigstack[data->mctx_offset];
219 
220 	if ((unsigned long)mcontext < (unsigned long)data->sigstack ||
221 	    (unsigned long)mcontext >
222 			(unsigned long) data->sigstack +
223 			sizeof(data->sigstack) - sizeof(*mcontext))
224 		return -EINVAL;
225 
226 	get_mc_from_regs(regs, mcontext, single_stepping);
227 
228 	fpstate_stub = get_fpstate(data, mcontext, &fp_size);
229 	if (!fpstate_stub)
230 		return -EINVAL;
231 
232 #ifdef CONFIG_X86_32
233 	xstate_stub = (void *)&fpstate_stub->_fxsr_env;
234 	xstate_size = fp_size - offsetof(struct _fpstate_32, _fxsr_env);
235 #else
236 	xstate_stub = (void *)fpstate_stub;
237 	xstate_size = fp_size;
238 #endif
239 
240 	memcpy(xstate_stub, &regs->fp, xstate_size);
241 
242 #ifdef __i386__
243 	/*
244 	 * On x86, the GDT entries are updated by arch_set_tls.
245 	 */
246 
247 	/* Store the i387 legacy FP registers which the host will use */
248 	if (um_i387_from_fxsr(fpstate_stub, (void *)&regs->fp))
249 		return -EINVAL;
250 #else
251 	/*
252 	 * On x86_64, we need to sync the FS_BASE/GS_BASE registers using the
253 	 * arch specific data.
254 	 */
255 	if (data->arch_data.fs_base != regs->gp[FS_BASE / sizeof(unsigned long)]) {
256 		data->arch_data.fs_base = regs->gp[FS_BASE / sizeof(unsigned long)];
257 		data->arch_data.sync |= STUB_SYNC_FS_BASE;
258 	}
259 	if (data->arch_data.gs_base != regs->gp[GS_BASE / sizeof(unsigned long)]) {
260 		data->arch_data.gs_base = regs->gp[GS_BASE / sizeof(unsigned long)];
261 		data->arch_data.sync |= STUB_SYNC_GS_BASE;
262 	}
263 #endif
264 
265 	return 0;
266 }
267