From 97d0f9f249c336d52654222f76238ca80c711bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20=C5=A0karvada?= Date: Wed, 20 May 2026 15:06:07 +0200 Subject: [PATCH] Fixed stack buffer overflow in rrdcached and added more security checks Resolves: RHEL-173257 --- rrdtool-1.7.2-CVE-2026-43958.patch | 254 +++++++++++++++++++++++++++++ rrdtool.spec | 10 +- 2 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 rrdtool-1.7.2-CVE-2026-43958.patch diff --git a/rrdtool-1.7.2-CVE-2026-43958.patch b/rrdtool-1.7.2-CVE-2026-43958.patch new file mode 100644 index 0000000..8ce05db --- /dev/null +++ b/rrdtool-1.7.2-CVE-2026-43958.patch @@ -0,0 +1,254 @@ +diff --git a/src/rrd_daemon.c b/src/rrd_daemon.c +index 54a4ec0..6058501 100644 +--- a/src/rrd_daemon.c ++++ b/src/rrd_daemon.c +@@ -334,7 +334,13 @@ static void do_log (int priority, const char *format, ...) + char buffer[32]; + pthread_mutex_lock(&log_lock); + time_t now = time(NULL); +- strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", gmtime(&now)); ++ struct tm tm_buf; ++ ++ if (gmtime_r(&now, &tm_buf) == NULL) { ++ snprintf(buffer, sizeof(buffer), "(time error)"); ++ } else { ++ strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm_buf); ++ } + fprintf(log_fh, "%s [%d] ", buffer, priority); + vfprintf(log_fh, format, args); + fprintf(log_fh, "\n"); +@@ -555,7 +561,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){ +@@ -740,11 +746,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) + { +@@ -829,14 +831,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; +@@ -2301,7 +2301,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; +@@ -2408,8 +2409,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 d21415e..654bf7c 100644 +--- a/src/rrd_graph.c ++++ b/src/rrd_graph.c +@@ -2471,7 +2471,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); + } + } +@@ -3797,10 +3797,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; +@@ -4089,6 +4093,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; + +@@ -5736,6 +5749,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; +@@ -5765,6 +5784,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 5632e67..e28c424 100644 +--- a/src/rrd_graph_helper.c ++++ b/src/rrd_graph_helper.c +@@ -870,7 +870,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 04a449c..3f01a40 100644 +--- a/src/rrd_xport.c ++++ b/src/rrd_xport.c +@@ -357,6 +357,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); + + *end = im->end - im->end % (*step); +@@ -371,26 +381,30 @@ static int rrd_xport_fn( + (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; ++ } + } + } + +@@ -963,6 +977,9 @@ static void escapeJSON( + size_t l = strlen(txt); + size_t pos = 0; + ++ if (tmp == NULL) ++ return; ++ + /* now iterate over the chars */ + for (size_t i = 0; (i < l) && (pos < len); i++, pos++) { + switch (txt[i]) { diff --git a/rrdtool.spec b/rrdtool.spec index a911906..b9d010a 100644 --- a/rrdtool.spec +++ b/rrdtool.spec @@ -18,7 +18,7 @@ Summary: Round Robin Database Tool to store and display time-series data Name: rrdtool Version: 1.7.2 -Release: 21%{?dist} +Release: 22%{?dist} License: GPLv2+ with exceptions URL: https://oss.oetiker.ch/rrdtool/ Source0: https://oss.oetiker.ch/%{name}/pub/%{name}-%{version}.tar.gz @@ -30,6 +30,9 @@ Patch3: rrdtool-1.6.0-ruby-2-fix.patch # enable php bindings on ppc Patch4: rrdtool-1.4.8-php-ppc-fix.patch Patch5: rrdtool-1.7.2-python-rpath-fix.patch +# backported from: +# https://github.com/oetiker/rrdtool-1.x/commit/4218ec7127ba6c7ea1c20d7c8ea6e2b3f83df73a +Patch6: rrdtool-1.7.2-CVE-2026-43958.patch Requires: dejavu-sans-mono-fonts Requires(post): systemd @@ -167,6 +170,7 @@ The %{name}-lua package includes RRDtool bindings for Lua. %endif %patch4 -p1 -b .php-ppc-fix %patch5 -p1 -b .python-rpath-fix +%patch6 -p1 -b .CVE-2026-43958 # Fix to find correct python dir on lib64 perl -pi -e 's|get_python_lib\(0,0,prefix|get_python_lib\(1,0,prefix|g' \ @@ -396,6 +400,10 @@ LD_LIBRARY_PATH=%{buildroot}%{_libdir} php -n \ %endif %changelog +* Wed May 20 2026 Jaroslav Škarvada - 1.7.2-22 +- Fixed stack buffer overflow in rrdcached and added more security checks + Resolves: RHEL-173257 + * Tue Aug 10 2021 Mohan Boddu - 1.7.2-21 - Rebuilt for IMA sigs, glibc 2.34, aarch64 flags Related: rhbz#1991688