Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/arch/x86/pv/emul-gate-op.c
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 * arch/x86/pv/emul-gate-op.c
3
 *
4
 * Emulate gate op for PV guests
5
 *
6
 * Modifications to Linux original are copyright (c) 2002-2004, K A Fraser
7
 *
8
 * This program is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 2 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; If not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
#include <xen/errno.h>
23
#include <xen/event.h>
24
#include <xen/guest_access.h>
25
#include <xen/iocap.h>
26
#include <xen/spinlock.h>
27
#include <xen/trace.h>
28
29
#include <asm/apic.h>
30
#include <asm/debugreg.h>
31
#include <asm/hpet.h>
32
#include <asm/hypercall.h>
33
#include <asm/mc146818rtc.h>
34
#include <asm/p2m.h>
35
#include <asm/pv/traps.h>
36
#include <asm/shared.h>
37
#include <asm/traps.h>
38
#include <asm/x86_emulate.h>
39
40
#include <xsm/xsm.h>
41
42
#include "emulate.h"
43
44
/* Override macros from asm/page.h to make them work with mfn_t */
45
#undef mfn_to_page
46
#define mfn_to_page(mfn) __mfn_to_page(mfn_x(mfn))
47
#undef page_to_mfn
48
#define page_to_mfn(pg) _mfn(__page_to_mfn(pg))
49
50
static int read_gate_descriptor(unsigned int gate_sel,
51
                                const struct vcpu *v,
52
                                unsigned int *sel,
53
                                unsigned long *off,
54
                                unsigned int *ar)
55
0
{
56
0
    struct desc_struct desc;
57
0
    const struct desc_struct *pdesc;
58
0
59
0
    pdesc = (const struct desc_struct *)
60
0
        (!(gate_sel & 4) ? GDT_VIRT_START(v) : LDT_VIRT_START(v))
61
0
        + (gate_sel >> 3);
62
0
    if ( (gate_sel < 4) ||
63
0
         ((gate_sel >= FIRST_RESERVED_GDT_BYTE) && !(gate_sel & 4)) ||
64
0
         __get_user(desc, pdesc) )
65
0
        return 0;
66
0
67
0
    *sel = (desc.a >> 16) & 0x0000fffc;
68
0
    *off = (desc.a & 0x0000ffff) | (desc.b & 0xffff0000);
69
0
    *ar = desc.b & 0x0000ffff;
70
0
71
0
    /*
72
0
     * check_descriptor() clears the DPL field and stores the
73
0
     * guest requested DPL in the selector's RPL field.
74
0
     */
75
0
    if ( *ar & _SEGMENT_DPL )
76
0
        return 0;
77
0
    *ar |= (desc.a >> (16 - 13)) & _SEGMENT_DPL;
78
0
79
0
    if ( !is_pv_32bit_vcpu(v) )
80
0
    {
81
0
        if ( (*ar & 0x1f00) != 0x0c00 ||
82
0
             (gate_sel >= FIRST_RESERVED_GDT_BYTE - 8 && !(gate_sel & 4)) ||
83
0
             __get_user(desc, pdesc + 1) ||
84
0
             (desc.b & 0x1f00) )
85
0
            return 0;
86
0
87
0
        *off |= (unsigned long)desc.a << 32;
88
0
        return 1;
89
0
    }
90
0
91
0
    switch ( *ar & 0x1f00 )
92
0
    {
93
0
    case 0x0400:
94
0
        *off &= 0xffff;
95
0
        break;
96
0
    case 0x0c00:
97
0
        break;
98
0
    default:
99
0
        return 0;
100
0
    }
101
0
102
0
    return 1;
103
0
}
104
105
static inline bool check_stack_limit(unsigned int ar, unsigned int limit,
106
                                     unsigned int esp, unsigned int decr)
107
0
{
108
0
    return (((esp - decr) < (esp - 1)) &&
109
0
            (!(ar & _SEGMENT_EC) ? (esp - 1) <= limit : (esp - decr) > limit));
110
0
}
111
112
struct gate_op_ctxt {
113
    struct x86_emulate_ctxt ctxt;
114
    struct {
115
        unsigned long base, limit;
116
    } cs;
117
    bool insn_fetch;
118
};
119
120
static int read_mem(enum x86_segment seg, unsigned long offset, void *p_data,
121
                    unsigned int bytes, struct x86_emulate_ctxt *ctxt)
