Branch data Line data Source code
1 : : /* Copyright (c) 2019, Red Hat, Inc.
2 : : *
3 : : * Authors: Jakub Jelen <jjelen@redhat.com>
4 : : *
5 : : * This code is licensed under the GNU LGPL, version 2.1 or later.
6 : : * See the COPYING file in the top-level directory.
7 : : */
8 : :
9 : : #include <stdlib.h>
10 : : #include <libcacard.h>
11 : :
12 : : #include "fuzzer.h"
13 : :
14 : : #define ARGS "db=\"sql:%s\" use_hw=no soft=(,Test,CAC,,cert1,cert2,cert3)"
15 : : #define APDUBufSize 270
16 : :
17 : : static GMainLoop *loop;
18 : : static GThread *thread;
19 : : static guint nreaders;
20 : : static GMutex mutex;
21 : : static GCond cond;
22 : :
23 : : static gpointer
24 : 1 : events_thread(gpointer arg)
25 : : {
26 : : unsigned int reader_id;
27 : : VEvent *event;
28 : :
29 : : (void)arg;
30 : :
31 : : while (1) {
32 : 4 : event = vevent_wait_next_vevent();
33 [ + + ]: 4 : if (event->type == VEVENT_LAST) {
34 : 1 : vevent_delete(event);
35 : : break;
36 : : }
37 : 3 : reader_id = vreader_get_id(event->reader);
38 [ + + ]: 3 : if (reader_id == VSCARD_UNDEFINED_READER_ID) {
39 : 1 : g_mutex_lock(&mutex);
40 : 1 : vreader_set_id(event->reader, nreaders++);
41 : 1 : g_cond_signal(&cond);
42 : 1 : g_mutex_unlock(&mutex);
43 : 1 : reader_id = vreader_get_id(event->reader);
44 : : }
45 [ - + ]: 3 : switch (event->type) {
46 : : case VEVENT_READER_INSERT:
47 : : case VEVENT_READER_REMOVE:
48 : : case VEVENT_CARD_INSERT:
49 : : case VEVENT_CARD_REMOVE:
50 : : break;
51 : 0 : case VEVENT_LAST:
52 : : default:
53 : 0 : g_warn_if_reached();
54 : 0 : break;
55 : : }
56 : 3 : vevent_delete(event);
57 : : }
58 : :
59 : 1 : return NULL;
60 : : }
61 : :
62 : 1 : static void libcacard_init(void)
63 : : {
64 : : VCardEmulOptions *command_line_options = NULL;
65 : : gchar *dbdir = NULL;
66 : : gchar *args = NULL;
67 : : VReader *r;
68 : : VCardEmulError ret;
69 : :
70 : : /* This will use the test directory when running as test and
71 : : * and dirname part of argv[0] when running from oss-fuzz */
72 : 1 : dbdir = g_test_build_filename(G_TEST_DIST, "db", NULL);
73 : 1 : args = g_strdup_printf(ARGS, dbdir);
74 : :
75 : 1 : thread = g_thread_new("fuzz/events", events_thread, NULL);
76 : :
77 : 1 : command_line_options = vcard_emul_options(args);
78 : 1 : ret = vcard_emul_init(command_line_options);
79 [ - + ]: 1 : g_assert_cmpint(ret, ==, VCARD_EMUL_OK);
80 : :
81 : 1 : r = vreader_get_reader_by_name("Test");
82 [ - + ]: 1 : g_assert_nonnull(r);
83 : 1 : vreader_free(r); /* get by name ref */
84 : :
85 : 1 : g_mutex_lock(&mutex);
86 [ + + ]: 2 : while (nreaders == 0)
87 : 1 : g_cond_wait(&cond, &mutex);
88 : 1 : g_mutex_unlock(&mutex);
89 : :
90 : 1 : g_free(args);
91 : 1 : g_free(dbdir);
92 : 1 : }
93 : :
94 : 1 : static void libcacard_finalize(void)
95 : : {
96 : 1 : VReader *reader = vreader_get_reader_by_id(0);
97 : :
98 : : /* This actually still generates events ?? */
99 [ + - ]: 1 : if (reader) /*if /remove didn't run */
100 : 1 : vreader_remove_reader(reader);
101 : :
102 : : /* This probably supposed to be a event that terminates the loop */
103 : 1 : vevent_queue_vevent(vevent_new(VEVENT_LAST, reader, NULL));
104 : :
105 : : /* join */
106 : 1 : g_thread_join(thread);
107 : :
108 : 1 : vreader_free(reader);
109 : :
110 : 1 : vcard_emul_finalize();
111 : 1 : }
112 : :
113 : 1 : int LLVMFuzzerInitialize(int *argc, char ***argv)
114 : : {
115 : : VReader *reader;
116 : :
117 : : (void) argc;
118 : :
119 : 1 : g_test_init(argc, argv, NULL);
120 : :
121 : 1 : loop = g_main_loop_new(NULL, TRUE);
122 : :
123 : 1 : g_debug("Initializing ...");
124 : 1 : libcacard_init();
125 : :
126 : 1 : reader = vreader_get_reader_by_id(0);
127 [ - + ]: 1 : if (vreader_card_is_present(reader) != VREADER_OK) {
128 : 0 : g_error("Card inserted but not still not present");
129 : : return -1;
130 : : }
131 : :
132 : 1 : atexit(libcacard_finalize);
133 : :
134 : 1 : vreader_free(reader);
135 : : return 0;
136 : : }
137 : :
138 : : /* We require at least 2b for length and 4 bytes for simplest APDU (Case 1) */
139 : : size_t kMinInputLength = 6;
140 : :
141 : 1 : int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
142 : : {
143 : : size_t left = Size;
144 : : uint8_t *data = (uint8_t *) Data;
145 : : VReader *reader = NULL;
146 : 1 : int dwRecvLength = APDUBufSize;
147 : : uint8_t pbRecvBuffer[APDUBufSize];
148 : :
149 [ - + ]: 1 : if (left < kMinInputLength) {
150 : 0 : g_debug("Too short input for APDU");
151 : 0 : return 0;
152 : : }
153 : :
154 : 1 : reader = vreader_get_reader_by_id(0);
155 [ - + ]: 1 : g_assert_nonnull(reader);
156 : :
157 [ + + ]: 88 : while (left > 0) {
158 : : VReaderStatus status;
159 : : size_t data_len;
160 : :
161 : : /* Interpret the fuzzing data as follows:
162 : : * 1 byte length
163 : : * length bytes data
164 : : */
165 : 87 : data_len = (size_t) data[0];
166 : 87 : data++;
167 : 87 : left--;
168 : 87 : data_len = data_len > left ? left : data_len;
169 : :
170 : 87 : g_debug("Transfering %zu bytes", data_len);
171 : 87 : status = vreader_xfr_bytes(reader,
172 : : data, data_len,
173 : : pbRecvBuffer, &dwRecvLength);
174 [ - + ]: 87 : if (status != VREADER_OK) {
175 [ # # ]: 0 : g_debug("Returned %s", status == VREADER_NO_CARD ? "VREADER_NO_CARD" : "VREADER_OUT_OF_MEMORY");
176 : : }
177 : 87 : data += data_len;
178 : 87 : left -= data_len;
179 : : }
180 : :
181 : 1 : g_debug("Cleaning up");
182 : 1 : vreader_free(reader);
183 : :
184 : 1 : return 0;
185 : : }
186 : :
187 : : /* vim: set ts=4 sw=4 tw=0 noet expandtab: */
|