aboutsummaryrefslogtreecommitdiff
path: root/brightnessctl.c
diff options
context:
space:
mode:
authorGravatar Miciah Masters <miciah.masters@gmail.com>2016-12-24 02:48:24 -0500
committerGravatar Miciah Dashiel Butler Masters <mmasters@redhat.com>2017-01-09 02:34:26 -0500
commit18ece5f9cc147999e57ed1bf139bcbd056185deb (patch)
tree904565fa3a8547ed90a3a42097c7e079e1b7940a /brightnessctl.c
parent2f85d31d0909cd23204fa810483fdff8854444cb (diff)
Fix buffer overflow in cat_with
Account for separators when computing the buffer size in cat_width in order to avoid overflowing the buffer. Previously, cat_width only accounted for the lengths of the strings being catenated, but not the separators, which could result in buffer overflows. For example, trace the execution of the following invocation of cat_with: char s[5] = "xxxx"; cat_with(' ', s, s, s, s, s, s, s, s); cat_with initialises size and length and allocates an initial buffer: size = 32; /* size = 32 */ length = 0; /* length = 0 */ buf = calloc(1, size + 1); /* allocated 33 bytes for buf */ The first iteration of the main loop in cat_with catenates the first string and a separator but fails to account for the separator in length: length += strlen(curr); /* length = 4 */ while (length + 2 > size) /* 4 + 2 > 32 is false */ strcat(buf, curr); /* written 5 bytes to buf */ strcat(buf, split); /* written 6 bytes to buf */ Now we have written the string "xxxx " (6 bytes including NUL) to buf, but length only counts the 4 bytes "xxxx" (excluding NUL). In successive iterations, the discrepancy between the value in length and the actual length of the string in the buffer grows: length += strlen(curr); /* length = 8 */ while (length + 2 > size) /* 8 + 2 > 32 is false */ strcat(buf, curr); /* written 10 bytes to buf */ strcat(buf, split); /* written 11 bytes to buf */ Now we have written "xxxx xxxx " (11 bytes incl. NUL). length += strlen(curr); /* length = 12 */ while (length + 2 > size) /* 12 + 2 > 32 is false */ strcat(buf, curr); /* written 15 bytes to buf */ strcat(buf, split); /* written 16 bytes to buf */ Now we have written "xxxx xxxx xxxx " (16 bytes incl. NUL). length += strlen(curr); /* length = 16 */ while (length + 2 > size) /* 16 + 2 > 32 is false */ strcat(buf, curr); /* written 20 bytes to buf */ strcat(buf, split); /* written 21 bytes to buf */ Now we have written "xxxx xxxx xxxx xxxx " (21 bytes incl. NUL). length += strlen(curr); /* length = 20 */ while (length + 2 > size) /* 20 + 2 > 32 is false */ strcat(buf, curr); /* written 25 bytes to buf */ strcat(buf, split); /* written 26 bytes to buf */ Now we have written "xxxx xxxx xxxx xxxx xxxx " (26 bytes incl. NUL). length += strlen(curr); /* length = 24 */ while (length + 2 > size) /* 24 + 2 > 32 is false */ strcat(buf, curr); /* written 30 bytes to buf */ strcat(buf, split); /* written 31 bytes to buf */ Now we have written "xxxx xxxx xxxx xxxx xxxx xxxx " (31 bytes incl. NUL). Eventually, the string can grow beyond the buffer before length grows large enough to cause a re-allocation: length += strlen(curr); /* length = 28 */ while (length + 2 > size) /* 28 + 2 > 32 is false */ strcat(buf, curr); /* written 35 bytes to buf */ strcat(buf, split); /* written 36 bytes to buf */ Note that we have not increased size or re-allocated the buffer, and so we have written "xxxx xxxx xxxx xxxx xxxx xxxx xxxx" (35 bytes incl. NUL) to a buffer for which we have allocated only 33 bytes.
Diffstat (limited to 'brightnessctl.c')
-rw-r--r--brightnessctl.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/brightnessctl.c b/brightnessctl.c
index 355fc86..60ca3a4 100644
--- a/brightnessctl.c
+++ b/brightnessctl.c
@@ -463,8 +463,10 @@ char *_cat_with(char c, ...) {
while (length + 2 > size)
buf = realloc(buf, size *= 2);
strcat(buf, curr);
- if ((curr = va_arg(va, char*)))
+ if ((curr = va_arg(va, char*))) {
+ length++;
strcat(buf, split);
+ }
}
return buf;
}