1
1
// SPDX-License-Identifier: GPL-2.0
2
- #include <sys/ucontext.h>
3
2
#define __FRAME_OFFSETS
3
+ #include <linux/errno.h>
4
+ #include <linux/string.h>
5
+ #include <sys/ucontext.h>
4
6
#include <asm/ptrace.h>
7
+ #include <asm/sigcontext.h>
5
8
#include <sysdep/ptrace.h>
6
9
#include <sysdep/mcontext.h>
7
10
#include <arch.h>
@@ -18,6 +21,10 @@ void get_regs_from_mc(struct uml_pt_regs *regs, mcontext_t *mc)
18
21
COPY2 (UESP , ESP ); /* sic */
19
22
COPY (EBX ); COPY (EDX ); COPY (ECX ); COPY (EAX );
20
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
21
28
#else
22
29
#define COPY2 (X ,Y ) regs->gp[X/sizeof(unsigned long)] = mc->gregs[REG_##Y]
23
30
#define COPY (X ) regs->gp[X/sizeof(unsigned long)] = mc->gregs[REG_##X]
@@ -29,6 +36,8 @@ void get_regs_from_mc(struct uml_pt_regs *regs, mcontext_t *mc)
29
36
COPY2 (EFLAGS , EFL );
30
37
COPY2 (CS , CSGSFS );
31
38
regs -> gp [SS / sizeof (unsigned long )] = mc -> gregs [REG_CSGSFS ] >> 48 ;
39
+ #undef COPY2
40
+ #undef COPY
32
41
#endif
33
42
}
34
43
@@ -42,3 +51,210 @@ void mc_set_rip(void *_mc, void *target)
42
51
mc -> gregs [REG_RIP ] = (unsigned long )target ;
43
52
#endif
44
53
}
54
+
55
+ /* Same thing, but the copy macros are turned around. */
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
+
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
+
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
+
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 (fpstate_stub , & regs -> fp , fp_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
+ }
0 commit comments