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 [ - + ]: 1 : while (nreaders == 0) 87 : 0 : 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: */