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(®s->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 *)®s->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, ®s->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 *)®s->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