Skip to content

Commit 4eb3835

Browse files
dkgkdfg65wb2osz
andauthored
Issue 617 - Buffer Overflow in KISS code. (#652)
(cherry picked from commit 694c954) Co-authored-by: wb2osz <wb2osz@comcast.net>
1 parent a231971 commit 4eb3835

3 files changed

Lines changed: 77 additions & 19 deletions

File tree

CMakeLists.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -229,16 +229,16 @@ if (C_CLANG OR C_GCC)
229229
# It might go back in someday when I have more patience to clean up all the warnings.
230230
#
231231

232-
# TODO:
233-
# Try error checking -fsanitize=bounds-strict -fsanitize=leak
234-
# Requires libubsan and liblsan, respectively.
235-
# Maybe -fstack-protector-all, -fstack-check
236232

237-
###set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wvla -ffast-math -ftree-vectorize -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE ${EXTRA_FLAGS}")
233+
# Address Sanitizer. See https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html
234+
# gcc links with libasan automatically when compiled with -fsanitize=address
235+
236+
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -g -Og -fno-optimize-sibling-calls -fno-omit-frame-pointer")
237+
238+
238239
if(FREEBSD)
239240
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wvla -ffast-math -ftree-vectorize -D_DEFAULT_SOURCE ${EXTRA_FLAGS}")
240241
else()
241-
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wvla -ffast-math -ftree-vectorize -D_GNU_SOURCE -fsanitize=bounds-strict ${EXTRA_FLAGS}")
242242
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wvla -ffast-math -ftree-vectorize -D_GNU_SOURCE ${EXTRA_FLAGS}")
243243
endif()
244244
#

src/deviceid.c

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// This file is part of Dire Wolf, an amateur radio packet TNC.
33
//
4-
// Copyright (C) 2023 John Langner, WB2OSZ
4+
// Copyright (C) 2023, 2025 John Langner, WB2OSZ
55
//
66
// This program is free software: you can redistribute it and/or modify
77
// it under the terms of the GNU General Public License as published by
@@ -53,6 +53,8 @@ static void unquote (int line, char *pin, char *pout);
5353
static int tocall_cmp (const void *px, const void *py);
5454
static int mice_cmp (const void *px, const void *py);
5555

56+
static void deviceid_term(void);
57+
5658
/*------------------------------------------------------------------
5759
*
5860
* Function: main
@@ -300,6 +302,7 @@ void deviceid_init(void)
300302
//dw_printf ("%d: %s\n", line, stuff);
301303
#endif
302304
// This is not very robust; everything better be in exactly the right format.
305+
// TODO: Be more forgiving.
303306

304307
if (strncmp(stuff, "mice:", strlen("mice:")) == 0) {
305308
section = mice_section;
@@ -361,12 +364,18 @@ void deviceid_init(void)
361364
}
362365
if (strncmp(stuff+3, "tocall: ", strlen("tocall: ")) == 0) {
363366
// Remove trailing wildcard characters ? * n
367+
// "APZ*" has quotes around it, inconsistent with everything else.
364368
char *r = stuff + strlen(stuff) - 1;
365-
while (r >= (char*)stuff && (*r == '?' || *r == '*' || *r == 'n')) {
369+
while (r >= (char*)stuff && (*r == '?' || *r == '*' || *r == 'n' || *r == '"')) {
366370
*r-- = '\0';
367371
}
368372

369-
strlcpy (ptocalls[tocalls_index].tocall, stuff+3+8, sizeof(ptocalls[tocalls_index].tocall));
373+
if (stuff[3+8] == '"') {
374+
strlcpy (ptocalls[tocalls_index].tocall, stuff+3+8 +1, sizeof(ptocalls[tocalls_index].tocall));
375+
}
376+
else {
377+
strlcpy (ptocalls[tocalls_index].tocall, stuff+3+8, sizeof(ptocalls[tocalls_index].tocall));
378+
}
370379

371380
// Remove trailing CR/LF or spaces.
372381
char *p = stuff + strlen(stuff) - 1;
@@ -375,10 +384,10 @@ void deviceid_init(void)
375384
}
376385
}
377386
else if (strncmp(stuff+3, "vendor: ", strlen("vendor: ")) == 0) {
378-
ptocalls[tocalls_index].vendor = strdup(stuff+3+8);
387+
ptocalls[tocalls_index].vendor = strdup(stuff+3+8);
379388
}
380389
else if (strncmp(stuff+3, "model: ", strlen("model: ")) == 0) {
381-
ptocalls[tocalls_index].model = strdup(stuff+3+7);
390+
ptocalls[tocalls_index].model = strdup(stuff+3+7);
382391
}
383392
break;
384393
}
@@ -413,23 +422,61 @@ void deviceid_init(void)
413422

414423
qsort (ptocalls, tocalls_count, sizeof(struct tocalls), tocall_cmp);
415424

416-
417425
#if TEST
418426
dw_printf ("MIC-E:\n");
419427
for (int i = 0; i < mice_count; i++) {
420-
dw_printf ("%s %s %s\n", pmice[i].suffix, pmice[i].vendor, pmice[i].model);
428+
dw_printf ("%s %s %s %s\n", pmice[i].prefix, pmice[i].suffix, pmice[i].vendor, pmice[i].model);
421429
}
422430
dw_printf ("TOCALLS:\n");
423431
for (int i = 0; i < tocalls_count; i++) {
424432
dw_printf ("%s %s %s\n", ptocalls[i].tocall, ptocalls[i].vendor, ptocalls[i].model);
425433
}
426434
#endif
427435

436+
atexit (deviceid_term);
428437
return;
429438

430439
} // end deviceid_init
431440

432441

442+
/*------------------------------------------------------------------
443+
*
444+
* Function: deviceid_term
445+
*
446+
* Purpose: Called when exiting to cleanup.
447+
*
448+
* In/Out: pmice
449+
* mice_count
450+
* ptocalls
451+
* tocalls_count
452+
*
453+
* Description: Free all the allocated memory.
454+
*
455+
* Mystery: Why does Address Sanitizer complain about a data leak
456+
* for 62 strdups?
457+
*
458+
*------------------------------------------------------------------*/
459+
460+
static void deviceid_term(void)
461+
{
462+
for (int n = 0; n < tocalls_count; n++) {
463+
if (ptocalls[n].model != NULL) free (ptocalls[n].model);
464+
if (ptocalls[n].vendor != NULL) free (ptocalls[n].vendor);
465+
}
466+
tocalls_count = 0;
467+
free (ptocalls);
468+
ptocalls = NULL;
469+
470+
for (int n = 0; n < mice_count; n++) {
471+
if (pmice[n].model != NULL) free (pmice[n].model);
472+
if (pmice[n].vendor != NULL) free (pmice[n].vendor);
473+
}
474+
mice_count = 0;
475+
free (pmice);
476+
pmice = NULL;
477+
}
478+
479+
433480
/*------------------------------------------------------------------
434481
*
435482
* Function: unquote
@@ -612,6 +659,7 @@ void deviceid_decode_dest (char *dest, char *device, size_t device_size)
612659
* https://github.com/wb2osz/aprsspec containing:
613660
* APRS Protocol Specification 1.2
614661
* Understanding APRS Packets
662+
*
615663
*------------------------------------------------------------------*/
616664

617665
// The strncmp documentation doesn't mention behavior if length is zero.

src/kiss_frame.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -251,10 +251,12 @@ int kiss_encapsulate (unsigned char *in, int ilen, unsigned char *out)
251251
*
252252
* Inputs: out - Where to put the resulting frame without
253253
* the escapes or FEND.
254+
* Storage must be at least as long as input.
255+
* Output can never be longer than input.
254256
* First byte is the "type indicator" with type and
255257
* channel but we don't care about that here.
256258
* We treat it like any other byte with special handling
257-
* if it happens to be FESC.
259+
* if it happens to be one of the escaped characters.
258260
* Note that this is "binary" data and can contain
259261
* nul (0x00) values. Don't treat it like a text string!
260262
*
@@ -280,7 +282,7 @@ int kiss_unwrap (unsigned char *in, int ilen, unsigned char *out)
280282
}
281283

