From 43ce6c4c0dc0e19814d2fc9661812697090ca773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20=C5=A0karvada?= Date: Wed, 20 May 2026 09:14:55 +0200 Subject: [PATCH] Fixed stack buffer overflow in rrdcached and added more security checks Resolves: RHEL-173259 --- rrdtool-1.7.0-CVE-2026-43958.patch | 239 +++++++++++++++++++++++++++++ rrdtool.spec | 10 +- 2 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 rrdtool-1.7.0-CVE-2026-43958.patch diff --git a/rrdtool-1.7.0-CVE-2026-43958.patch b/rrdtool-1.7.0-CVE-2026-43958.patch new file mode 100644 index 0000000..2c59fa7 --- /dev/null +++ b/rrdtool-1.7.0-CVE-2026-43958.patch @@ -0,0 +1,239 @@ +diff --git a/src/rrd_daemon.c b/src/rrd_daemon.c +index 23faeba..4e63d80 100644 +--- a/src/rrd_daemon.c ++++ b/src/rrd_daemon.c +@@ -521,7 +521,7 @@ static int check_pidfile(void) + { + int pid_fd; + pid_t pid; +- char pid_str[16]; ++ char pid_str[16] = {0}; + + pid_fd = open_pidfile("open", O_RDWR); + if (pid_fd < 0){ +@@ -676,11 +676,7 @@ static int add_response_info(listen_socket_t *sock, char *fmt, ...) /* {{{ */ + if (sock->batch_start) return 0; /* no extra info returned when in BATCH */ + + va_start(argp, fmt); +-#ifdef HAVE_VSNPRINTF + len = vsnprintf(buffer, sizeof(buffer), fmt, argp); +-#else +- len = vsprintf(buffer, fmt, argp); +-#endif + va_end(argp); + if (len < 0) + { +@@ -765,14 +761,12 @@ static int send_response (listen_socket_t *sock, response_code rc, + rc = RESP_OK; + } else { + rclen = snprintf(buffer, sizeof buffer, "%d ", lines); ++ if (rclen < 0 || rclen >= (int) sizeof(buffer)) ++ return -1; + } + + va_start(argp, fmt); +-#ifdef HAVE_VSNPRINTF + len = vsnprintf(buffer+rclen, sizeof(buffer)-rclen, fmt, argp); +-#else +- len = vsprintf(buffer+rclen, fmt, argp); +-#endif + va_end(argp); + if (len < 0) + return -1; +@@ -2285,7 +2279,8 @@ static int handle_request_create (HANDLER_PROTO) /* {{{ */ + char *file_copy = NULL, *dir = NULL, *dir2 = NULL; + char *tok; + int ac = 0; +- char *av[128]; ++#define MAX_CREATE_AV 128 ++ char *av[MAX_CREATE_AV]; + char **sources = NULL; + int sources_length = 0; + char *template = NULL; +@@ -2392,8 +2387,26 @@ static int handle_request_create (HANDLER_PROTO) /* {{{ */ + no_overwrite = 1; + continue; + } +- if( ! strncmp(tok,"DS:",3) ) { av[ac++]=tok; continue; } +- if( ! strncmp(tok,"RRA:",4) ) { av[ac++]=tok; continue; } ++ if( ! strncmp(tok,"DS:",3) ) { ++ if (ac >= MAX_CREATE_AV) { ++ rc = send_response(sock, RESP_ERR, ++ "Too many DS/RRA definitions (max %d)\n", ++ MAX_CREATE_AV); ++ goto done; ++ } ++ av[ac++]=tok; ++ continue; ++ } ++ if( ! strncmp(tok,"RRA:",4) ) { ++ if (ac >= MAX_CREATE_AV) { ++ rc = send_response(sock, RESP_ERR, ++ "Too many DS/RRA definitions (max %d)\n", ++ MAX_CREATE_AV); ++ goto done; ++ } ++ av[ac++]=tok; ++ continue; ++ } + rc = syntax_error(sock,cmd); + goto done; + } +diff --git a/src/rrd_graph.c b/src/rrd_graph.c +index fc7ee95..54aad94 100644 +--- a/src/rrd_graph.c ++++ b/src/rrd_graph.c +@@ -2449,7 +2449,7 @@ int draw_horizontal_grid( + } + } + } else { +- sprintf(graph_label, im->primary_axis_format, ++ snprintf(graph_label, sizeof(graph_label), im->primary_axis_format, + scaledstep * (double) i, sisym); + } + } +@@ -3767,10 +3767,14 @@ static cairo_status_t cairo_output( + { + image_desc_t *im = (image_desc_t*)closure; + +- im->rendered_image = +- (unsigned char*)realloc(im->rendered_image, im->rendered_image_size + length); +- if (im->rendered_image == NULL) +- return CAIRO_STATUS_WRITE_ERROR; ++ { ++ unsigned char *tmp = ++ (unsigned char *) realloc(im->rendered_image, ++ im->rendered_image_size + length); ++ if (tmp == NULL) ++ return CAIRO_STATUS_WRITE_ERROR; ++ im->rendered_image = tmp; ++ } + memcpy(im->rendered_image + im->rendered_image_size, data, length); + im->rendered_image_size += length; + return CAIRO_STATUS_SUCCESS; +@@ -4057,6 +4061,15 @@ int graph_paint_timestring( + (double *) malloc(sizeof(double) * im->xsize * 2); + int drawem = 0; + ++ if (foreY == NULL || foreX == NULL || ++ backY == NULL || backX == NULL) { ++ free(foreY); ++ free(foreX); ++ free(backY); ++ free(backX); ++ return -1; ++ } ++ + for (ii = 0; ii <= im->xsize; ii++) { + double ybase, ytop; + +@@ -5694,6 +5707,12 @@ int vdef_calc( + case VDEF_PERCENT:{ + rrd_value_t *array; + int field; ++ if (steps == 0) { ++ dst->vf.val = DNAN; ++ dst->vf.when = 0; ++ dst->vf.never = 1; ++ break; ++ } + if ((array = (rrd_value_t*)malloc(steps * sizeof(double))) == NULL) { + rrd_set_error("malloc VDEV_PERCENT"); + return -1; +@@ -5723,6 +5742,12 @@ int vdef_calc( + if (!isnan(data[step * src->ds_cnt])) { nancount++; } + } + /* and allocate it */ ++ if (nancount == 0) { ++ dst->vf.val = DNAN; ++ dst->vf.when = 0; ++ dst->vf.never = 1; ++ break; ++ } + if ((array = (rrd_value_t*)malloc(nancount * sizeof(double))) == NULL) { + rrd_set_error("malloc VDEV_PERCENT"); + return -1; +diff --git a/src/rrd_graph_helper.c b/src/rrd_graph_helper.c +index 9e5ffdd..c954018 100644 +--- a/src/rrd_graph_helper.c ++++ b/src/rrd_graph_helper.c +@@ -866,7 +866,7 @@ static int parse_xport(enum gf_en,parsedargs_t*,image_desc_t *const); + static void legend_shift(char *legend) + { + if (!legend || !legend[0]) { return; } +- memmove(legend+2,legend,strlen(legend)); ++ memmove(legend+2,legend,strlen(legend)+1); + legend[0]=' '; + legend[1]=' '; + } +diff --git a/src/rrd_xport.c b/src/rrd_xport.c +index fd7986d..0325dd9 100644 +--- a/src/rrd_xport.c ++++ b/src/rrd_xport.c +@@ -321,6 +321,16 @@ static int rrd_xport_fn( + /* printf("step: %lu\n",*step); */ + free(step_list); + ++ if (*step == 0) { ++ rrd_set_error("xport step is zero"); ++ free(ref_list); ++ for (unsigned long k = *col_cnt; k > 0; k--) ++ free(legend_list[k - 1]); ++ *col_cnt = 0; ++ free(legend_list); ++ return (-1); ++ } ++ + *start = im->start - im->start % (*step); + if ( im->start > *start ) { + *start = *start + *step; +@@ -337,24 +347,30 @@ static int rrd_xport_fn( + if (((*data) = + (rrd_value_t*)malloc((*col_cnt) * row_cnt * sizeof(rrd_value_t))) == NULL) { + free(ref_list); ++ for (unsigned long k = *col_cnt; k > 0; k--) ++ free(legend_list[k - 1]); ++ *col_cnt = 0; + free(legend_list); + rrd_set_error("malloc xport data area"); + return (-1); + } + dstptr = (*data); + ++ long unsigned int chosen_idx = 0; + /* fill data structure */ +- for (dst_row = 0; (int) dst_row < (int) row_cnt; dst_row++) { +- for (i = 0; i < (int) (*col_cnt); i++) { ++ for (dst_row = 0; dst_row < row_cnt; dst_row++) { ++ for (i = 0; (unsigned long) i < *col_cnt; i++) { + long vidx = im->gdes[ref_list[i]].vidx; + time_t now = *start + dst_row * *step; +- (*dstptr++) = im->gdes[vidx].data[(unsigned long) +- floor((double) +- (now - im->gdes[vidx].start) +- /im->gdes[vidx].step) +- * im->gdes[vidx].ds_cnt + +- im->gdes[vidx].ds]; + ++ if (im->gdes[vidx].step > 0 && ++ now >= im->gdes[vidx].start) { ++ chosen_idx = floor((double) (now - im->gdes[vidx].start) / im->gdes[vidx].step) * im->gdes[vidx].ds_cnt + im->gdes[vidx].ds; ++ ++ (*dstptr++) = im->gdes[vidx].data[chosen_idx]; ++ } else { ++ (*dstptr++) = DNAN; ++ } + } + } + +@@ -821,6 +837,10 @@ static void escapeJSON(char* txt,size_t len) { + char *tmp=(char*)malloc(len+2); + size_t l=strlen(txt); + size_t pos=0; ++ ++ if (tmp == NULL) ++ return; ++ + /* now iterate over the chars */ + for(size_t i=0;(i - 1.7.0-17 +- Fixed stack buffer overflow in rrdcached and added more security checks + Resolves: RHEL-173259 + * Thu Dec 6 2018 Jaroslav Škarvada - 1.7.0-16 - Rebuilt to fix broken build Related: rhbz#1636795