• R/O
  • HTTP
  • SSH
  • HTTPS

コミット

タグ
未設定

よく使われているワード(クリックで追加)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

コミットメタ情報

リビジョン275ab39d86974aab8bbce14b1a0c488653cc72d2 (tree)
日時2020-02-22 17:26:48
作者Alexander Bulekov <alxndr@bu.e...>
コミッターStefan Hajnoczi

ログメッセージ

fuzz: add support for qos-assisted fuzz targets

Signed-off-by: Alexander Bulekov <alxndr@bu.edu>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
Message-id: 20200220041118.23264-17-alxndr@bu.edu
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>

変更サマリ

差分

--- a/tests/qtest/fuzz/Makefile.include
+++ b/tests/qtest/fuzz/Makefile.include
@@ -1,8 +1,10 @@
11 QEMU_PROG_FUZZ=qemu-fuzz-$(TARGET_NAME)$(EXESUF)
22
33 fuzz-obj-y += tests/qtest/libqtest.o
4+fuzz-obj-y += $(libqos-obj-y)
45 fuzz-obj-y += tests/qtest/fuzz/fuzz.o # Fuzzer skeleton
56 fuzz-obj-y += tests/qtest/fuzz/fork_fuzz.o
7+fuzz-obj-y += tests/qtest/fuzz/qos_fuzz.o
68
79 FUZZ_CFLAGS += -I$(SRC_PATH)/tests -I$(SRC_PATH)/tests/qtest
810
--- /dev/null
+++ b/tests/qtest/fuzz/qos_fuzz.c
@@ -0,0 +1,234 @@
1+/*
2+ * QOS-assisted fuzzing helpers
3+ *
4+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
5+ *
6+ * This library is free software; you can redistribute it and/or
7+ * modify it under the terms of the GNU Lesser General Public
8+ * License version 2 as published by the Free Software Foundation.
9+ *
10+ * This library is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+ * Lesser General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU Lesser General Public
16+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
17+ */
18+
19+#include "qemu/osdep.h"
20+#include "qemu/units.h"
21+#include "qapi/error.h"
22+#include "qemu-common.h"
23+#include "exec/memory.h"
24+#include "exec/address-spaces.h"
25+#include "sysemu/sysemu.h"
26+#include "qemu/main-loop.h"
27+
28+#include "tests/qtest/libqtest.h"
29+#include "tests/qtest/libqos/malloc.h"
30+#include "tests/qtest/libqos/qgraph.h"
31+#include "tests/qtest/libqos/qgraph_internal.h"
32+#include "tests/qtest/libqos/qos_external.h"
33+
34+#include "fuzz.h"
35+#include "qos_fuzz.h"
36+
37+#include "qapi/qapi-commands-machine.h"
38+#include "qapi/qapi-commands-qom.h"
39+#include "qapi/qmp/qlist.h"
40+
41+
42+void *fuzz_qos_obj;
43+QGuestAllocator *fuzz_qos_alloc;
44+
45+static const char *fuzz_target_name;
46+static char **fuzz_path_vec;
47+
48+/*
49+ * Replaced the qmp commands with direct qmp_marshal calls.
50+ * Probably there is a better way to do this
51+ */
52+static void qos_set_machines_devices_available(void)
53+{
54+ QDict *req = qdict_new();
55+ QObject *response;
56+ QDict *args = qdict_new();
57+ QList *lst;
58+ Error *err = NULL;
59+
60+ qmp_marshal_query_machines(NULL, &response, &err);
61+ assert(!err);
62+ lst = qobject_to(QList, response);
63+ apply_to_qlist(lst, true);
64+
65+ qobject_unref(response);
66+
67+
68+ qdict_put_str(req, "execute", "qom-list-types");
69+ qdict_put_str(args, "implements", "device");
70+ qdict_put_bool(args, "abstract", true);
71+ qdict_put_obj(req, "arguments", (QObject *) args);
72+
73+ qmp_marshal_qom_list_types(args, &response, &err);
74+ assert(!err);
75+ lst = qobject_to(QList, response);
76+ apply_to_qlist(lst, false);
77+ qobject_unref(response);
78+ qobject_unref(req);
79+}
80+
81+static char **current_path;
82+
83+void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc)
84+{
85+ return allocate_objects(qts, current_path + 1, p_alloc);
86+}
87+
88+static const char *qos_build_main_args(void)
89+{
90+ char **path = fuzz_path_vec;
91+ QOSGraphNode *test_node;
92+ GString *cmd_line = g_string_new(path[0]);
93+ void *test_arg;
94+
95+ if (!path) {
96+ fprintf(stderr, "QOS Path not found\n");
97+ abort();
98+ }
99+
100+ /* Before test */
101+ current_path = path;
102+ test_node = qos_graph_get_node(path[(g_strv_length(path) - 1)]);
103+ test_arg = test_node->u.test.arg;
104+ if (test_node->u.test.before) {
105+ test_arg = test_node->u.test.before(cmd_line, test_arg);
106+ }
107+ /* Prepend the arguments that we need */
108+ g_string_prepend(cmd_line,
109+ TARGET_NAME " -display none -machine accel=qtest -m 64 ");
110+ return cmd_line->str;
111+}
112+
113+/*
114+ * This function is largely a copy of qos-test.c:walk_path. Since walk_path
115+ * is itself a callback, its a little annoying to add another argument/layer of
116+ * indirection
117+ */
118+static void walk_path(QOSGraphNode *orig_path, int len)
119+{
120+ QOSGraphNode *path;
121+ QOSGraphEdge *edge;
122+
123+ /* etype set to QEDGE_CONSUMED_BY so that machine can add to the command line */
124+ QOSEdgeType etype = QEDGE_CONSUMED_BY;
125+
126+ /* twice QOS_PATH_MAX_ELEMENT_SIZE since each edge can have its arg */
127+ char **path_vec = g_new0(char *, (QOS_PATH_MAX_ELEMENT_SIZE * 2));
128+ int path_vec_size = 0;
129+
130+ char *after_cmd, *before_cmd, *after_device;
131+ GString *after_device_str = g_string_new("");
132+ char *node_name = orig_path->name, *path_str;
133+
134+ GString *cmd_line = g_string_new("");
135+ GString *cmd_line2 = g_string_new("");
136+
137+ path = qos_graph_get_node(node_name); /* root */
138+ node_name = qos_graph_edge_get_dest(path->path_edge); /* machine name */
139+
140+ path_vec[path_vec_size++] = node_name;
141+ path_vec[path_vec_size++] = qos_get_machine_type(node_name);
142+
143+ for (;;) {
144+ path = qos_graph_get_node(node_name);
145+ if (!path->path_edge) {
146+ break;
147+ }
148+
149+ node_name = qos_graph_edge_get_dest(path->path_edge);
150+
151+ /* append node command line + previous edge command line */
152+ if (path->command_line && etype == QEDGE_CONSUMED_BY) {
153+ g_string_append(cmd_line, path->command_line);
154+ g_string_append(cmd_line, after_device_str->str);
155+ g_string_truncate(after_device_str, 0);
156+ }
157+
158+ path_vec[path_vec_size++] = qos_graph_edge_get_name(path->path_edge);
159+ /* detect if edge has command line args */
160+ after_cmd = qos_graph_edge_get_after_cmd_line(path->path_edge);
161+ after_device = qos_graph_edge_get_extra_device_opts(path->path_edge);
162+ before_cmd = qos_graph_edge_get_before_cmd_line(path->path_edge);
163+ edge = qos_graph_get_edge(path->name, node_name);
164+ etype = qos_graph_edge_get_type(edge);
165+
166+ if (before_cmd) {
167+ g_string_append(cmd_line, before_cmd);
168+ }
169+ if (after_cmd) {
170+ g_string_append(cmd_line2, after_cmd);
171+ }
172+ if (after_device) {
173+ g_string_append(after_device_str, after_device);
174+ }
175+ }
176+
177+ path_vec[path_vec_size++] = NULL;
178+ g_string_append(cmd_line, after_device_str->str);
179+ g_string_free(after_device_str, true);
180+
181+ g_string_append(cmd_line, cmd_line2->str);
182+ g_string_free(cmd_line2, true);
183+
184+ /*
185+ * here position 0 has <arch>/<machine>, position 1 has <machine>.
186+ * The path must not have the <arch>, qtest_add_data_func adds it.
187+ */
188+ path_str = g_strjoinv("/", path_vec + 1);
189+
190+ /* Check that this is the test we care about: */
191+ char *test_name = strrchr(path_str, '/') + 1;
192+ if (strcmp(test_name, fuzz_target_name) == 0) {
193+ /*
194+ * put arch/machine in position 1 so run_one_test can do its work
195+ * and add the command line at position 0.
196+ */
197+ path_vec[1] = path_vec[0];
198+ path_vec[0] = g_string_free(cmd_line, false);
199+
200+ fuzz_path_vec = path_vec;
201+ } else {
202+ g_free(path_vec);
203+ }
204+
205+ g_free(path_str);
206+}
207+
208+static const char *qos_get_cmdline(FuzzTarget *t)
209+{
210+ /*
211+ * Set a global variable that we use to identify the qos_path for our
212+ * fuzz_target
213+ */
214+ fuzz_target_name = t->name;
215+ qos_set_machines_devices_available();
216+ qos_graph_foreach_test_path(walk_path);
217+ return qos_build_main_args();
218+}
219+
220+void fuzz_add_qos_target(
221+ FuzzTarget *fuzz_opts,
222+ const char *interface,
223+ QOSGraphTestOptions *opts
224+ )
225+{
226+ qos_add_test(fuzz_opts->name, interface, NULL, opts);
227+ fuzz_opts->get_init_cmdline = qos_get_cmdline;
228+ fuzz_add_target(fuzz_opts);
229+}
230+
231+void qos_init_path(QTestState *s)
232+{
233+ fuzz_qos_obj = qos_allocate_objects(s , &fuzz_qos_alloc);
234+}
--- /dev/null
+++ b/tests/qtest/fuzz/qos_fuzz.h
@@ -0,0 +1,33 @@
1+/*
2+ * QOS-assisted fuzzing helpers
3+ *
4+ * Copyright Red Hat Inc., 2019
5+ *
6+ * Authors:
7+ * Alexander Bulekov <alxndr@bu.edu>
8+ *
9+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
10+ * See the COPYING file in the top-level directory.
11+ */
12+
13+#ifndef _QOS_FUZZ_H_
14+#define _QOS_FUZZ_H_
15+
16+#include "tests/qtest/fuzz/fuzz.h"
17+#include "tests/qtest/libqos/qgraph.h"
18+
19+int qos_fuzz(const unsigned char *Data, size_t Size);
20+void qos_setup(void);
21+
22+extern void *fuzz_qos_obj;
23+extern QGuestAllocator *fuzz_qos_alloc;
24+
25+void fuzz_add_qos_target(
26+ FuzzTarget *fuzz_opts,
27+ const char *interface,
28+ QOSGraphTestOptions *opts
29+ );
30+
31+void qos_init_path(QTestState *);
32+
33+#endif