282284
if (in[ilen-1] == FEND) {
283-
ilen--; /* Don't try to process below. */
285+
ilen--; /* Remove FEND from he end. */
284286
}
285287
else {
286288
text_color_set(DW_COLOR_ERROR);
@@ -342,6 +344,8 @@ int kiss_unwrap (unsigned char *in, int ilen, unsigned char *out)
342344
*
343345
* Inputs: kf - Current state of building a frame.
344346
* ch - A byte from the input stream.
347+
* Note that it can be any value 0-255.
348+
* This is binary data, not a nul terminated string.
345349
* debug - Activates debug output.
346350
* kps - KISS TCP port status block.
347351
* NULL for pseudo terminal and serial port.
@@ -442,8 +446,9 @@ void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug,
442446

443447

444448
if (ch == FEND) {
445-
446-
unsigned char unwrapped[AX25_MAX_PACKET_LEN];
449+
// Unwrapped result can't be longer than received encoded KISS.
450+
// kf->kiss_msg is MAX_KISS_LEN so that is enough for here.
451+
unsigned char unwrapped[MAX_KISS_LEN];
447452
int ulen;
448453

449454
/* End of frame. */
@@ -482,12 +487,17 @@ void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug,
482487
return;
483488
}
484489

485-
if (kf->kiss_len < MAX_KISS_LEN) {
490+
// Issue 617.
491+
// In the KS_COLLECTING state, non-FEND bytes were being collected up until
492+
// the MAX_KISS_LEN limit, leaving no room for appending the final FEND byte
493+
// at the end. By reducing the collection limit by one, there is room for
494+
// that final byte.
495+
if (kf->kiss_len < MAX_KISS_LEN - 1) {
486496
kf->kiss_msg[kf->kiss_len++] = ch;
487497
}
488498
else {
489499
text_color_set(DW_COLOR_ERROR);
490-
dw_printf ("KISS message exceeded maximum length.\n");
500+
dw_printf ("KISS message exceeded maximum length. Discarding excess.\n");
491501
}
492502
return;
493503
break;

0 commit comments

Comments
 (0)