File Index
Files and directories
Sign in
FILE

mcontext.c

File preview with syntax highlighting.

linux-6.19.14/arch/x86/um/os-Linux/mcontext.c C
  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
 12void 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
 44void 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. */
 56void 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
 88struct _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 */
 96int um_i387_from_fxsr(struct _fpstate_32 *i387,
 97		      const struct _fpstate_64 *fxsave);
 98int um_fxsr_from_i387(struct _fpstate_64 *fxsave,
 99		      const struct _fpstate_32 *from);
100#else
101#define _xstate_64 _xstate
102#endif
103
104static 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
145int 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. */
192struct task_struct;
193struct user_regset;
194struct membuf {
195	void *p;
196	size_t left;
197};
198
199int fpregs_legacy_get(struct task_struct *target,
200		      const struct user_regset *regset,
201		      struct membuf to);
202
203int 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}
~/ Read-only file preview.