test-qxl-parsing is really a series of several tests. Porting it to GTest makes this more obvious. This also has the side-effect of making it more friendly to 'make check-valgrind' (which would fail on SIGALRM, and on unexpected g_warning()). --- server/tests/Makefile.am | 1 + server/tests/test-qxl-parsing.c | 212 ++++++++++++++++++++++++++++------------ 2 files changed, 149 insertions(+), 64 deletions(-) diff --git a/server/tests/Makefile.am b/server/tests/Makefile.am index 3f61faa..fc9e1f2 100644 --- a/server/tests/Makefile.am +++ b/server/tests/Makefile.am @@ -124,6 +124,7 @@ test_vdagent_CPPFLAGS = \ -UGLIB_VERSION_MAX_ALLOWED \ $(NULL) test_codecs_parsing_CPPFLAGS = $(test_vdagent_CPPFLAGS) +test_qxl_parsing_CPPFLAGS = $(test_vdagent_CPPFLAGS) if HAVE_GSTREAMER test_gst_SOURCES = test-gst.c \ diff --git a/server/tests/test-qxl-parsing.c b/server/tests/test-qxl-parsing.c index dd99150..f84f8c8 100644 --- a/server/tests/test-qxl-parsing.c +++ b/server/tests/test-qxl-parsing.c @@ -32,25 +32,7 @@ #include <spice/macros.h> #include "memslot.h" #include "red-parse-qxl.h" - -static int exit_code = EXIT_SUCCESS; -static const char *test_name = NULL; - -static void -failure(void) -{ - assert(test_name); - printf("Test %s FAILED!\n", test_name); - exit_code = EXIT_FAILURE; -} - -static void -test(const char *desc) -{ - test_name = desc; - printf("Starting test %s\n", desc); - alarm(5); -} +#include "test-glib-compat.h" static inline QXLPHYSICAL to_physical(const void *ptr) @@ -71,45 +53,77 @@ create_chunk(size_t prefix, uint32_t size, QXLDataChunk* prev, int fill) return ptr; } -int main(int argc, char **argv) +static void init_meminfo(RedMemSlotInfo *mem_info) { - RedMemSlotInfo mem_info; - memslot_info_init(&mem_info, 1 /* groups */, 1 /* slots */, 1, 1, 0); - memslot_info_add_slot(&mem_info, 0, 0, 0 /* delta */, 0 /* start */, ~0ul /* end */, 0 /* generation */); - - RedSurfaceCmd cmd; - QXLSurfaceCmd qxl; - - RedCursorCmd red_cursor_cmd; - QXLCursorCmd cursor_cmd; - QXLCursor *cursor; - QXLDataChunk *chunks[2]; + memslot_info_init(mem_info, 1 /* groups */, 1 /* slots */, 1, 1, 0); + memslot_info_add_slot(mem_info, 0, 0, 0 /* delta */, 0 /* start */, ~0ul /* end */, 0 /* generation */); +} +static void init_qxl_surface(QXLSurfaceCmd *qxl) +{ void *surface_mem; - memset(&qxl, 0, sizeof(qxl)); + memset(qxl, 0, sizeof(*qxl)); - qxl.surface_id = 123; + qxl->surface_id = 123; - /* try to create a surface with no issues, should succeed */ - test("no issues"); - qxl.u.surface_create.format = SPICE_SURFACE_FMT_32_xRGB; - qxl.u.surface_create.width = 128; - qxl.u.surface_create.stride = 512; - qxl.u.surface_create.height = 128; + qxl->u.surface_create.format = SPICE_SURFACE_FMT_32_xRGB; + qxl->u.surface_create.width = 128; + qxl->u.surface_create.stride = 512; + qxl->u.surface_create.height = 128; surface_mem = malloc(0x10000); - qxl.u.surface_create.data = to_physical(surface_mem); - if (red_get_surface_cmd(&mem_info, 0, &cmd, to_physical(&qxl))) - failure(); + qxl->u.surface_create.data = to_physical(surface_mem); +} + +static void deinit_qxl_surface(QXLSurfaceCmd *qxl) +{ + free((void *)qxl->u.surface_create.data); +} + +static void test_no_issues(void) +{ + RedMemSlotInfo mem_info; + RedSurfaceCmd cmd; + QXLSurfaceCmd qxl; + + init_meminfo(&mem_info); + init_qxl_surface(&qxl); + + /* try to create a surface with no issues, should succeed */ + g_assert_false(red_get_surface_cmd(&mem_info, 0, &cmd, to_physical(&qxl))); + + deinit_qxl_surface(&qxl); + memslot_info_destroy(&mem_info); +} + +static void test_stride_too_small(void) +{ + RedMemSlotInfo mem_info; + RedSurfaceCmd cmd; + QXLSurfaceCmd qxl; + + init_meminfo(&mem_info); + init_qxl_surface(&qxl); /* try to create a surface with a stride too small to fit * the entire width. * This can be used to cause buffer overflows so refuse it. */ - test("stride too small"); qxl.u.surface_create.stride = 256; - if (!red_get_surface_cmd(&mem_info, 0, &cmd, to_physical(&qxl))) - failure(); + g_assert_true(red_get_surface_cmd(&mem_info, 0, &cmd, to_physical(&qxl))); + + deinit_qxl_surface(&qxl); + memslot_info_destroy(&mem_info); +} + +static void test_too_big_image(void) +{ + RedMemSlotInfo mem_info; + RedSurfaceCmd cmd; + QXLSurfaceCmd qxl; + + init_meminfo(&mem_info); + init_qxl_surface(&qxl); /* try to create a surface quite large. * The sizes (width and height) were chosen so the multiplication @@ -118,15 +132,25 @@ int main(int argc, char **argv) * overflows. Also the total memory for the card is not enough to * hold the surface so surely can't be accepted. */ - test("too big image"); qxl.u.surface_create.stride = 0x08000004 * 4; qxl.u.surface_create.width = 0x08000004; qxl.u.surface_create.height = 0x40000020; - if (!red_get_surface_cmd(&mem_info, 0, &cmd, to_physical(&qxl))) - failure(); + g_assert_true(red_get_surface_cmd(&mem_info, 0, &cmd, to_physical(&qxl))); + + deinit_qxl_surface(&qxl); + memslot_info_destroy(&mem_info); +} + +static void test_cursor_command(void) +{ + RedMemSlotInfo mem_info; + RedCursorCmd red_cursor_cmd; + QXLCursorCmd cursor_cmd; + QXLCursor *cursor; + + init_meminfo(&mem_info); /* test base cursor with no problems */ - test("base cursor command"); memset(&cursor_cmd, 0, sizeof(cursor_cmd)); cursor_cmd.type = QXL_CURSOR_SET; @@ -138,13 +162,25 @@ int main(int argc, char **argv) cursor_cmd.u.set.shape = to_physical(cursor); - if (red_get_cursor_cmd(&mem_info, 0, &red_cursor_cmd, to_physical(&cursor_cmd))) - failure(); + g_assert_false(red_get_cursor_cmd(&mem_info, 0, &red_cursor_cmd, to_physical(&cursor_cmd))); free(red_cursor_cmd.u.set.shape.data); free(cursor); + memslot_info_destroy(&mem_info); +} + +static void test_circular_empty_chunks(void) +{ + RedMemSlotInfo mem_info; + RedCursorCmd red_cursor_cmd; + QXLCursorCmd cursor_cmd; + QXLCursor *cursor; + QXLDataChunk *chunks[2]; + + init_meminfo(&mem_info); + g_test_expect_message(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*red_get_data_chunks_ptr: data split in too many chunks, avoiding DoS*"); /* a circular list of empty chunks should not be a problems */ - test("circular empty chunks"); memset(&cursor_cmd, 0, sizeof(cursor_cmd)); cursor_cmd.type = QXL_CURSOR_SET; @@ -162,16 +198,31 @@ int main(int argc, char **argv) memset(&red_cursor_cmd, 0xaa, sizeof(red_cursor_cmd)); if (!red_get_cursor_cmd(&mem_info, 0, &red_cursor_cmd, to_physical(&cursor_cmd))) { /* function does not return errors so there should be no data */ - assert(red_cursor_cmd.type == QXL_CURSOR_SET); - assert(red_cursor_cmd.u.set.position.x == 0); - assert(red_cursor_cmd.u.set.position.y == 0); - assert(red_cursor_cmd.u.set.shape.data_size == 0); + g_assert_cmpuint(red_cursor_cmd.type, ==, QXL_CURSOR_SET); + g_assert_cmpuint(red_cursor_cmd.u.set.position.x, ==, 0); + g_assert_cmpuint(red_cursor_cmd.u.set.position.y, ==, 0); + g_assert_cmpuint(red_cursor_cmd.u.set.shape.data_size, ==, 0); } + g_test_assert_expected_messages(); + free(cursor); free(chunks[0]); + memslot_info_destroy(&mem_info); +} + +static void test_circular_small_chunks(void) +{ + RedMemSlotInfo mem_info; + RedCursorCmd red_cursor_cmd; + QXLCursorCmd cursor_cmd; + QXLCursor *cursor; + QXLDataChunk *chunks[2]; + + init_meminfo(&mem_info); + g_test_expect_message(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*red_get_data_chunks_ptr: data split in too many chunks, avoiding DoS*"); /* a circular list of small chunks should not be a problems */ - test("circular small chunks"); memset(&cursor_cmd, 0, sizeof(cursor_cmd)); cursor_cmd.type = QXL_CURSOR_SET; @@ -189,16 +240,49 @@ int main(int argc, char **argv) memset(&red_cursor_cmd, 0xaa, sizeof(red_cursor_cmd)); if (!red_get_cursor_cmd(&mem_info, 0, &red_cursor_cmd, to_physical(&cursor_cmd))) { /* function does not return errors so there should be no data */ - assert(red_cursor_cmd.type == QXL_CURSOR_SET); - assert(red_cursor_cmd.u.set.position.x == 0); - assert(red_cursor_cmd.u.set.position.y == 0); - assert(red_cursor_cmd.u.set.shape.data_size == 0); + g_assert_cmpuint(red_cursor_cmd.type, ==, QXL_CURSOR_SET); + g_assert_cmpuint(red_cursor_cmd.u.set.position.x, ==, 0); + g_assert_cmpuint(red_cursor_cmd.u.set.position.y, ==, 0); + g_assert_cmpuint(red_cursor_cmd.u.set.shape.data_size, ==, 0); } + g_test_assert_expected_messages(); + free(cursor); free(chunks[0]); - memslot_info_destroy(&mem_info); - free(surface_mem); +} + + +int main(int argc, char *argv[]) +{ + g_test_init(&argc, &argv, NULL); + + /* try to create a surface with no issues, should succeed */ + g_test_add_func("/server/qxl-parsing-no-issues", test_no_issues); + + /* try to create a surface with a stride too small to fit + * the entire width. + * This can be used to cause buffer overflows so refuse it. + */ + g_test_add_func("/server/qxl-parsing/stride-too-small", test_stride_too_small); + + /* try to create a surface quite large. + * The sizes (width and height) were chosen so the multiplication + * using 32 bit values gives a very small value. + * These kind of values should be refused as they will cause + * overflows. Also the total memory for the card is not enough to + * hold the surface so surely can't be accepted. + */ + g_test_add_func("/server/qxl-parsing/too-big-image", test_too_big_image); + + /* test base cursor with no problems */ + g_test_add_func("/server/qxl-parsing/base-cursor-command", test_cursor_command); + + /* a circular list of empty chunks should not be a problems */ + g_test_add_func("/server/qxl-parsing/circular-empty-chunks", test_circular_empty_chunks); + + /* a circular list of small chunks should not be a problems */ + g_test_add_func("/server/qxl-parsing/circular-small-chunks", test_circular_small_chunks); - return exit_code; + return g_test_run(); } -- 2.9.3 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel