====================
Bugfixes
--------
+* Fix a 1-byte heap buffer overflow in `checkUnusedValues()` that
+ triggered `*** buffer overflow detected ***` SIGABRT under glibc
+ fortified `strcat()` when reporting unused graph arguments. The
+ function under-allocated by one byte and silently relied on that
+ overflow to make its trailing `:` strip land on the right index.
+ Refactored to size buffers correctly and prepend the separator
+ rather than build-then-strip, so the two no longer have to agree.
+ Reported and original fix attempt in PR #1329 by @ppisar,
+ refactored fix by @oetiker
* Pad the Perl `$RRDs::VERSION` / `$RRDp::VERSION` numeric encoding so
two-digit minor releases compare monotonically. The numeric version
now uses three-digit zero-padded minor and patch fields, e.g.
parsedargs_t *pa)
{
char *res = NULL;
- size_t len = 0;
+ size_t used = 0; /* current strlen(res) */
for (int i = 0; i < pa->kv_cnt; i++) {
- if (!pa->kv_args[i].flag) {
- const size_t kvlen = strlen(pa->kv_args[i].keyvalue);
+ if (pa->kv_args[i].flag)
+ continue;
- len += kvlen + 1;
+ const size_t kvlen = strlen(pa->kv_args[i].keyvalue);
+ const size_t sep = res ? 1 : 0; /* ':' before all but the first */
+ const size_t need = used + sep + kvlen + 1; /* + trailing NUL */
+ char *t = res ? (char *) realloc(res, need)
+ : (char *) malloc(need);
- /* alloc/realloc if necessary and set to 0 */
- if (res) {
- char *t = (char *) realloc(res, len);
+ if (!t) {
+ return res; /* keep what we have on OOM */
+ }
+ if (!res) {
+ *t = 0; /* initialize on first allocation */
+ }
+ res = t;
- if (!t) {
- return res;
- }
- res = t;
- } else {
- res = malloc(len);
- if (!res) {
- return NULL;
- }
- *res = 0;
- }
- /* add key = value as originally given */
- strncat(res, pa->kv_args[i].keyvalue, kvlen);
- strcat(res, ":");
+ if (sep) {
+ res[used] = ':';
}
+ memcpy(res + used + sep, pa->kv_args[i].keyvalue, kvlen);
+ used += sep + kvlen;
+ res[used] = 0;
}
- /* if we got one, then strip the final : */
- if (res) {
- res[len - 1] = 0;
- }
- /* and return res */
+
return res;
}