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