Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/common/compat/grant_table.c
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 * common/compat/grant_table.c
3
 *
4
 */
5
6
#include <compat/grant_table.h>
7
8
#define xen_grant_entry_v1 grant_entry_v1
9
CHECK_grant_entry_v1;
10
#undef xen_grant_entry_v1
11
12
#define xen_grant_entry_header grant_entry_header
13
CHECK_grant_entry_header;
14
#undef xen_grant_entry_header
15
16
#define xen_grant_entry_v2 grant_entry_v2
17
CHECK_grant_entry_v2;
18
#undef xen_grant_entry_v2
19
20
#define xen_gnttab_map_grant_ref gnttab_map_grant_ref
21
CHECK_gnttab_map_grant_ref;
22
#undef xen_gnttab_map_grant_ref
23
24
#define xen_gnttab_unmap_grant_ref gnttab_unmap_grant_ref
25
CHECK_gnttab_unmap_grant_ref;
26
#undef xen_gnttab_unmap_grant_ref
27
28
#define xen_gnttab_unmap_and_replace gnttab_unmap_and_replace
29
CHECK_gnttab_unmap_and_replace;
30
#undef xen_gnttab_unmap_and_replace
31
32
DEFINE_XEN_GUEST_HANDLE(gnttab_setup_table_compat_t);
33
DEFINE_XEN_GUEST_HANDLE(gnttab_transfer_compat_t);
34
DEFINE_XEN_GUEST_HANDLE(gnttab_copy_compat_t);
35
36
#define xen_gnttab_dump_table gnttab_dump_table
37
CHECK_gnttab_dump_table;
38
#undef xen_gnttab_dump_table
39
40
#define xen_gnttab_set_version gnttab_set_version
41
CHECK_gnttab_set_version;
42
#undef xen_gnttab_set_version
43
44
DEFINE_XEN_GUEST_HANDLE(gnttab_get_status_frames_compat_t);
45
46
#define xen_gnttab_get_version gnttab_get_version
47
CHECK_gnttab_get_version;
48
#undef xen_gnttab_get_version
49
50
#define xen_gnttab_swap_grant_ref gnttab_swap_grant_ref
51
CHECK_gnttab_swap_grant_ref;
52
#undef xen_gnttab_swap_grant_ref
53
54
#define xen_gnttab_cache_flush gnttab_cache_flush
55
CHECK_gnttab_cache_flush;
56
#undef xen_gnttab_cache_flush
57
58
int compat_grant_table_op(unsigned int cmd,
59
                          XEN_GUEST_HANDLE_PARAM(void) cmp_uop,
60
                          unsigned int count)
