Bug Summary

File:libcacard/vreader.c
Location:line 288, column 20
Description:Access to field 'b_total_len' results in a dereference of a null pointer (loaded from variable 'response')

Annotated Source Code

1/*
2 * emulate the reader
3 *
4 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
5 * See the COPYING.LIB file in the top-level directory.
6 */
7
8#ifdef G_LOG_DOMAIN"libcacard"
9#undef G_LOG_DOMAIN"libcacard"
10#endif
11#define G_LOG_DOMAIN"libcacard" "libcacard"
12#include <glib.h>
13
14#include "qemu-common.h"
15#include "qemu/thread.h"
16
17#include "vcard.h"
18#include "vcard_emul.h"
19#include "card_7816.h"
20#include "vreader.h"
21#include "vevent.h"
22#include "cac.h" /* just for debugging defines */
23
24#define LIBCACARD_LOG_DOMAIN"libcacard" "libcacard"
25
26struct VReaderStruct {
27 int reference_count;
28 VCard *card;
29 char *name;
30 vreader_id_t id;
31 QemuMutex lock;
32 VReaderEmul *reader_private;
33 VReaderEmulFree reader_private_free;
34};
35
36/*
37 * Debug helpers
38 */
39
40static const char *
41apdu_ins_to_string(int ins)
42{
43 switch (ins) {
44 case VCARD7816_INS_MANAGE_CHANNEL0x70:
45 return "manage channel";
46 case VCARD7816_INS_EXTERNAL_AUTHENTICATE0x82:
47 return "external authenticate";
48 case VCARD7816_INS_GET_CHALLENGE0x84:
49 return "get challenge";
50 case VCARD7816_INS_INTERNAL_AUTHENTICATE0x88:
51 return "internal authenticate";
52 case VCARD7816_INS_ERASE_BINARY0x0e:
53 return "erase binary";
54 case VCARD7816_INS_READ_BINARY0xb0:
55 return "read binary";
56 case VCARD7816_INS_WRITE_BINARY0xd0:
57 return "write binary";
58 case VCARD7816_INS_UPDATE_BINARY0xd6:
59 return "update binary";
60 case VCARD7816_INS_READ_RECORD0xb2:
61 return "read record";
62 case VCARD7816_INS_WRITE_RECORD0xd2:
63 return "write record";
64 case VCARD7816_INS_UPDATE_RECORD0xdc:
65 return "update record";
66 case VCARD7816_INS_APPEND_RECORD0xe2:
67 return "append record";
68 case VCARD7816_INS_ENVELOPE0xc2:
69 return "envelope";
70 case VCARD7816_INS_PUT_DATA0xda:
71 return "put data";
72 case VCARD7816_INS_GET_DATA0xca:
73 return "get data";
74 case VCARD7816_INS_SELECT_FILE0xa4:
75 return "select file";
76 case VCARD7816_INS_VERIFY0x20:
77 return "verify";
78 case VCARD7816_INS_GET_RESPONSE0xc0:
79 return "get response";
80 case CAC_GET_PROPERTIES0x56:
81 return "get properties";
82 case CAC_GET_ACR0x4c:
83 return "get acr";
84 case CAC_READ_BUFFER0x52:
85 return "read buffer";
86 case CAC_UPDATE_BUFFER0x58:
87 return "update buffer";
88 case CAC_SIGN_DECRYPT0x42:
89 return "sign decrypt";
90 case CAC_GET_CERTIFICATE0x36:
91 return "get certificate";
92 }
93 return "unknown";
94}
95
96/* manage locking */
97static inline void
98vreader_lock(VReader *reader)
99{
100 qemu_mutex_lock(&reader->lock);
101}
102
103static inline void
104vreader_unlock(VReader *reader)
105{
106 qemu_mutex_unlock(&reader->lock);
107}
108
109/*
110 * vreader constructor
111 */
112VReader *
113vreader_new(const char *name, VReaderEmul *private,
114 VReaderEmulFree private_free)
115{
116 VReader *reader;
117
118 reader = (VReader *)g_malloc(sizeof(VReader));
119 qemu_mutex_init(&reader->lock);
120 reader->reference_count = 1;
121 reader->name = g_strdup(name);
122 reader->card = NULL((void*)0);
123 reader->id = (vreader_id_t)-1;
124 reader->reader_private = private;
125 reader->reader_private_free = private_free;
126 return reader;
127}
128
129/* get a reference */
130VReader*
131vreader_reference(VReader *reader)
132{
133 if (reader == NULL((void*)0)) {
134 return NULL((void*)0);
135 }
136 vreader_lock(reader);
137 reader->reference_count++;
138 vreader_unlock(reader);
139 return reader;
140}
141
142/* free a reference */
143void
144vreader_free(VReader *reader)
145{
146 if (reader == NULL((void*)0)) {
147 return;
148 }
149 vreader_lock(reader);
150 if (reader->reference_count-- > 1) {
151 vreader_unlock(reader);
152 return;
153 }
154 vreader_unlock(reader);
155 if (reader->card) {
156 vcard_free(reader->card);
157 }
158 if (reader->name) {
159 g_free(reader->name);
160 }
161 if (reader->reader_private_free) {
162 reader->reader_private_free(reader->reader_private);
163 }
164 g_free(reader);
165}
166
167static VCard *
168vreader_get_card(VReader *reader)
169{
170 VCard *card;
171
172 vreader_lock(reader);
173 card = vcard_reference(reader->card);
174 vreader_unlock(reader);
175 return card;
176}
177
178VReaderStatus
179vreader_card_is_present(VReader *reader)
180{
181 VCard *card = vreader_get_card(reader);
182
183 if (card == NULL((void*)0)) {
184 return VREADER_NO_CARD;
185 }
186 vcard_free(card);
187 return VREADER_OK;
188}
189
190vreader_id_t
191vreader_get_id(VReader *reader)
192{
193 if (reader == NULL((void*)0)) {
194 return (vreader_id_t)-1;
195 }
196 return reader->id;
197}
198
199VReaderStatus
200vreader_set_id(VReader *reader, vreader_id_t id)
201{
202 if (reader == NULL((void*)0)) {
203 return VREADER_NO_CARD;
204 }
205 reader->id = id;
206 return VREADER_OK;
207}
208
209const char *
210vreader_get_name(VReader *reader)
211{
212 if (reader == NULL((void*)0)) {
213 return NULL((void*)0);
214 }
215 return reader->name;
216}
217
218VReaderEmul *
219vreader_get_private(VReader *reader)
220{
221 return reader->reader_private;
222}
223
224static VReaderStatus
225vreader_reset(VReader *reader, VCardPower power, unsigned char *atr, int *len)
226{
227 VCard *card = vreader_get_card(reader);
228
229 if (card == NULL((void*)0)) {
230 return VREADER_NO_CARD;
231 }
232 /*
233 * clean up our state
234 */
235 vcard_reset(card, power);
236 if (atr) {
237 vcard_get_atr(card, atr, len);
238 }
239 vcard_free(card); /* free our reference */
240 return VREADER_OK;
241}
242
243VReaderStatus
244vreader_power_on(VReader *reader, unsigned char *atr, int *len)
245{
246 return vreader_reset(reader, VCARD_POWER_ON, atr, len);
247}
248
249VReaderStatus
250vreader_power_off(VReader *reader)
251{
252 return vreader_reset(reader, VCARD_POWER_OFF, NULL((void*)0), 0);
253}
254
255
256VReaderStatus
257vreader_xfr_bytes(VReader *reader,
258 unsigned char *send_buf, int send_buf_len,
259 unsigned char *receive_buf, int *receive_buf_len)
260{
261 VCardAPDU *apdu;
262 VCardResponse *response = NULL((void*)0);
263 VCardStatus card_status;
264 unsigned short status;
265 VCard *card = vreader_get_card(reader);
266
267 if (card == NULL((void*)0)) {
1
Assuming 'card' is not equal to null
2
Taking false branch
268 return VREADER_NO_CARD;
269 }
270
271 apdu = vcard_apdu_new(send_buf, send_buf_len, &status);
272 if (apdu == NULL((void*)0)) {
3
Assuming 'apdu' is not equal to null
4
Taking false branch
273 response = vcard_make_response(status);
274 card_status = VCARD_DONE;
275 } else {
276 g_debug("%s: CLS=0x%x,INS=0x%x,P1=0x%x,P2=0x%x,Lc=%d,Le=%d %s\n",g_log ("libcacard", G_LOG_LEVEL_DEBUG, "%s: CLS=0x%x,INS=0x%x,P1=0x%x,P2=0x%x,Lc=%d,Le=%d %s\n"
, __func__, apdu->u.header->ah_cla, apdu->u.header->
ah_ins, apdu->u.header->ah_p1, apdu->u.header->ah_p2
, apdu->a_Lc, apdu->a_Le, apdu_ins_to_string(apdu->u
.header->ah_ins))
277 __func__, apdu->a_cla, apdu->a_ins, apdu->a_p1, apdu->a_p2,g_log ("libcacard", G_LOG_LEVEL_DEBUG, "%s: CLS=0x%x,INS=0x%x,P1=0x%x,P2=0x%x,Lc=%d,Le=%d %s\n"
, __func__, apdu->u.header->ah_cla, apdu->u.header->
ah_ins, apdu->u.header->ah_p1, apdu->u.header->ah_p2
, apdu->a_Lc, apdu->a_Le, apdu_ins_to_string(apdu->u
.header->ah_ins))
278 apdu->a_Lc, apdu->a_Le, apdu_ins_to_string(apdu->a_ins))g_log ("libcacard", G_LOG_LEVEL_DEBUG, "%s: CLS=0x%x,INS=0x%x,P1=0x%x,P2=0x%x,Lc=%d,Le=%d %s\n"
, __func__, apdu->u.header->ah_cla, apdu->u.header->
ah_ins, apdu->u.header->ah_p1, apdu->u.header->ah_p2
, apdu->a_Lc, apdu->a_Le, apdu_ins_to_string(apdu->u
.header->ah_ins))
;
279 card_status = vcard_process_apdu(card, apdu, &response);
5
Value assigned to 'response'
280 if (response) {
6
Assuming 'response' is null
7
Taking false branch
281 g_debug("%s: status=%d sw1=0x%x sw2=0x%x len=%d (total=%d)\n",g_log ("libcacard", G_LOG_LEVEL_DEBUG, "%s: status=%d sw1=0x%x sw2=0x%x len=%d (total=%d)\n"
, __func__, response->b_status, response->b_sw1, response
->b_sw2, response->b_len, response->b_total_len)
282 __func__, response->b_status, response->b_sw1,g_log ("libcacard", G_LOG_LEVEL_DEBUG, "%s: status=%d sw1=0x%x sw2=0x%x len=%d (total=%d)\n"
, __func__, response->b_status, response->b_sw1, response
->b_sw2, response->b_len, response->b_total_len)
283 response->b_sw2, response->b_len, response->b_total_len)g_log ("libcacard", G_LOG_LEVEL_DEBUG, "%s: status=%d sw1=0x%x sw2=0x%x len=%d (total=%d)\n"
, __func__, response->b_status, response->b_sw1, response
->b_sw2, response->b_len, response->b_total_len)
;
284 }
285 }
286 assert(card_status == VCARD_DONE)((card_status == VCARD_DONE) ? (void) (0) : __assert_fail ("card_status == VCARD_DONE"
, "/home/stefan/src/qemu/qemu.org/qemu/libcacard/vreader.c", 286
, __PRETTY_FUNCTION__))
;
287 if (card_status == VCARD_DONE) {
8
Taking true branch
288 int size = MIN(*receive_buf_len, response->b_total_len)(((*receive_buf_len) < (response->b_total_len)) ? (*receive_buf_len
) : (response->b_total_len))
;
9
Within the expansion of the macro 'MIN':
a
Access to field 'b_total_len' results in a dereference of a null pointer (loaded from variable 'response')
289 memcpy(receive_buf, response->b_data, size);
290 *receive_buf_len = size;
291 }
292 vcard_response_delete(response);
293 vcard_apdu_delete(apdu);
294 vcard_free(card); /* free our reference */
295 return VREADER_OK;
296}
297
298struct VReaderListStruct {
299 VReaderListEntry *head;
300 VReaderListEntry *tail;
301};
302
303struct VReaderListEntryStruct {
304 VReaderListEntry *next;
305 VReaderListEntry *prev;
306 VReader *reader;
307};
308
309
310static VReaderListEntry *
311vreader_list_entry_new(VReader *reader)
312{
313 VReaderListEntry *new_reader_list_entry;
314
315 new_reader_list_entry = (VReaderListEntry *)
316 g_malloc(sizeof(VReaderListEntry));
317 new_reader_list_entry->next = NULL((void*)0);
318 new_reader_list_entry->prev = NULL((void*)0);
319 new_reader_list_entry->reader = vreader_reference(reader);
320 return new_reader_list_entry;
321}
322
323static void
324vreader_list_entry_delete(VReaderListEntry *entry)
325{
326 if (entry == NULL((void*)0)) {
327 return;
328 }
329 vreader_free(entry->reader);
330 g_free(entry);
331}
332
333
334static VReaderList *
335vreader_list_new(void)
336{
337 VReaderList *new_reader_list;
338
339 new_reader_list = (VReaderList *)g_malloc(sizeof(VReaderList));
340 new_reader_list->head = NULL((void*)0);
341 new_reader_list->tail = NULL((void*)0);
342 return new_reader_list;
343}
344
345void
346vreader_list_delete(VReaderList *list)
347{
348 VReaderListEntry *current_entry;
349 VReaderListEntry *next_entry = NULL((void*)0);
350 for (current_entry = vreader_list_get_first(list); current_entry;
351 current_entry = next_entry) {
352 next_entry = vreader_list_get_next(current_entry);
353 vreader_list_entry_delete(current_entry);
354 }
355 list->head = NULL((void*)0);
356 list->tail = NULL((void*)0);
357 g_free(list);
358}
359
360
361VReaderListEntry *
362vreader_list_get_first(VReaderList *list)
363{
364 return list ? list->head : NULL((void*)0);
365}
366
367VReaderListEntry *
368vreader_list_get_next(VReaderListEntry *current)
369{
370 return current ? current->next : NULL((void*)0);
371}
372
373VReader *
374vreader_list_get_reader(VReaderListEntry *entry)
375{
376 return entry ? vreader_reference(entry->reader) : NULL((void*)0);
377}
378
379static void
380vreader_queue(VReaderList *list, VReaderListEntry *entry)
381{
382 if (entry == NULL((void*)0)) {
383 return;
384 }
385 entry->next = NULL((void*)0);
386 entry->prev = list->tail;
387 if (list->head) {
388 list->tail->next = entry;
389 } else {
390 list->head = entry;
391 }
392 list->tail = entry;
393}
394
395static void
396vreader_dequeue(VReaderList *list, VReaderListEntry *entry)
397{
398 if (entry == NULL((void*)0)) {
399 return;
400 }
401 if (entry->next == NULL((void*)0)) {
402 list->tail = entry->prev;
403 } else if (entry->prev == NULL((void*)0)) {
404 list->head = entry->next;
405 } else {
406 entry->prev->next = entry->next;
407 entry->next->prev = entry->prev;
408 }
409 if ((list->tail == NULL((void*)0)) || (list->head == NULL((void*)0))) {
410 list->head = list->tail = NULL((void*)0);
411 }
412 entry->next = entry->prev = NULL((void*)0);
413}
414
415static VReaderList *vreader_list;
416static QemuMutex vreader_list_mutex;
417
418static void
419vreader_list_init(void)
420{
421 vreader_list = vreader_list_new();
422 qemu_mutex_init(&vreader_list_mutex);
423}
424
425static void
426vreader_list_lock(void)
427{
428 qemu_mutex_lock(&vreader_list_mutex);
429}
430
431static void
432vreader_list_unlock(void)
433{
434 qemu_mutex_unlock(&vreader_list_mutex);
435}
436
437static VReaderList *
438vreader_copy_list(VReaderList *list)
439{
440 VReaderList *new_list = NULL((void*)0);
441 VReaderListEntry *current_entry = NULL((void*)0);
442
443 new_list = vreader_list_new();
444 if (new_list == NULL((void*)0)) {
445 return NULL((void*)0);
446 }
447 for (current_entry = vreader_list_get_first(list); current_entry;
448 current_entry = vreader_list_get_next(current_entry)) {
449 VReader *reader = vreader_list_get_reader(current_entry);
450 VReaderListEntry *new_entry = vreader_list_entry_new(reader);
451
452 vreader_free(reader);
453 vreader_queue(new_list, new_entry);
454 }
455 return new_list;
456}
457
458VReaderList *
459vreader_get_reader_list(void)
460{
461 VReaderList *new_reader_list;
462
463 vreader_list_lock();
464 new_reader_list = vreader_copy_list(vreader_list);
465 vreader_list_unlock();
466 return new_reader_list;
467}
468
469VReader *
470vreader_get_reader_by_id(vreader_id_t id)
471{
472 VReader *reader = NULL((void*)0);
473 VReaderListEntry *current_entry = NULL((void*)0);
474
475 if (id == (vreader_id_t) -1) {
476 return NULL((void*)0);
477 }
478
479 vreader_list_lock();
480 for (current_entry = vreader_list_get_first(vreader_list); current_entry;
481 current_entry = vreader_list_get_next(current_entry)) {
482 VReader *creader = vreader_list_get_reader(current_entry);
483 if (creader->id == id) {
484 reader = creader;
485 break;
486 }
487 vreader_free(creader);
488 }
489 vreader_list_unlock();
490 return reader;
491}
492
493VReader *
494vreader_get_reader_by_name(const char *name)
495{
496 VReader *reader = NULL((void*)0);
497 VReaderListEntry *current_entry = NULL((void*)0);
498
499 vreader_list_lock();
500 for (current_entry = vreader_list_get_first(vreader_list); current_entry;
501 current_entry = vreader_list_get_next(current_entry)) {
502 VReader *creader = vreader_list_get_reader(current_entry);
503 if (strcmp(creader->name, name) == 0) {
504 reader = creader;
505 break;
506 }
507 vreader_free(creader);
508 }
509 vreader_list_unlock();
510 return reader;
511}
512
513/* called from card_emul to initialize the readers */
514VReaderStatus
515vreader_add_reader(VReader *reader)
516{
517 VReaderListEntry *reader_entry;
518
519 reader_entry = vreader_list_entry_new(reader);
520 if (reader_entry == NULL((void*)0)) {
521 return VREADER_OUT_OF_MEMORY;
522 }
523 vreader_list_lock();
524 vreader_queue(vreader_list, reader_entry);
525 vreader_list_unlock();
526 vevent_queue_vevent(vevent_new(VEVENT_READER_INSERT, reader, NULL((void*)0)));
527 return VREADER_OK;
528}
529
530
531VReaderStatus
532vreader_remove_reader(VReader *reader)
533{
534 VReaderListEntry *current_entry;
535
536 vreader_list_lock();
537 for (current_entry = vreader_list_get_first(vreader_list); current_entry;
538 current_entry = vreader_list_get_next(current_entry)) {
539 if (current_entry->reader == reader) {
540 break;
541 }
542 }
543 vreader_dequeue(vreader_list, current_entry);
544 vreader_list_unlock();
545 vreader_list_entry_delete(current_entry);
546 vevent_queue_vevent(vevent_new(VEVENT_READER_REMOVE, reader, NULL((void*)0)));
547 return VREADER_OK;
548}
549
550/*
551 * Generate VEVENT_CARD_INSERT or VEVENT_CARD_REMOVE based on vreader
552 * state. Separated from vreader_insert_card to allow replaying events
553 * for a given state.
554 */
555void
556vreader_queue_card_event(VReader *reader)
557{
558 vevent_queue_vevent(vevent_new(
559 reader->card ? VEVENT_CARD_INSERT : VEVENT_CARD_REMOVE, reader,
560 reader->card));
561}
562
563/*
564 * insert/remove a new card. for removal, card == NULL
565 */
566VReaderStatus
567vreader_insert_card(VReader *reader, VCard *card)
568{
569 vreader_lock(reader);
570 if (reader->card) {
571 /* decrement reference count */
572 vcard_free(reader->card);
573 reader->card = NULL((void*)0);
574 }
575 reader->card = vcard_reference(card);
576 vreader_unlock(reader);
577 vreader_queue_card_event(reader);
578 return VREADER_OK;
579}
580
581/*
582 * initialize all the static reader structures
583 */
584void
585vreader_init(void)
586{
587 vreader_list_init();
588}
589