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