122
0
{
123
0
    const struct gate_op_ctxt *goc =
124
0
        container_of(ctxt, struct gate_op_ctxt, ctxt);
125
0
    unsigned int rc = bytes, sel = 0;
126
0
    unsigned long addr = offset, limit = 0;
127
0
128
0
    switch ( seg )
129
0
    {
130
0
    case x86_seg_cs:
131
0
        addr += goc->cs.base;
132
0
        limit = goc->cs.limit;
133
0
        break;
134
0
    case x86_seg_ds:
135
0
        sel = read_sreg(ds);
136
0
        break;
137
0
    case x86_seg_es:
138
0
        sel = read_sreg(es);
139
0
        break;
140
0
    case x86_seg_fs:
141
0
        sel = read_sreg(fs);
142
0
        break;
143
0
    case x86_seg_gs:
144
0
        sel = read_sreg(gs);
145
0
        break;
146
0
    case x86_seg_ss:
147
0
        sel = ctxt->regs->ss;
148
0
        break;
149
0
    default:
150
0
        return X86EMUL_UNHANDLEABLE;
151
0
    }
152
0
    if ( sel )
153
0
    {
154
0
        unsigned int ar;
155
0
156
0
        ASSERT(!goc->insn_fetch);
157
0
        if ( !pv_emul_read_descriptor(sel, current, &addr, &limit, &ar, 0) ||
158
0
             !(ar & _SEGMENT_S) ||
159
0
             !(ar & _SEGMENT_P) ||
160
0
             ((ar & _SEGMENT_CODE) && !(ar & _SEGMENT_WR)) )
161
0
            return X86EMUL_UNHANDLEABLE;
162
0
        addr += offset;
163
0
    }
164
0
    else if ( seg != x86_seg_cs )
165
0
        return X86EMUL_UNHANDLEABLE;
166
0
167
0
    /* We don't mean to emulate any branches. */
168
0
    if ( limit < bytes - 1 || offset > limit - bytes + 1 )
169
0
        return X86EMUL_UNHANDLEABLE;
170
0
171
0
    addr = (uint32_t)addr;
172
0
173
0
    if ( (rc = __copy_from_user(p_data, (void *)addr, bytes)) )
174
0
    {
175
0
        /*
176
0
         * TODO: This should report PFEC_insn_fetch when goc->insn_fetch &&
177
0
         * cpu_has_nx, but we'd then need a "fetch" variant of
178
0
         * __copy_from_user() respecting NX, SMEP, and protection keys.
179
0
         */
180
0
        x86_emul_pagefault(0, addr + bytes - rc, ctxt);
181
0
        return X86EMUL_EXCEPTION;
182
0
    }
183
0
184
0
    return X86EMUL_OKAY;
185
0
}
186
187
void pv_emulate_gate_op(struct cpu_user_regs *regs)
188
0
{
189
0
    struct vcpu *v = current;
190
0
    unsigned int sel, ar, dpl, nparm, insn_len;
191
0
    struct gate_op_ctxt ctxt = { .ctxt.regs = regs, .insn_fetch = true };
192
0
    struct x86_emulate_state *state;
193
0
    unsigned long off, base, limit;
194
0
    uint16_t opnd_sel = 0;
195
0
    int jump = -1, rc = X86EMUL_OKAY;
196
0
197
0
    /* Check whether this fault is due to the use of a call gate. */
198
0
    if ( !read_gate_descriptor(regs->error_code, v, &sel, &off, &ar) ||
199
0
         (((ar >> 13) & 3) < (regs->cs & 3)) ||
200
0
         ((ar & _SEGMENT_TYPE) != 0xc00) )
201
0
    {
202
0
        pv_inject_hw_exception(TRAP_gp_fault, regs->error_code);
203
0
        return;
204
0
    }
205
0
    if ( !(ar & _SEGMENT_P) )
206
0
    {
207
0
        pv_inject_hw_exception(TRAP_no_segment, regs->error_code);
208
0
        return;
209
0
    }
210
0
    dpl = (ar >> 13) & 3;
211
0
    nparm = ar & 0x1f;
212
0
213
0
    /*
214
0
     * Decode instruction (and perhaps operand) to determine RPL,
215
0
     * whether this is a jump or a call, and the call return offset.
216
0
     */
217
0
    if ( !pv_emul_read_descriptor(regs->cs, v, &ctxt.cs.base, &ctxt.cs.limit,
218
0
                                  &ar, 0) ||
219
0
         !(ar & _SEGMENT_S) ||
220
0
         !(ar & _SEGMENT_P) ||
221
0
         !(ar & _SEGMENT_CODE) )
222
0
    {
223
0
        pv_inject_hw_exception(TRAP_gp_fault, regs->error_code);
224
0
        return;
225
0
    }
226
0
227
0
    ctxt.ctxt.addr_size = ar & _SEGMENT_DB ? 32 : 16;
228
0
    /* Leave zero in ctxt.ctxt.sp_size, as it's not needed for decoding. */
229
0
    state = x86_decode_insn(&ctxt.ctxt, read_mem);
230
0
    ctxt.insn_fetch = false;
231
0
    if ( IS_ERR_OR_NULL(state) )
232
0
    {
233
0
        if ( PTR_ERR(state) == -X86EMUL_EXCEPTION )
234
0
            pv_inject_event(&ctxt.ctxt.event);
235
0
        else
236
0
            pv_inject_hw_exception(TRAP_gp_fault, regs->error_code);
237
0
        return;
238
0
    }
239
0
240
0
    switch ( ctxt.ctxt.opcode )
241
0
    {
242
0
        unsigned int modrm_345;
243
0
244
0
    case 0xea:
245
0
        ++jump;
246
0
        /* fall through */
247
0
    case 0x9a:
248
0
        ++jump;
249
0
        opnd_sel = x86_insn_immediate(state, 1);
250
0
        break;
251
0
    case 0xff:
252
0
        if ( x86_insn_modrm(state, NULL, &modrm_345) >= 3 )
253
0
            break;
254
0
        switch ( modrm_345 & 7 )
255
0
        {
256
0
            enum x86_segment seg;
257
0
258
0
        case 5:
259
0
            ++jump;
260
0
            /* fall through */
261
0
        case 3:
262
0
            ++jump;
263
0
            base = x86_insn_operand_ea(state, &seg);
264
0
            rc = read_mem(seg, base + (x86_insn_opsize(state) >> 3),
265
0
                          &opnd_sel, sizeof(opnd_sel), &ctxt.ctxt);
266
0
            break;
267
0
        }
268
0
        break;
269
0
    }
270
0
271
0
    insn_len = x86_insn_length(state, &ctxt.ctxt);
272
0
    x86_emulate_free_state(state);
273
0
274
0
    if ( rc == X86EMUL_EXCEPTION )
275
0
    {
276
0
        pv_inject_event(&ctxt.ctxt.event);
277
0
        return;
278
0
    }
279
0
280
0
    if ( rc != X86EMUL_OKAY ||
281
0
         jump < 0 ||
282
0
         (opnd_sel & ~3) != regs->error_code ||
283
0
         dpl < (opnd_sel & 3) )
284
0
    {
285
0
        pv_inject_hw_exception(TRAP_gp_fault, regs->error_code);
286
0
        return;
287
0
    }
288
0
289
0
    if ( !pv_emul_read_descriptor(sel, v, &base, &limit, &ar, 0) ||
290
0
         !(ar & _SEGMENT_S) ||
291
0
         !(ar & _SEGMENT_CODE) ||
292
0
         (!jump || (ar & _SEGMENT_EC) ?
293
0
          ((ar >> 13) & 3) > (regs->cs & 3) :
294
0
          ((ar >> 13) & 3) != (regs->cs & 3)) )
295
0
    {
296
0
        pv_inject_hw_exception(TRAP_gp_fault, sel);
297
0
        return;
298
0
    }
299
0
    if ( !(ar & _SEGMENT_P) )
300
0
    {
301
0
        pv_inject_hw_exception(TRAP_no_segment, sel);
302
0
        return;
303
0
    }
304
0
    if ( off > limit )
305
0
    {
306
0
        pv_inject_hw_exception(TRAP_gp_fault, 0);
307
0
        return;
308
0
    }
309
0
310
0
    if ( !jump )
311
0
    {
312
0
        unsigned int ss, esp, *stkp;
313
0
        int rc;
314
0
#define push(item) do \
315
0
        { \
316
0
            --stkp; \
317
0
            esp -= 4; \
318
0
            rc = __put_user(item, stkp); \
319
0
            if ( rc ) \
320
0
            { \
321
0
                pv_inject_page_fault(PFEC_write_access, \
322
0
                                     (unsigned long)(stkp + 1) - rc); \
323
0
                return; \
324
0
            } \
325
0
        } while ( 0 )
326
0
327
0
        if ( ((ar >> 13) & 3) < (regs->cs & 3) )
328
0
        {
329
0
            sel |= (ar >> 13) & 3;
330
0
            /* Inner stack known only for kernel ring. */
331
0
            if ( (sel & 3) != GUEST_KERNEL_RPL(v->domain) )
332
0
            {
333
0
                pv_inject_hw_exception(TRAP_gp_fault, regs->error_code);
334
0
                return;
335
0
            }
336
0
            esp = v->arch.pv_vcpu.kernel_sp;
337
0
            ss = v->arch.pv_vcpu.kernel_ss;
338
0
            if ( (ss & 3) != (sel & 3) ||
339
0
                 !pv_emul_read_descriptor(ss, v, &base, &limit, &ar, 0) ||
340
0
                 ((ar >> 13) & 3) != (sel & 3) ||
341
0
                 !(ar & _SEGMENT_S) ||
342
0
                 (ar & _SEGMENT_CODE) ||
343
0
                 !(ar & _SEGMENT_WR) )
344
0
            {
345
0
                pv_inject_hw_exception(TRAP_invalid_tss, ss & ~3);
346
0
                return;
347
0
            }
348
0
            if ( !(ar & _SEGMENT_P) ||
349
0
                 !check_stack_limit(ar, limit, esp, (4 + nparm) * 4) )
350
0
            {
351
0
                pv_inject_hw_exception(TRAP_stack_error, ss & ~3);
352
0
                return;
353
0
            }
354
0
            stkp = (unsigned int *)(unsigned long)((unsigned int)base + esp);
355
0
            if ( !compat_access_ok(stkp - 4 - nparm, 16 + nparm * 4) )
356
0
            {
357
0
                pv_inject_hw_exception(TRAP_gp_fault, regs->error_code);
358
0
                return;
359
0
            }
360
0
            push(regs->ss);
361
0
            push(regs->rsp);
362
0
            if ( nparm )
363
0
            {
364
0
                const unsigned int *ustkp;
365
0
366
0
                if ( !pv_emul_read_descriptor(regs->ss, v, &base,
367
0
                                              &limit, &ar, 0) ||
368
0
                     ((ar >> 13) & 3) != (regs->cs & 3) ||
369
0
                     !(ar & _SEGMENT_S) ||
370
0
                     (ar & _SEGMENT_CODE) ||
371
0
                     !(ar & _SEGMENT_WR) ||
372
0
                     !check_stack_limit(ar, limit, esp + nparm * 4, nparm * 4) )
373
0
                    return pv_inject_hw_exception(TRAP_gp_fault, regs->error_code);
374
0
                ustkp = (unsigned int *)(unsigned long)
375
0
                        ((unsigned int)base + regs->esp + nparm * 4);
376
0
                if ( !compat_access_ok(ustkp - nparm, 0 + nparm * 4) )
377
0
                {
378
0
                    pv_inject_hw_exception(TRAP_gp_fault, regs->error_code);
379
0
                    return;
380
0
                }
381
0
                do
382
0
                {
383
0
                    unsigned int parm;
384
0
385
0
                    --ustkp;
386
0
                    rc = __get_user(parm, ustkp);
387
0
                    if ( rc )
388
0
                    {
389
0
                        pv_inject_page_fault(0, (unsigned long)(ustkp + 1) - rc);
390
0
                        return;
391
0
                    }
392
0
                    push(parm);
393
0
                } while ( --nparm );
394
0
            }
395
0
        }
396
0
        else
397
0
        {
398
0
            sel |= (regs->cs & 3);
399
0
            esp = regs->rsp;
400
0
            ss = regs->ss;
401
0
            if ( !pv_emul_read_descriptor(ss, v, &base, &limit, &ar, 0) ||
402
0
                 ((ar >> 13) & 3) != (sel & 3) )
403
0
            {
404
0
                pv_inject_hw_exception(TRAP_gp_fault, regs->error_code);
405
0
                return;
406
0
            }
407
0
            if ( !check_stack_limit(ar, limit, esp, 2 * 4) )
408
0
            {
409
0
                pv_inject_hw_exception(TRAP_stack_error, 0);
410
0
                return;
411
0
            }
412
0
            stkp = (unsigned int *)(unsigned long)((unsigned int)base + esp);
413
0
            if ( !compat_access_ok(stkp - 2, 2 * 4) )
414
0
            {
415
0
                pv_inject_hw_exception(TRAP_gp_fault, regs->error_code);
416
0
                return;
417
0
            }
418
0
        }
419
0
        push(regs->cs);
420
0
        push(regs->rip + insn_len);
421
0
#undef push
422
0
        regs->rsp = esp;
423
0
        regs->ss = ss;
424
0
    }
425
0
    else
426
0
        sel |= (regs->cs & 3);
427
0
428
0
    regs->cs = sel;
429
0
    pv_emul_instruction_done(regs, off);
430
0
}
431
432
/*
433
 * Local variables:
434
 * mode: C
435
 * c-file-style: "BSD"
436
 * c-basic-offset: 4
437
 * tab-width: 4
438
 * indent-tabs-mode: nil
439
 * End:
440
 */