]> Git Repo - qemu.git/blob - tests/test-vmstate.c
qcow1: Validate image size (CVE-2014-0223)
[qemu.git] / tests / test-vmstate.c
1 /*
2  *  Test code for VMState
3  *
4  *  Copyright (c) 2013 Red Hat Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24
25 #include <glib.h>
26
27 #include "qemu-common.h"
28 #include "migration/migration.h"
29 #include "migration/vmstate.h"
30 #include "block/coroutine.h"
31
32 char temp_file[] = "/tmp/vmst.test.XXXXXX";
33 int temp_fd;
34
35 /* Fake yield_until_fd_readable() implementation so we don't have to pull the
36  * coroutine code as dependency.
37  */
38 void yield_until_fd_readable(int fd)
39 {
40     fd_set fds;
41     FD_ZERO(&fds);
42     FD_SET(fd, &fds);
43     select(fd + 1, &fds, NULL, NULL, NULL);
44 }
45
46 /* Duplicate temp_fd and seek to the beginning of the file */
47 static int dup_temp_fd(bool truncate)
48 {
49     int fd = dup(temp_fd);
50     lseek(fd, 0, SEEK_SET);
51     if (truncate) {
52         g_assert_cmpint(ftruncate(fd, 0), ==, 0);
53     }
54     return fd;
55 }
56
57 typedef struct TestSruct {
58     uint32_t a, b, c, e;
59     uint64_t d, f;
60     bool skip_c_e;
61 } TestStruct;
62
63
64 static const VMStateDescription vmstate_simple = {
65     .name = "test",
66     .version_id = 1,
67     .minimum_version_id = 1,
68     .fields = (VMStateField[]) {
69         VMSTATE_UINT32(a, TestStruct),
70         VMSTATE_UINT32(b, TestStruct),
71         VMSTATE_UINT32(c, TestStruct),
72         VMSTATE_UINT64(d, TestStruct),
73         VMSTATE_END_OF_LIST()
74     }
75 };
76
77 static void test_simple_save(void)
78 {
79     QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
80     TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4 };
81     vmstate_save_state(fsave, &vmstate_simple, &obj);
82     g_assert(!qemu_file_get_error(fsave));
83     qemu_fclose(fsave);
84
85     QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
86     uint8_t expected[] = {
87         0, 0, 0, 1, /* a */
88         0, 0, 0, 2, /* b */
89         0, 0, 0, 3, /* c */
90         0, 0, 0, 0, 0, 0, 0, 4, /* d */
91     };
92     uint8_t result[sizeof(expected)];
93     g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==,
94                     sizeof(result));
95     g_assert(!qemu_file_get_error(loading));
96     g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0);
97
98     /* Must reach EOF */
99     qemu_get_byte(loading);
100     g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
101
102     qemu_fclose(loading);
103 }
104
105 static void test_simple_load(void)
106 {
107     QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
108     uint8_t buf[] = {
109         0, 0, 0, 10,             /* a */
110         0, 0, 0, 20,             /* b */
111         0, 0, 0, 30,             /* c */
112         0, 0, 0, 0, 0, 0, 0, 40, /* d */
113         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
114     };
115     qemu_put_buffer(fsave, buf, sizeof(buf));
116     qemu_fclose(fsave);
117
118     QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
119     TestStruct obj;
120     vmstate_load_state(loading, &vmstate_simple, &obj, 1);
121     g_assert(!qemu_file_get_error(loading));
122     g_assert_cmpint(obj.a, ==, 10);
123     g_assert_cmpint(obj.b, ==, 20);
124     g_assert_cmpint(obj.c, ==, 30);
125     g_assert_cmpint(obj.d, ==, 40);
126     qemu_fclose(loading);
127 }
128
129 static const VMStateDescription vmstate_versioned = {
130     .name = "test",
131     .version_id = 2,
132     .minimum_version_id = 1,
133     .fields = (VMStateField[]) {
134         VMSTATE_UINT32(a, TestStruct),
135         VMSTATE_UINT32_V(b, TestStruct, 2), /* Versioned field in the middle, so
136                                              * we catch bugs more easily.
137                                              */
138         VMSTATE_UINT32(c, TestStruct),
139         VMSTATE_UINT64(d, TestStruct),
140         VMSTATE_UINT32_V(e, TestStruct, 2),
141         VMSTATE_UINT64_V(f, TestStruct, 2),
142         VMSTATE_END_OF_LIST()
143     }
144 };
145
146 static void test_load_v1(void)
147 {
148     QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
149     uint8_t buf[] = {
150         0, 0, 0, 10,             /* a */
151         0, 0, 0, 30,             /* c */
152         0, 0, 0, 0, 0, 0, 0, 40, /* d */
153         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
154     };
155     qemu_put_buffer(fsave, buf, sizeof(buf));
156     qemu_fclose(fsave);
157
158     QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
159     TestStruct obj = { .b = 200, .e = 500, .f = 600 };
160     vmstate_load_state(loading, &vmstate_versioned, &obj, 1);
161     g_assert(!qemu_file_get_error(loading));
162     g_assert_cmpint(obj.a, ==, 10);
163     g_assert_cmpint(obj.b, ==, 200);
164     g_assert_cmpint(obj.c, ==, 30);
165     g_assert_cmpint(obj.d, ==, 40);
166     g_assert_cmpint(obj.e, ==, 500);
167     g_assert_cmpint(obj.f, ==, 600);
168     qemu_fclose(loading);
169 }
170
171 static void test_load_v2(void)
172 {
173     QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
174     uint8_t buf[] = {
175         0, 0, 0, 10,             /* a */
176         0, 0, 0, 20,             /* b */
177         0, 0, 0, 30,             /* c */
178         0, 0, 0, 0, 0, 0, 0, 40, /* d */
179         0, 0, 0, 50,             /* e */
180         0, 0, 0, 0, 0, 0, 0, 60, /* f */
181         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
182     };
183     qemu_put_buffer(fsave, buf, sizeof(buf));
184     qemu_fclose(fsave);
185
186     QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
187     TestStruct obj;
188     vmstate_load_state(loading, &vmstate_versioned, &obj, 2);
189     g_assert_cmpint(obj.a, ==, 10);
190     g_assert_cmpint(obj.b, ==, 20);
191     g_assert_cmpint(obj.c, ==, 30);
192     g_assert_cmpint(obj.d, ==, 40);
193     g_assert_cmpint(obj.e, ==, 50);
194     g_assert_cmpint(obj.f, ==, 60);
195     qemu_fclose(loading);
196 }
197
198 static bool test_skip(void *opaque, int version_id)
199 {
200     TestStruct *t = (TestStruct *)opaque;
201     return !t->skip_c_e;
202 }
203
204 static const VMStateDescription vmstate_skipping = {
205     .name = "test",
206     .version_id = 2,
207     .minimum_version_id = 1,
208     .fields = (VMStateField[]) {
209         VMSTATE_UINT32(a, TestStruct),
210         VMSTATE_UINT32(b, TestStruct),
211         VMSTATE_UINT32_TEST(c, TestStruct, test_skip),
212         VMSTATE_UINT64(d, TestStruct),
213         VMSTATE_UINT32_TEST(e, TestStruct, test_skip),
214         VMSTATE_UINT64_V(f, TestStruct, 2),
215         VMSTATE_END_OF_LIST()
216     }
217 };
218
219
220 static void test_save_noskip(void)
221 {
222     QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
223     TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
224                        .skip_c_e = false };
225     vmstate_save_state(fsave, &vmstate_skipping, &obj);
226     g_assert(!qemu_file_get_error(fsave));
227     qemu_fclose(fsave);
228
229     QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
230     uint8_t expected[] = {
231         0, 0, 0, 1,             /* a */
232         0, 0, 0, 2,             /* b */
233         0, 0, 0, 3,             /* c */
234         0, 0, 0, 0, 0, 0, 0, 4, /* d */
235         0, 0, 0, 5,             /* e */
236         0, 0, 0, 0, 0, 0, 0, 6, /* f */
237     };
238     uint8_t result[sizeof(expected)];
239     g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==,
240                     sizeof(result));
241     g_assert(!qemu_file_get_error(loading));
242     g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0);
243
244     /* Must reach EOF */
245     qemu_get_byte(loading);
246     g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
247
248     qemu_fclose(loading);
249 }
250
251 static void test_save_skip(void)
252 {
253     QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
254     TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
255                        .skip_c_e = true };
256     vmstate_save_state(fsave, &vmstate_skipping, &obj);
257     g_assert(!qemu_file_get_error(fsave));
258     qemu_fclose(fsave);
259
260     QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
261     uint8_t expected[] = {
262         0, 0, 0, 1,             /* a */
263         0, 0, 0, 2,             /* b */
264         0, 0, 0, 0, 0, 0, 0, 4, /* d */
265         0, 0, 0, 0, 0, 0, 0, 6, /* f */
266     };
267     uint8_t result[sizeof(expected)];
268     g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==,
269                     sizeof(result));
270     g_assert(!qemu_file_get_error(loading));
271     g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0);
272
273
274     /* Must reach EOF */
275     qemu_get_byte(loading);
276     g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
277
278     qemu_fclose(loading);
279 }
280
281 static void test_load_noskip(void)
282 {
283     QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
284     uint8_t buf[] = {
285         0, 0, 0, 10,             /* a */
286         0, 0, 0, 20,             /* b */
287         0, 0, 0, 30,             /* c */
288         0, 0, 0, 0, 0, 0, 0, 40, /* d */
289         0, 0, 0, 50,             /* e */
290         0, 0, 0, 0, 0, 0, 0, 60, /* f */
291         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
292     };
293     qemu_put_buffer(fsave, buf, sizeof(buf));
294     qemu_fclose(fsave);
295
296     QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
297     TestStruct obj = { .skip_c_e = false };
298     vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
299     g_assert(!qemu_file_get_error(loading));
300     g_assert_cmpint(obj.a, ==, 10);
301     g_assert_cmpint(obj.b, ==, 20);
302     g_assert_cmpint(obj.c, ==, 30);
303     g_assert_cmpint(obj.d, ==, 40);
304     g_assert_cmpint(obj.e, ==, 50);
305     g_assert_cmpint(obj.f, ==, 60);
306     qemu_fclose(loading);
307 }
308
309 static void test_load_skip(void)
310 {
311     QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
312     uint8_t buf[] = {
313         0, 0, 0, 10,             /* a */
314         0, 0, 0, 20,             /* b */
315         0, 0, 0, 0, 0, 0, 0, 40, /* d */
316         0, 0, 0, 0, 0, 0, 0, 60, /* f */
317         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
318     };
319     qemu_put_buffer(fsave, buf, sizeof(buf));
320     qemu_fclose(fsave);
321
322     QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
323     TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 };
324     vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
325     g_assert(!qemu_file_get_error(loading));
326     g_assert_cmpint(obj.a, ==, 10);
327     g_assert_cmpint(obj.b, ==, 20);
328     g_assert_cmpint(obj.c, ==, 300);
329     g_assert_cmpint(obj.d, ==, 40);
330     g_assert_cmpint(obj.e, ==, 500);
331     g_assert_cmpint(obj.f, ==, 60);
332     qemu_fclose(loading);
333 }
334
335 int main(int argc, char **argv)
336 {
337     temp_fd = mkstemp(temp_file);
338
339     g_test_init(&argc, &argv, NULL);
340     g_test_add_func("/vmstate/simple/save", test_simple_save);
341     g_test_add_func("/vmstate/simple/load", test_simple_load);
342     g_test_add_func("/vmstate/versioned/load/v1", test_load_v1);
343     g_test_add_func("/vmstate/versioned/load/v2", test_load_v2);
344     g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip);
345     g_test_add_func("/vmstate/field_exists/load/skip", test_load_skip);
346     g_test_add_func("/vmstate/field_exists/save/noskip", test_save_noskip);
347     g_test_add_func("/vmstate/field_exists/save/skip", test_save_skip);
348     g_test_run();
349
350     close(temp_fd);
351     unlink(temp_file);
352
353     return 0;
354 }
This page took 0.041997 seconds and 4 git commands to generate.