From: Marc Schink Date: Sun, 22 May 2016 17:44:27 +0000 (+0200) Subject: helper: Make unhexify() robust on invalid data X-Git-Tag: v0.10.0-rc1~80 X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=commitdiff_plain;h=674141e8a7a6413cb803d90c2a20150260015f81;ds=sidebyside helper: Make unhexify() robust on invalid data The current implementation is not suitable for user provided data because it does not detect invalid inputs in many cases. For example, the string "aa0xbb" is successfully converted to the 3 bytes: 0xaa, 0x00 and 0xbb. An other example is "aabi" which is successfully converted to the 2 bytes: 0xaa and 0x0b. Both are obviously incorrect. Make unhexify() robust on invalid data and use more appropriate data types for its parameters. Also, add a small documentation for the function. Change-Id: Idb799beb86fc608b066c8a76365021ed44c7f890 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/3792 Tested-by: jenkins Reviewed-by: Tomas Vanek --- diff --git a/src/helper/binarybuffer.c b/src/helper/binarybuffer.c index c1e6322658..26aa8ccede 100644 --- a/src/helper/binarybuffer.c +++ b/src/helper/binarybuffer.c @@ -369,17 +369,42 @@ void bit_copy_discard(struct bit_copy_queue *q) } } -int unhexify(char *bin, const char *hex, int count) +/** + * Convert a string of hexadecimal pairs into its binary + * representation. + * + * @param[out] bin Buffer to store binary representation. The buffer size must + * be at least @p count. + * @param[in] hex String with hexadecimal pairs to convert into its binary + * representation. + * @param[in] count Number of hexadecimal pairs to convert. + * + * @return The number of converted hexadecimal pairs. + */ +size_t unhexify(uint8_t *bin, const char *hex, size_t count) { - int i, tmp; + size_t i; + char tmp; - for (i = 0; i < count; i++) { - if (sscanf(hex + (2 * i), "%02x", &tmp) != 1) - return i; - bin[i] = tmp; + if (!bin || !hex) + return 0; + + memset(bin, 0, count); + + for (i = 0; i < 2 * count; i++) { + if (hex[i] >= 'a' && hex[i] <= 'f') + tmp = hex[i] - 'a' + 10; + else if (hex[i] >= 'A' && hex[i] <= 'F') + tmp = hex[i] - 'A' + 10; + else if (hex[i] >= '0' && hex[i] <= '9') + tmp = hex[i] - '0'; + else + return i / 2; + + bin[i / 2] |= tmp << (4 * ((i + 1) % 2)); } - return i; + return i / 2; } int hexify(char *hex, const char *bin, int count, int out_maxlen) diff --git a/src/helper/binarybuffer.h b/src/helper/binarybuffer.h index dd0d275abd..b035779af5 100644 --- a/src/helper/binarybuffer.h +++ b/src/helper/binarybuffer.h @@ -234,7 +234,7 @@ void bit_copy_discard(struct bit_copy_queue *q); /* functions to convert to/from hex encoded buffer * used in ti-icdi driver and gdb server */ -int unhexify(char *bin, const char *hex, int count); +size_t unhexify(uint8_t *bin, const char *hex, size_t count); int hexify(char *hex, const char *bin, int count, int out_maxlen); void buffer_shr(void *_buf, unsigned buf_len, unsigned count); diff --git a/src/jtag/drivers/ti_icdi_usb.c b/src/jtag/drivers/ti_icdi_usb.c index 3db03b032d..7a6272fdb2 100644 --- a/src/jtag/drivers/ti_icdi_usb.c +++ b/src/jtag/drivers/ti_icdi_usb.c @@ -266,7 +266,7 @@ static int icdi_get_cmd_result(void *handle) if (h->read_buffer[offset] == 'E') { /* get error code */ - char result; + uint8_t result; if (unhexify(&result, h->read_buffer + offset + 1, 1) != 1) return ERROR_FAIL; return result; @@ -328,7 +328,7 @@ static int icdi_usb_version(void *handle) } /* convert reply */ - if (unhexify(version, h->read_buffer + 2, 4) != 4) { + if (unhexify((uint8_t *)version, h->read_buffer + 2, 4) != 4) { LOG_WARNING("unable to get ICDI version"); return ERROR_OK; } @@ -495,7 +495,7 @@ static int icdi_usb_read_reg(void *handle, int num, uint32_t *val) /* convert result */ uint8_t buf[4]; - if (unhexify((char *)buf, h->read_buffer + 2, 4) != 4) { + if (unhexify(buf, h->read_buffer + 2, 4) != 4) { LOG_ERROR("failed to convert result"); return ERROR_FAIL; } diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index 4c99ad2333..448c49c060 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -213,7 +213,7 @@ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_s goto done; /* Decode any symbol name in the packet*/ - int len = unhexify(cur_sym, strchr(packet + 8, ':') + 1, strlen(strchr(packet + 8, ':') + 1)); + size_t len = unhexify((uint8_t *)cur_sym, strchr(packet + 8, ':') + 1, strlen(strchr(packet + 8, ':') + 1)); cur_sym[len] = 0; if ((strcmp(packet, "qSymbol::") != 0) && /* GDB is not offering symbol lookup for the first time */ diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index d09a8be6e4..f85fa1bde9 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1449,7 +1449,7 @@ static int gdb_write_memory_packet(struct connection *connection, LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len); - if (unhexify((char *)buffer, separator, len) != (int)len) + if (unhexify(buffer, separator, len) != len) LOG_ERROR("unable to decode memory packet"); retval = target_write_buffer(target, addr, len, buffer); @@ -2277,7 +2277,7 @@ static int gdb_query_packet(struct connection *connection, if (packet_size > 6) { char *cmd; cmd = malloc((packet_size - 6) / 2 + 1); - int len = unhexify(cmd, packet + 6, (packet_size - 6) / 2); + size_t len = unhexify((uint8_t *)cmd, packet + 6, (packet_size - 6) / 2); cmd[len] = 0; /* We want to print all debug output to GDB connection */