61
0
{
62
0
    int rc = 0;
63
0
    unsigned int i, cmd_op;
64
0
    XEN_GUEST_HANDLE_PARAM(void) cnt_uop;
65
0
66
0
    set_xen_guest_handle(cnt_uop, NULL);
67
0
    cmd_op = cmd & GNTTABOP_CMD_MASK;
68
0
    if ( cmd_op != GNTTABOP_cache_flush )
69
0
        cmd_op = cmd;
70
0
    switch ( cmd_op )
71
0
    {
72
0
#define CASE(name) \
73
0
    case GNTTABOP_##name: \
74
0
        if ( unlikely(!guest_handle_okay(guest_handle_cast(cmp_uop, \
75
0
                                                           gnttab_##name##_compat_t), \
76
0
                                         count)) ) \
77
0
            rc = -EFAULT; \
78
0
        break
79
0
80
0
#ifndef CHECK_gnttab_map_grant_ref
81
    CASE(map_grant_ref);
82
#endif
83
0
84
0
#ifndef CHECK_gnttab_unmap_grant_ref
85
    CASE(unmap_grant_ref);
86
#endif
87
0
88
0
#ifndef CHECK_gnttab_unmap_and_replace
89
    CASE(unmap_and_replace);
90
#endif
91
0
92
0
#ifndef CHECK_gnttab_setup_table
93
0
    CASE(setup_table);
94
0
#endif
95
0
96
0
#ifndef CHECK_gnttab_transfer
97
0
    CASE(transfer);
98
0
#endif
99
0
100
0
#ifndef CHECK_gnttab_copy
101
0
    CASE(copy);
102
0
#endif
103
0
104
0
#ifndef CHECK_gnttab_dump_table
105
    CASE(dump_table);
106
#endif
107
0
108
0
#ifndef CHECK_gnttab_get_status_frames
109
0
    CASE(get_status_frames);
110
0
#endif
111
0
112
0
#ifndef CHECK_gnttab_swap_grant_ref
113
    CASE(swap_grant_ref);
114
#endif
115
0
116
0
#ifndef CHECK_gnttab_cache_flush
117
    CASE(cache_flush);
118
#endif
119
0
120
0
#undef CASE
121
0
    default:
122
0
        return do_grant_table_op(cmd, cmp_uop, count);
123
0
    }
124
0
125
0
    if ( (int)count < 0 )
126
0
        rc = -EINVAL;
127
0
128
0
    for ( i = 0; i < count && rc == 0; )
129
0
    {
130
0
        unsigned int n;
131
0
        union {
132
0
            XEN_GUEST_HANDLE(void) uop;
133
0
            struct gnttab_setup_table *setup;
134
0
            struct gnttab_transfer *xfer;
135
0
            struct gnttab_copy *copy;
136
0
            struct gnttab_get_status_frames *get_status;
137
0
        } nat;
138
0
        union {
139
0
            struct compat_gnttab_setup_table setup;
140
0
            struct compat_gnttab_transfer xfer;
141
0
            struct compat_gnttab_copy copy;
142
0
            struct compat_gnttab_get_status_frames get_status;
143
0
        } cmp;
144
0
145
0
        set_xen_guest_handle(nat.uop, COMPAT_ARG_XLAT_VIRT_BASE);
146
0
        switch ( cmd_op )
147
0
        {
148
0
        case GNTTABOP_setup_table:
149
0
            if ( unlikely(count > 1) )
150
0
                rc = -EINVAL;
151
0
            else if ( unlikely(__copy_from_guest(&cmp.setup, cmp_uop, 1)) )
152
0
                rc = -EFAULT;
153
0
            else if ( unlikely(!compat_handle_okay(cmp.setup.frame_list, cmp.setup.nr_frames)) )
154
0
                rc = -EFAULT;
155
0
            else
156
0
            {
157
0
                unsigned int max_frame_list_size_in_page =
158
0
                    (COMPAT_ARG_XLAT_SIZE - sizeof(*nat.setup)) /
159
0
                    sizeof(*nat.setup->frame_list.p);
160
0
161
0
#define XLAT_gnttab_setup_table_HNDL_frame_list(_d_, _s_) \
162
0
                set_xen_guest_handle((_d_)->frame_list, (unsigned long *)(nat.setup + 1))
163
0
                XLAT_gnttab_setup_table(nat.setup, &cmp.setup);
164
0
#undef XLAT_gnttab_setup_table_HNDL_frame_list
165
0
                rc = gnttab_setup_table(guest_handle_cast(nat.uop,
166
0
                                                          gnttab_setup_table_t),
167
0
                                        1, max_frame_list_size_in_page);
168
0
            }
169
0
            ASSERT(rc <= 0);
170
0
            if ( rc == 0 )
171
0
            {
172
0
#define XLAT_gnttab_setup_table_HNDL_frame_list(_d_, _s_) \
173
0
                do \
174
0
                { \
175
0
                    if ( (_s_)->status == GNTST_okay ) \
176
0
                    { \
177
0
                        for ( i = 0; i < (_s_)->nr_frames; ++i ) \
178
0
                        { \
179
0
                            unsigned int frame = (_s_)->frame_list.p[i]; \
180
0
                            if ( __copy_to_compat_offset((_d_)->frame_list, \
181
0
                                                         i, &frame, 1) ) \
182
0
                                (_s_)->status = GNTST_bad_virt_addr; \
183
0
                        } \
184
0
                    } \
185
0
                } while (0)
186
0
                XLAT_gnttab_setup_table(&cmp.setup, nat.setup);
187
0
#undef XLAT_gnttab_setup_table_HNDL_frame_list
188
0
                if ( unlikely(__copy_to_guest(cmp_uop, &cmp.setup, 1)) )
189
0
                    rc = -EFAULT;
190
0
                else
191
0
                    i = 1;
192
0
            }
193
0
            break;
194
0
195
0
        case GNTTABOP_transfer:
196
0
            for ( n = 0; n < COMPAT_ARG_XLAT_SIZE / sizeof(*nat.xfer) && i < count && rc == 0; ++i, ++n )
197
0
            {
198
0
                if ( unlikely(__copy_from_guest_offset(&cmp.xfer, cmp_uop, i, 1)) )
199
0
                    rc = -EFAULT;
200
0
                else
201
0
                {
202
0
                    XLAT_gnttab_transfer(nat.xfer + n, &cmp.xfer);
203
0
                }
204
0
            }
205
0
            if ( rc == 0 )
206
0
                rc = gnttab_transfer(guest_handle_cast(nat.uop, gnttab_transfer_t), n);
207
0
            if ( rc > 0 )
208
0
            {
209
0
                ASSERT(rc < n);
210
0
                i -= n - rc;
211
0
                n = rc;
212
0
            }
213
0
            if ( rc >= 0 )
214
0
            {
215
0
                XEN_GUEST_HANDLE_PARAM(gnttab_transfer_compat_t) xfer;
216
0
217
0
                xfer = guest_handle_cast(cmp_uop, gnttab_transfer_compat_t);
218
0
                guest_handle_add_offset(xfer, i);
219
0
                cnt_uop = guest_handle_cast(xfer, void);
220
0
                while ( n-- )
221
0
                {
222
0
                    guest_handle_add_offset(xfer, -1);
223
0
                    if ( __copy_field_to_guest(xfer, nat.xfer + n, status) )
224
0
                        rc = -EFAULT;
225
0
                }
226
0
            }
227
0
            break;
228
0
229
0
        case GNTTABOP_copy:
230
0
            for ( n = 0; n < COMPAT_ARG_XLAT_SIZE / sizeof(*nat.copy) && i < count && rc == 0; ++i, ++n )
231
0
            {
232
0
                if ( unlikely(__copy_from_guest_offset(&cmp.copy, cmp_uop, i, 1)) )
233
0
                    rc = -EFAULT;
234
0
                else
235
0
                {
236
0
                    enum XLAT_gnttab_copy_source_u source_u;
237
0
                    enum XLAT_gnttab_copy_dest_u dest_u;
238
0
239
0
                    if ( cmp.copy.flags & GNTCOPY_source_gref )
240
0
                        source_u = XLAT_gnttab_copy_source_u_ref;
241
0
                    else
242
0
                        source_u = XLAT_gnttab_copy_source_u_gmfn;
243
0
                    if ( cmp.copy.flags & GNTCOPY_dest_gref )
244
0
                        dest_u = XLAT_gnttab_copy_dest_u_ref;
245
0
                    else
246
0
                        dest_u = XLAT_gnttab_copy_dest_u_gmfn;
247
0
                    XLAT_gnttab_copy(nat.copy + n, &cmp.copy);
248
0
                }
249
0
            }
250
0
            if ( rc == 0 )
251
0
                rc = gnttab_copy(guest_handle_cast(nat.uop, gnttab_copy_t), n);
252
0
            if ( rc > 0 )
253
0
            {
254
0
                ASSERT(rc <= n);
255
0
                i -= rc;
256
0
                n -= rc;
257
0
            }
258
0
            if ( rc >= 0 )
259
0
            {
260
0
                XEN_GUEST_HANDLE_PARAM(gnttab_copy_compat_t) copy;
261
0
262
0
                copy = guest_handle_cast(cmp_uop, gnttab_copy_compat_t);
263
0
                guest_handle_add_offset(copy, i);
264
0
                cnt_uop = guest_handle_cast(copy, void);
265
0
                while ( n-- )
266
0
                {
267
0
                    guest_handle_add_offset(copy, -1);
268
0
                    if ( __copy_field_to_guest(copy, nat.copy + n, status) )
269
0
                        rc = -EFAULT;
270
0
                }
271
0
            }
272
0
            break;
273
0
274
0
        case GNTTABOP_get_status_frames: {
275
0
            unsigned int max_frame_list_size_in_pages =
276
0
                (COMPAT_ARG_XLAT_SIZE - sizeof(*nat.get_status)) /
277
0
                sizeof(*nat.get_status->frame_list.p);
278
0
            if ( count != 1)
279
0
            {
280
0
                rc = -EINVAL;
281
0
                break;
282
0
            }
283
0
            if ( unlikely(__copy_from_guest(&cmp.get_status, cmp_uop, 1) ||
284
0
                          !compat_handle_okay(cmp.get_status.frame_list,
285
0
                                              cmp.get_status.nr_frames)) )
286
0
            {
287
0
                rc = -EFAULT;
288
0
                break;
289
0
            }
290
0
291
0
#define XLAT_gnttab_get_status_frames_HNDL_frame_list(_d_, _s_) \
292
0
            set_xen_guest_handle((_d_)->frame_list, (uint64_t *)(nat.get_status + 1))
293
0
            XLAT_gnttab_get_status_frames(nat.get_status, &cmp.get_status);
294
0
#undef XLAT_gnttab_get_status_frames_HNDL_frame_list
295
0
296
0
            rc = gnttab_get_status_frames(
297
0
                guest_handle_cast(nat.uop, gnttab_get_status_frames_t),
298
0
                count, max_frame_list_size_in_pages);
299
0
            if ( rc >= 0 )
300
0
            {
301
0
#define XLAT_gnttab_get_status_frames_HNDL_frame_list(_d_, _s_) \
302
0
                do \
303
0
                { \
304
0
                    if ( (_s_)->status == GNTST_okay ) \
305
0
                    { \
306
0
                        for ( i = 0; i < (_s_)->nr_frames; ++i ) \
307
0
                        { \
308
0
                            uint64_t frame = (_s_)->frame_list.p[i]; \
309
0
                            if ( __copy_to_compat_offset((_d_)->frame_list, \
310
0
                                                         i, &frame, 1) ) \
311
0
                                (_s_)->status = GNTST_bad_virt_addr; \
312
0
                        } \
313
0
                    } \
314
0
                } while (0)
315
0
                XLAT_gnttab_get_status_frames(&cmp.get_status, nat.get_status);
316
0
#undef XLAT_gnttab_get_status_frames_HNDL_frame_list
317
0
                if ( unlikely(__copy_to_guest(cmp_uop, &cmp.get_status, 1)) )
318
0
                    rc = -EFAULT;
319
0
                else
320
0
                    i = 1;
321
0
            }
322
0
            break;
323
0
        }
324
0
325
0
        default:
326
0
            domain_crash(current->domain);
327
0
            break;
328
0
        }
329
0
    }
330
0
331
0
    if ( rc > 0 )
332
0
    {
333
0
        ASSERT(i < count);
334
0
        ASSERT(!guest_handle_is_null(cnt_uop));
335
0
        rc = hypercall_create_continuation(__HYPERVISOR_grant_table_op,
336
0
                                           "ihi", cmd, cnt_uop, count - i);
337
0
    }
338
0
339
0
    return rc;
340
0
}
341
342
/*
343
 * Local variables:
344
 * mode: C
345
 * c-file-style: "BSD"
346
 * c-basic-offset: 4
347
 * tab-width: 4
348
 * indent-tabs-mode: nil
349
 * End:
350
 */