Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/arch/x86/hvm/hypercall.c
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 * arch/hvm/hypercall.c
3
 *
4
 * HVM hypercall dispatching routines
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 * Copyright (c) 2017 Citrix Systems Ltd.
20
 */
21
#include <xen/lib.h>
22
#include <xen/hypercall.h>
23
24
#include <asm/hvm/support.h>
25
26
static long hvm_memory_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
27
4
{
28
4
    const struct vcpu *curr = current;
29
4
    long rc;
30
4
31
4
    switch ( cmd & MEMOP_CMD_MASK )
32
4
    {
33
0
    case XENMEM_machine_memory_map:
34
0
    case XENMEM_machphys_mapping:
35
0
        return -ENOSYS;
36
4
    }
37
4
38
4
    if ( !curr->hcall_compat )
39
4
        rc = do_memory_op(cmd, arg);
40
4
    else
41
0
        rc = compat_memory_op(cmd, arg);
42
4
43
4
    if ( (cmd & MEMOP_CMD_MASK) == XENMEM_decrease_reservation )
44
0
        curr->domain->arch.hvm_domain.qemu_mapcache_invalidate = true;
45
4
46
4
    return rc;
47
4
}
48
49
static long hvm_grant_table_op(
50
    unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) uop, unsigned int count)
51
3
{
52
3
    switch ( cmd )
53
3
    {
54
3
    case GNTTABOP_query_size:
55
3
    case GNTTABOP_setup_table:
56
3
    case GNTTABOP_set_version:
57
3
    case GNTTABOP_get_version:
58
3
    case GNTTABOP_copy:
59
3
    case GNTTABOP_map_grant_ref:
60
3
    case GNTTABOP_unmap_grant_ref:
61
3
    case GNTTABOP_swap_grant_ref:
62
3
        break;
63
3
64
0
    default: /* All other commands need auditing. */
65
0
        return -ENOSYS;
66
3
    }
67
3
68
3
    if ( !current->hcall_compat )
69
3
        return do_grant_table_op(cmd, uop, count);
70
3
    else
71
0
        return compat_grant_table_op(cmd, uop, count);
72
3
}
73
74
static long hvm_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
75
69
{
76
69
    const struct vcpu *curr = current;
77
69
78
69
    switch ( cmd )
79
69
    {
80
69
    default:
81
69
        if ( !is_hardware_domain(curr->domain) )
82
0
            return -ENOSYS;
83
69
        /* fall through */
84
69
    case PHYSDEVOP_map_pirq:
85
69
    case PHYSDEVOP_unmap_pirq:
86
69
    case PHYSDEVOP_eoi:
87
69
    case PHYSDEVOP_irq_status_query:
88
69
    case PHYSDEVOP_get_free_pirq:
89
69
        if ( !has_pirq(curr->domain) )
90
69
            return -ENOSYS;
91
0
        break;
92
0
    case PHYSDEVOP_pci_mmcfg_reserved:
93
0
        if ( !has_vpci(curr->domain) )
94
0
            return -ENOSYS;
95
0
        break;
96
69
    }
97
69
98
0
    if ( !curr->hcall_compat )
99
0
        return do_physdev_op(cmd, arg);
100
0
    else
101
0
        return compat_physdev_op(cmd, arg);
102
0
}
103
104
#define HYPERCALL(x)                                         \
105
    [ __HYPERVISOR_ ## x ] = { (hypercall_fn_t *) do_ ## x,  \
106
                               (hypercall_fn_t *) do_ ## x }
107
108
#define HVM_CALL(x)                                          \
109
    [ __HYPERVISOR_ ## x ] = { (hypercall_fn_t *) hvm_ ## x, \
110
                               (hypercall_fn_t *) hvm_ ## x }
111
112
#define COMPAT_CALL(x)                                       \
113
    [ __HYPERVISOR_ ## x ] = { (hypercall_fn_t *) do_ ## x,  \
114
                               (hypercall_fn_t *) compat_ ## x }
115
116
#define do_arch_1             paging_domctl_continuation
117
118
static const hypercall_table_t hvm_hypercall_table[] = {
119
    HVM_CALL(memory_op),
120
    HVM_CALL(grant_table_op),
121
    COMPAT_CALL(vcpu_op),
122
    HVM_CALL(physdev_op),
123
    COMPAT_CALL(xen_version),
124
    HYPERCALL(console_io),
125
    HYPERCALL(event_channel_op),
126
    COMPAT_CALL(sched_op),
127
    COMPAT_CALL(set_timer_op),
128
    HYPERCALL(xsm_op),
129
    HYPERCALL(hvm_op),
130
    HYPERCALL(sysctl),
131
    HYPERCALL(domctl),
132
#ifdef CONFIG_TMEM
133
    HYPERCALL(tmem_op),
134
#endif
135
    COMPAT_CALL(platform_op),
136
    COMPAT_CALL(mmuext_op),
137
    HYPERCALL(xenpmu_op),
138
    COMPAT_CALL(dm_op),
139
    HYPERCALL(arch_1)
140
};
141
142
#undef do_arch_1
143
144
#undef HYPERCALL
145
#undef HVM_CALL
146
#undef COMPAT_CALL
147
148
int hvm_hypercall(struct cpu_user_regs *regs)
149
304k
{
150
304k
    struct vcpu *curr = current;
151
304k
    struct domain *currd = curr->domain;
152
304k
    int mode = hvm_guest_x86_mode(curr);
153
304k
    unsigned long eax = regs->eax;
154
304k
155
304k
    switch ( mode )
156
304k
    {
157
305k
    case 8:
158
305k
        eax = regs->rax;
159
305k
        /* Fallthrough to permission check. */
160
305k
    case 4:
161
305k
    case 2:
162
305k
        if ( currd->arch.monitor.guest_request_userspace_enabled &&
163
0
            eax == __HYPERVISOR_hvm_op &&
164
0
            (mode == 8 ? regs->rdi : regs->ebx) == HVMOP_guest_request_vm_event )
165
0
            break;
166
305k
167
305k
        if ( unlikely(hvm_get_cpl(curr)) )
168
0
        {
169
0
    default:
170
0
            regs->rax = -EPERM;
171
0
            return HVM_HCALL_completed;
172
0
        }
173
305k
    case 0:
174
305k
        break;
175
304k
    }
176
304k
177
304k
    if ( (eax & 0x80000000) && is_viridian_domain(currd) )
178
0
        return viridian_hypercall(regs);
179
304k
180
304k
    BUILD_BUG_ON(ARRAY_SIZE(hvm_hypercall_table) >
181
304k
                 ARRAY_SIZE(hypercall_args_table));
182
304k
183
304k
    if ( (eax >= ARRAY_SIZE(hvm_hypercall_table)) ||
184
304k
         !hvm_hypercall_table[eax].native )
185
69
    {
186
69
        regs->rax = -ENOSYS;
187
69
        return HVM_HCALL_completed;
188
69
    }
189
304k
190
304k
    curr->hcall_preempted = false;
191
304k
192
304k
    if ( mode == 8 )
193
304k
    {
194
304k
        unsigned long rdi = regs->rdi;
195
304k
        unsigned long rsi = regs->rsi;
196
304k
        unsigned long rdx = regs->rdx;
197
304k
        unsigned long r10 = regs->r10;
198
304k
        unsigned long r8 = regs->r8;
199
304k
        unsigned long r9 = regs->r9;
200
304k
201
304k
        HVM_DBG_LOG(DBG_LEVEL_HCALL, "hcall%lu(%lx, %lx, %lx, %lx, %lx, %lx)",
202
304k
                    eax, rdi, rsi, rdx, r10, r8, r9);
203
304k
204
304k
#ifndef NDEBUG
205
304k
        /* Deliberately corrupt parameter regs not used by this hypercall. */
206
304k
        switch ( hypercall_args_table[eax].native )
207
304k
        {
208
0
        case 0: rdi = 0xdeadbeefdeadf00dUL;
209
12
        case 1: rsi = 0xdeadbeefdeadf00dUL;
210
94.7k
        case 2: rdx = 0xdeadbeefdeadf00dUL;
211
305k
        case 3: r10 = 0xdeadbeefdeadf00dUL;
212
305k
        case 4: r8 = 0xdeadbeefdeadf00dUL;
213
305k
        case 5: r9 = 0xdeadbeefdeadf00dUL;
214
304k
        }
215
304k
#endif
216
304k
217
304k
        regs->rax = hvm_hypercall_table[eax].native(rdi, rsi, rdx, r10, r8,
218
304k
                                                    r9);
219
304k
220
304k
#ifndef NDEBUG
221
304k
        if ( !curr->hcall_preempted )
222
304k
        {
223
304k
            /* Deliberately corrupt parameter regs used by this hypercall. */
224
304k
            switch ( hypercall_args_table[eax].native )
225
304k
            {
226
0
            case 6: regs->r9  = 0xdeadbeefdeadf00dUL;
227
0
            case 5: regs->r8  = 0xdeadbeefdeadf00dUL;
228
0
            case 4: regs->r10 = 0xdeadbeefdeadf00dUL;
229
209k
            case 3: regs->rdx = 0xdeadbeefdeadf00dUL;
230
304k
            case 2: regs->rsi = 0xdeadbeefdeadf00dUL;
231
304k
            case 1: regs->rdi = 0xdeadbeefdeadf00dUL;
232
304k
            }
233
304k
        }
234
304k
#endif
235
304k
    }
236
304k
    else
237
293
    {
238
293
        unsigned int ebx = regs->ebx;
239
293
        unsigned int ecx = regs->ecx;
240
293
        unsigned int edx = regs->edx;
241
293
        unsigned int esi = regs->esi;
242
293
        unsigned int edi = regs->edi;
243
293
        unsigned int ebp = regs->ebp;
244
293
245
293
        HVM_DBG_LOG(DBG_LEVEL_HCALL, "hcall%lu(%x, %x, %x, %x, %x, %x)", eax,
246
293
                    ebx, ecx, edx, esi, edi, ebp);
247
293
248
293
#ifndef NDEBUG
249
293
        /* Deliberately corrupt parameter regs not used by this hypercall. */
250
293
        switch ( hypercall_args_table[eax].compat )
251
293
        {
252
0
        case 0: ebx = 0xdeadf00d;
253
0
        case 1: ecx = 0xdeadf00d;
254
0
        case 2: edx = 0xdeadf00d;
255
0
        case 3: esi = 0xdeadf00d;
256
0
        case 4: edi = 0xdeadf00d;
257
0
        case 5: ebp = 0xdeadf00d;
258
293
        }
259
293
#endif
260
293
261
0
        curr->hcall_compat = true;
262
0
        regs->rax = hvm_hypercall_table[eax].compat(ebx, ecx, edx, esi, edi,
263
0
                                                    ebp);
264
0
        curr->hcall_compat = false;
265
0
266
0
#ifndef NDEBUG
267
0
        if ( !curr->hcall_preempted )
268
0
        {
269
0
            /* Deliberately corrupt parameter regs used by this hypercall. */
270
0
            switch ( hypercall_args_table[eax].compat )
271
0
            {
272
0
            case 6: regs->rbp = 0xdeadf00d;
273
0
            case 5: regs->rdi = 0xdeadf00d;
274
0
            case 4: regs->rsi = 0xdeadf00d;
275
0
            case 3: regs->rdx = 0xdeadf00d;
276
0
            case 2: regs->rcx = 0xdeadf00d;
277
0
            case 1: regs->rbx = 0xdeadf00d;
278
0
            }
279
0
        }
280
0
#endif
281
0
    }
282
304k
283
304k
    HVM_DBG_LOG(DBG_LEVEL_HCALL, "hcall%lu -> %lx", eax, regs->rax);
284
304k
285
304k
    if ( curr->hcall_preempted )
286
0
        return HVM_HCALL_preempted;
287
304k
288
304k
    if ( unlikely(currd->arch.hvm_domain.qemu_mapcache_invalidate) &&
289
0
         test_and_clear_bool(currd->arch.hvm_domain.qemu_mapcache_invalidate) )
290
0
        send_invalidate_req();
291
304k
292
304k
    return HVM_HCALL_completed;
293
304k
}
294
295
/*
296
 * Local variables:
297
 * mode: C
298
 * c-file-style: "BSD"
299
 * c-basic-offset: 4
300
 * tab-width: 4
301
 * indent-tabs-mode: nil
302
 * End:
303
 */