diff --git a/channel.c b/channel.c
index 407ce632f..10401d595 100644
--- a/channel.c
+++ b/channel.c
@@ -226,13 +226,16 @@ static char * get_scan_element(const struct iio_channel *chn, size_t *length)
/* Returns a string containing the XML representation of this channel */
char * iio_channel_get_xml(const struct iio_channel *chn, size_t *length)
{
- size_t len = sizeof("")
- + strlen(chn->id) + (chn->name ? strlen(chn->name) : 0);
- char *ptr, *str, **attrs, *scan_element = NULL;
+ ssize_t len;
+ char *ptr, *eptr, *str, **attrs, *scan_element = NULL;
size_t *attrs_len, scan_element_len = 0;
unsigned int i;
+ len = sizeof("");
+ len += strnlen(chn->id, MAX_CHN_ID);
+ len += chn->is_output ? sizeof("output") : sizeof("input");
+ len += chn->name ? sizeof(" name= ") + strnlen(chn->name, MAX_CHN_NAME) : 0;
+
if (chn->is_scan_element) {
scan_element = get_scan_element(chn, &scan_element_len);
if (!scan_element)
@@ -260,26 +263,36 @@ char * iio_channel_get_xml(const struct iio_channel *chn, size_t *length)
str = malloc(len);
if (!str)
goto err_free_attrs;
+ ptr = str;
+ eptr = str + len;
- iio_snprintf(str, len, "id);
- ptr = strrchr(str, '\0');
+ if (len > 0) {
+ ptr += iio_snprintf(str, len, "id);
+ len = eptr - ptr;
+ }
- if (chn->name) {
- sprintf(ptr, " name=\"%s\"", chn->name);
- ptr = strrchr(ptr, '\0');
+ if (chn->name && len > 0) {
+ ptr += iio_snprintf(ptr, len, " name=\"%s\"", chn->name);
+ len = eptr - ptr;
}
- sprintf(ptr, " type=\"%s\" >", chn->is_output ? "output" : "input");
- ptr = strrchr(ptr, '\0');
+ if (len > 0) {
+ ptr += iio_snprintf(ptr, len, " type=\"%s\" >", chn->is_output ? "output" : "input");
+ len = eptr - ptr;
+ }
- if (chn->is_scan_element) {
- strcpy(ptr, scan_element);
+ if (chn->is_scan_element && len > scan_element_len) {
+ memcpy(ptr, scan_element, scan_element_len); /* Flawfinder: ignore */
ptr += scan_element_len;
+ len -= scan_element_len;
}
for (i = 0; i < chn->nb_attrs; i++) {
- strcpy(ptr, attrs[i]);
- ptr += attrs_len[i];
+ if (len > attrs_len[i]) {
+ memcpy(ptr, attrs[i], attrs_len[i]); /* Flawfinder: ignore */
+ ptr += attrs_len[i];
+ len -= attrs_len[i];
+ }
free(attrs[i]);
}
@@ -287,8 +300,19 @@ char * iio_channel_get_xml(const struct iio_channel *chn, size_t *length)
free(attrs);
free(attrs_len);
- strcpy(ptr, "");
- *length = ptr - str + sizeof("") - 1;
+ if (len > 0) {
+ ptr += iio_strlcpy(ptr, "", len);
+ len -= sizeof("") -1;
+ }
+
+ *length = ptr - str;
+
+ if (len < 0) {
+ IIO_ERROR("Internal libIIO error: iio_channel_get_xml str length isssue\n");
+ free(str);
+ return NULL;
+ }
+
return str;
err_free_attrs:
diff --git a/context.c b/context.c
index c12395c3d..eed8730c2 100644
--- a/context.c
+++ b/context.c
@@ -53,20 +53,25 @@ static const char xml_header[] = ""
/* Returns a string containing the XML representation of this context */
char * iio_context_create_xml(const struct iio_context *ctx)
{
- size_t len, *devices_len = NULL;
- char *str, *ptr, **devices = NULL;
+ ssize_t len;
+ size_t *devices_len = NULL;
+ char *str, *ptr, *eptr, **devices = NULL;
unsigned int i;
- len = strlen(ctx->name) + sizeof(xml_header) - 1 +
- sizeof("");
- if (ctx->description)
- len += strlen(ctx->description) +
- sizeof(" description=\"\"") - 1;
+ len = sizeof(xml_header) - 1;
+ len += strnlen(ctx->name, MAX_CTX_NAME);
+ len += sizeof("") - 1;
- for (i = 0; i < ctx->nb_attrs; i++)
- len += strlen(ctx->attrs[i]) +
- strlen(ctx->values[i]) +
- sizeof("");
+ if (ctx->description) {
+ len += strnlen(ctx->description, MAX_CTX_DESC);
+ len += sizeof(" description=\"\"") - 1;
+ }
+
+ for (i = 0; i < ctx->nb_attrs; i++) {
+ len += strnlen(ctx->attrs[i], MAX_ATTR_NAME);
+ len += strnlen(ctx->values[i], MAX_ATTR_VALUE);
+ len += sizeof("") - 1;
+ }
if (ctx->nb_devices) {
devices_len = malloc(ctx->nb_devices * sizeof(*devices_len));
@@ -94,32 +99,50 @@ char * iio_context_create_xml(const struct iio_context *ctx)
errno = ENOMEM;
goto err_free_devices;
}
-
- if (ctx->description) {
- iio_snprintf(str, len, "%s",
- xml_header, ctx->name, ctx->description);
- } else {
- iio_snprintf(str, len, "%s",
- xml_header, ctx->name);
+ eptr = str + len;
+ ptr = str;
+
+ if (len > 0) {
+ if (ctx->description) {
+ ptr += iio_snprintf(str, len, "%s",
+ xml_header, ctx->name, ctx->description);
+ } else {
+ ptr += iio_snprintf(str, len, "%s",
+ xml_header, ctx->name);
+ }
+ len = eptr - ptr;
}
- ptr = strrchr(str, '\0');
-
- for (i = 0; i < ctx->nb_attrs; i++)
- ptr += sprintf(ptr, "",
+ for (i = 0; i < ctx->nb_attrs && len > 0; i++) {
+ ptr += iio_snprintf(ptr, len, "",
ctx->attrs[i], ctx->values[i]);
-
+ len = eptr - ptr;
+ }
for (i = 0; i < ctx->nb_devices; i++) {
- strcpy(ptr, devices[i]);
- ptr += devices_len[i];
+ if (len > devices_len[i]) {
+ memcpy(ptr, devices[i], devices_len[i]); /* Flawfinder: ignore */
+ ptr += devices_len[i];
+ len -= devices_len[i];
+ }
free(devices[i]);
}
free(devices);
free(devices_len);
- strcpy(ptr, "");
+
+ if (len > 0) {
+ ptr += iio_strlcpy(ptr, "", len);
+ len -= sizeof("") - 1;
+ }
+
+ if (len < 0) {
+ IIO_ERROR("Internal libIIO error: iio_context_create_xml str length isssue\n");
+ free(str);
+ return NULL;
+ }
+
return str;
err_free_devices:
diff --git a/device.c b/device.c
index d3ec781c6..e847264a0 100644
--- a/device.c
+++ b/device.c
@@ -65,12 +65,18 @@ static char *get_attr_xml(const char *attr, size_t *length, enum iio_attr_type t
/* Returns a string containing the XML representation of this device */
char * iio_device_get_xml(const struct iio_device *dev, size_t *length)
{
- size_t len = sizeof("")
- + strlen(dev->id) + (dev->name ? strlen(dev->name) : 0);
- char *ptr, *str, **attrs, **channels, **buffer_attrs, **debug_attrs;
+ ssize_t len;
+ char *ptr, *eptr, *str, **attrs, **channels, **buffer_attrs, **debug_attrs;
size_t *attrs_len, *channels_len, *buffer_attrs_len, *debug_attrs_len;
unsigned int i, j, k;
+ len = sizeof(" ") - 1;
+ len += strnlen(dev->id, MAX_DEV_ID);
+ if (dev->name) {
+ len += sizeof(" name=\"\"") - 1;
+ len += strnlen(dev->name, MAX_DEV_NAME);
+ }
+
attrs_len = malloc(dev->nb_attrs * sizeof(*attrs_len));
if (!attrs_len)
return NULL;
@@ -143,21 +149,30 @@ char * iio_device_get_xml(const struct iio_device *dev, size_t *length)
str = malloc(len);
if (!str)
goto err_free_debug_attrs;
+ eptr = str + len;
+ ptr = str;
- iio_snprintf(str, len, "id);
- ptr = strrchr(str, '\0');
+ if (len > 0) {
+ ptr += iio_snprintf(str, len, "id);
+ len = eptr - ptr;
+ }
- if (dev->name) {
- sprintf(ptr, " name=\"%s\"", dev->name);
- ptr = strrchr(ptr, '\0');
+ if (dev->name && len > 0) {
+ ptr += iio_snprintf(ptr, len, " name=\"%s\"", dev->name);
+ len = eptr - ptr;
}
- strcpy(ptr, " >");
- ptr += 2;
+ if (len > 0) {
+ ptr += iio_strlcpy(ptr, " >", len);
+ len -= 2;
+ }
for (i = 0; i < dev->nb_channels; i++) {
- strcpy(ptr, channels[i]);
- ptr += channels_len[i];
+ if (len > channels_len[i]) {
+ memcpy(ptr, channels[i], channels_len[i]); /* Flawfinder: ignore */
+ ptr += channels_len[i];
+ len -= channels_len[i];
+ }
free(channels[i]);
}
@@ -165,8 +180,11 @@ char * iio_device_get_xml(const struct iio_device *dev, size_t *length)
free(channels_len);
for (i = 0; i < dev->nb_attrs; i++) {
- strcpy(ptr, attrs[i]);
- ptr += attrs_len[i];
+ if (len > attrs_len[i]) {
+ memcpy(ptr, attrs[i], attrs_len[i]); /* Flawfinder: ignore */
+ ptr += attrs_len[i];
+ len -= attrs_len[i];
+ }
free(attrs[i]);
}
@@ -174,8 +192,11 @@ char * iio_device_get_xml(const struct iio_device *dev, size_t *length)
free(attrs_len);
for (i = 0; i < dev->nb_buffer_attrs; i++) {
- strcpy(ptr, buffer_attrs[i]);
- ptr += buffer_attrs_len[i];
+ if (len > buffer_attrs_len[i]) {
+ memcpy(ptr, buffer_attrs[i], buffer_attrs_len[i]); /* Flawfinder: ignore */
+ ptr += buffer_attrs_len[i];
+ len -= buffer_attrs_len[i];
+ }
free(buffer_attrs[i]);
}
@@ -183,16 +204,30 @@ char * iio_device_get_xml(const struct iio_device *dev, size_t *length)
free(buffer_attrs_len);
for (i = 0; i < dev->nb_debug_attrs; i++) {
- strcpy(ptr, debug_attrs[i]);
- ptr += debug_attrs_len[i];
+ if (len > debug_attrs_len[i]) {
+ memcpy(ptr, debug_attrs[i], debug_attrs_len[i]); /* Flawfinder: ignore */
+ ptr += debug_attrs_len[i];
+ len -= debug_attrs_len[i];
+ }
free(debug_attrs[i]);
}
free(debug_attrs);
free(debug_attrs_len);
- strcpy(ptr, "");
- *length = ptr - str + sizeof("") - 1;
+ if (len > 0) {
+ ptr += iio_strlcpy(ptr, "", len);
+ len -= sizeof("") - 1;
+ }
+
+ *length = ptr - str;
+
+ if (len < 0) {
+ IIO_ERROR("Internal libIIO error: iio_device_get_xml str length isssue\n");
+ free(str);
+ return NULL;
+ }
+
return str;
err_free_debug_attrs:
diff --git a/iio-private.h b/iio-private.h
index 7077bbae6..dafcfd841 100644
--- a/iio-private.h
+++ b/iio-private.h
@@ -60,6 +60,15 @@
#define CLEAR_BIT(addr, bit) \
*(((uint32_t *) addr) + BIT_WORD(bit)) &= ~BIT_MASK(bit)
+/* 256 is the MAX_NAME (file name) on Linux, 4096 is PAGESIZE */
+#define MAX_CHN_ID 256 /* encoded in the sysfs filename */
+#define MAX_CHN_NAME 256 /* encoded in the sysfs filename */
+#define MAX_DEV_ID 256 /* encoded in the sysfs filename */
+#define MAX_DEV_NAME 256 /* encoded in the sysfs filename */
+#define MAX_CTX_NAME 256 /* nominally "xml" */
+#define MAX_CTX_DESC 256 /* nominally "linux ..." */
+#define MAX_ATTR_NAME 256 /* encoded in the sysfs filename */
+#define MAX_ATTR_VALUE 4096 /* Linux page size, could be anything */
/* ntohl/htonl are a nightmare to use in cross-platform applications,
* since they are defined in different headers on different platforms.
@@ -289,6 +298,7 @@ void iio_channel_init_finalize(struct iio_channel *chn);
unsigned int find_channel_modifier(const char *s, size_t *len_p);
char *iio_strdup(const char *str);
+size_t iio_strlcpy(char * __restrict dst, const char * __restrict src, size_t dsize);
int iio_context_add_attr(struct iio_context *ctx,
const char *key, const char *value);
diff --git a/utilities.c b/utilities.c
index 85a4813cc..2178f194c 100644
--- a/utilities.c
+++ b/utilities.c
@@ -214,3 +214,46 @@ char *iio_strdup(const char *str)
return buf;
#endif
}
+
+/* strlcpy is designed to be safer, more consistent, and less error prone
+ * replacements for strncpy, since it guarantees to NUL-terminate the result.
+ *
+ * This function
+ * Copyright (c) 1998, 2015 Todd C. Miller
+ * https://github.com/freebsd/freebsd/blob/master/sys/libkern/strlcpy.c
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * Copy string src to buffer dst of size dsize. At most dsize-1
+ * chars will be copied. Always NUL terminates (unless dsize == 0).
+ * Returns strlen(src); if retval >= dsize, truncation occurred.
+ *
+ * src is assumed to be null terminated, if it is not, this function will
+ * dereference unknown memory beyond src.
+ */
+size_t iio_strlcpy(char * __restrict dst, const char * __restrict src, size_t dsize)
+{
+ const char *osrc = src;
+ size_t nleft = dsize;
+
+ /* Copy as many bytes as will fit. */
+ if (nleft != 0) {
+ while (--nleft != 0) {
+ if ((*dst++ = *src++) == '\0')
+ break;
+ }
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src. */
+ if (nleft == 0) {
+ if (dsize != 0)
+ *dst = '\0'; /* NUL-terminate dst */
+
+ while (*src++)
+ ;
+ }
+
+ return(src - osrc - 1); /* count does not include NUL */
+}