Package: release.debian.org Severity: normal Tags: stretch User: release.debian....@packages.debian.org Usertags: pu
Hi, The Debian Security Team decided to not issue a security update for these CVE IDs: * CVE-2019-13451: service overflows histlogfn in history.c. * CVE-2019-13452: service overflows histlogfn in reportlog.c. * CVE-2019-13273: srdb overflows dbfn in csvinfo.c. * CVE-2019-13274: reflected XSS in csvinfo.c. * CVE-2019-13455: htmlquoted(hostname) overflows msgline in acknowledge.c. * CVE-2019-13484: htmlquoted(xymondreq) overflows errtxt appfeed.c. * CVE-2019-13485: hostname overflows selfurl in history.c. * CVE-2019-13486: htmlquoted(xymondreq) overflows errtxt in svcstatus.c. Hence I propose to do these as a normal stable update. Full source debdiff: diff -Nru xymon-4.3.28/debian/changelog xymon-4.3.28/debian/changelog --- xymon-4.3.28/debian/changelog 2017-03-03 23:18:20.000000000 +0100 +++ xymon-4.3.28/debian/changelog 2019-08-23 01:09:07.000000000 +0200 @@ -1,3 +1,22 @@ +xymon (4.3.28-2+deb9u1) stretch; urgency=high + + * Apply minimal upstream security patch to fix several (server-only) + vulnerabilities reported upstream by Graham Rymer: + + CVE-2019-13451: service overflows histlogfn in history.c. + + CVE-2019-13452: service overflows histlogfn in reportlog.c. + + CVE-2019-13273: srdb overflows dbfn in csvinfo.c. + + CVE-2019-13274: reflected XSS in csvinfo.c. + + CVE-2019-13455: htmlquoted(hostname) overflows msgline in + acknowledge.c. + + CVE-2019-13484: htmlquoted(xymondreq) overflows errtxt appfeed.c. + + CVE-2019-13485: hostname overflows selfurl in history.c. + + CVE-2019-13486: htmlquoted(xymondreq) overflows errtxt in + svcstatus.c. + + Closes: #935470 + * Include hostname validation regression fixes from 4.3.30, too. + + -- Axel Beckert <a...@debian.org> Fri, 23 Aug 2019 01:09:07 +0200 + xymon (4.3.28-2) unstable; urgency=low * xymon-client: Add dependency on net-tools. (Closes: #856315) diff -Nru xymon-4.3.28/debian/patches/91_4.3.29-CVEs.patch xymon-4.3.28/debian/patches/91_4.3.29-CVEs.patch --- xymon-4.3.28/debian/patches/91_4.3.29-CVEs.patch 1970-01-01 01:00:00.000000000 +0100 +++ xymon-4.3.28/debian/patches/91_4.3.29-CVEs.patch 2019-08-23 01:07:05.000000000 +0200 @@ -0,0 +1,760 @@ +Description: Isolated CVE Patchset + history.c (service overflows histlogfn) = CVE-2019-13451 + reportlog.c (service overflows histlogfn) = CVE-2019-13452 + csvinfo.c (srdb overflows dbfn) = CVE-2019-13273 + csvinfo.c (reflected XSS) = CVE-2019-13274 + acknowledge.c (htmlquoted(hostname) overflows msgline) = CVE-2019-13455 + + appfeed.c (htmlquoted(xymondreq) overflows errtxt) = CVE-2019-13484 + history.c (hostname overflows selfurl) = CVE-2019-13485 + svcstatus.c (htmlquoted(xymondreq) overflows errtxt) = CVE-2019-13486 + + Includes hostname validation regression fixes from 4.3.30. +Author: Japheth Cleaver <clea...@terabithia.org> +Bug-Debian: https://bugs.debian.org/935470 + +Index: xymon/lib/strfunc.h +=================================================================== +--- xymon/lib/strfunc.h (revision 8059) ++++ xymon/lib/strfunc.h (working copy) +@@ -29,5 +29,14 @@ + extern char *prehtmlquoted(char *s); + extern strbuffer_t *replacetext(char *original, char *oldtext, char *newtext); + ++#define SBUF_DEFINE(NAME) char *NAME = NULL; size_t NAME##_buflen = 0; ++#define STATIC_SBUF_DEFINE(NAME) static char *NAME = NULL; static size_t NAME##_buflen = 0; ++#define SBUF_MALLOC(NAME, LEN) { NAME##_buflen = (LEN); NAME = (char *)malloc((LEN)+1); } ++#define SBUF_CALLOC(NAME, NMEMB, LEN) { NAME##_buflen = (LEN); NAME = (char *)calloc(NMEMB, (LEN)+1); } ++#define SBUF_REALLOC(NAME, LEN) { NAME##_buflen = (LEN); NAME = (char *)realloc(NAME, (LEN)+1); } ++ ++/* How much can a string expand when htmlquoted? ' ' --> ' ' */ ++#define MAX_HTMLQUOTE_FACTOR 6 ++ + #endif + +Index: xymon/web/csvinfo.c +=================================================================== +--- xymon/web/csvinfo.c (revision 8059) ++++ xymon/web/csvinfo.c (working copy) +@@ -123,12 +123,13 @@ + return 1; + } + +- sprintf(dbfn, "%s/etc/%s", xgetenv("XYMONHOME"), srcdb); ++ snprintf(dbfn, sizeof(dbfn), "%s/etc/%s", xgetenv("XYMONHOME"), srcdb); + db = fopen(dbfn, "r"); + if (db == NULL) { +- char msg[PATH_MAX]; ++ SBUF_DEFINE(msg); + +- sprintf(msg, "Cannot open sourcedb %s\n", dbfn); ++ SBUF_MALLOC(msg, 30+strlen(htmlquoted(dbfn))); ++ snprintf(msg, msg_buflen, "Cannot open sourcedb %s\n", htmlquoted(dbfn)); + errormsg(msg); + return 1; + } +Index: xymon/web/svcstatus.c +=================================================================== +--- xymon/web/svcstatus.c (revision 8059) ++++ xymon/web/svcstatus.c (working copy) +@@ -31,7 +31,7 @@ + /* Command-line params */ + static enum { SRC_XYMOND, SRC_HISTLOGS, SRC_CLIENTLOGS } source = SRC_XYMOND; + static int wantserviceid = 1; +-static char *multigraphs = ",disk,inode,qtree,quotas,snapshot,TblSpace,if_load,"; ++SBUF_DEFINE(multigraphs); + static int locatorbased = 0; + static char *critconfigfn = NULL; + static char *accessfn = NULL; +@@ -42,12 +42,12 @@ + static char *tstamp = NULL; + static char *nkprio = NULL, *nkttgroup = NULL, *nkttextra = NULL; + static enum { FRM_STATUS, FRM_CLIENT } outform = FRM_STATUS; +-static char *clienturi = NULL; ++STATIC_SBUF_DEFINE(clienturi); + static int backsecs = 0; + static time_t fromtime = 0, endtime = 0; + + static char errortxt[1000]; +-static char *hostdatadir = NULL; ++STATIC_SBUF_DEFINE(hostdatadir); + + + static void errormsg(int status, char *msg) +@@ -148,12 +148,13 @@ + + if (outform == FRM_STATUS) { + char *p, *req; ++ char *hostquoted = htmlquoted(hostname); + + req = getenv("SCRIPT_NAME"); +- clienturi = (char *)malloc(strlen(req) + 10 + strlen(htmlquoted(hostname))); +- strcpy(clienturi, req); ++ SBUF_MALLOC(clienturi, strlen(req) + 10 + strlen(hostquoted)); ++ strncpy(clienturi, req, clienturi_buflen); + p = strchr(clienturi, '?'); if (p) *p = '\0'; else p = clienturi + strlen(clienturi); +- sprintf(p, "?CLIENT=%s", htmlquoted(hostname)); ++ snprintf(p, (clienturi_buflen - (clienturi - p)), "?CLIENT=%s", hostquoted); + } + + return 0; +@@ -194,7 +195,8 @@ + int color = 0, flapping = 0; + char timesincechange[100]; + time_t logtime = 0, acktime = 0, disabletime = 0; +- char *log = NULL, *firstline = NULL, *sender = NULL, *clientid = NULL, *flags = NULL; /* These are free'd */ ++ SBUF_DEFINE(firstline); ++ char *log = NULL, *sender = NULL, *clientid = NULL, *flags = NULL; /* These are free'd */ + char *restofmsg = NULL, *ackmsg = NULL, *dismsg = NULL, *acklist=NULL, *modifiers = NULL; /* These are just used */ + int ishtmlformatted = 0; + int clientavail = 0; +@@ -231,30 +233,32 @@ + + s = xgetenv("CLIENTLOGS"); + if (s) { +- hostdatadir = (char *)malloc(strlen(s) + strlen(hostname) + 12); +- sprintf(hostdatadir, "%s/%s", s, hostname); ++ SBUF_MALLOC(hostdatadir, strlen(s) + strlen(hostname) + 12); ++ snprintf(hostdatadir, hostdatadir_buflen, "%s/%s", s, hostname); + } + else { + s = xgetenv("XYMONVAR"); +- hostdatadir = (char *)malloc(strlen(s) + strlen(hostname) + 12); +- sprintf(hostdatadir, "%s/hostdata/%s", s, hostname); ++ SBUF_MALLOC(hostdatadir, strlen(s) + strlen(hostname) + 12); ++ snprintf(hostdatadir, hostdatadir_buflen, "%s/hostdata/%s", s, hostname); + } + } + + if (outform == FRM_CLIENT) { + if (source == SRC_XYMOND) { +- char *xymondreq; ++ SBUF_DEFINE(xymondreq); + int xymondresult; + sendreturn_t *sres = newsendreturnbuf(1, NULL); + +- xymondreq = (char *)malloc(1024 + strlen(hostname) + (service ? strlen(service) : 0)); +- sprintf(xymondreq, "clientlog %s", hostname); +- if (service && *service) sprintf(xymondreq + strlen(xymondreq), " section=%s", service); ++ SBUF_MALLOC(xymondreq, 1024 + strlen(hostname) + (service ? strlen(service) : 0)); ++ snprintf(xymondreq, xymondreq_buflen, "clientlog %s", hostname); ++ if (service && *service) snprintf(xymondreq + strlen(xymondreq), (xymondreq_buflen - strlen(xymondreq)), " section=%s", service); + + xymondresult = sendmessage(xymondreq, NULL, XYMON_TIMEOUT, sres); + if (xymondresult != XYMONSEND_OK) { +- char *errtxt = (char *)malloc(1024 + strlen(xymondreq)); +- sprintf(errtxt, "Status not available: Req=%s, result=%d\n", htmlquoted(xymondreq), xymondresult); ++ SBUF_DEFINE(errtxt); ++ ++ SBUF_MALLOC(errtxt, 1024 + MAX_HTMLQUOTE_FACTOR*strlen(xymondreq)); ++ snprintf(errtxt, errtxt_buflen, "Status not available: Req=%s, result=%d\n", htmlquoted(xymondreq), xymondresult); + errormsg(500, errtxt); + return 1; + } +@@ -267,7 +271,7 @@ + char logfn[PATH_MAX]; + FILE *fd; + +- sprintf(logfn, "%s/%s", hostdatadir, tstamp); ++ snprintf(logfn, sizeof(logfn), "%s/%s", hostdatadir, tstamp); + fd = fopen(logfn, "r"); + if (fd) { + struct stat st; +@@ -295,7 +299,7 @@ + sethostenv_refresh(600); + color = COL_GREEN; + logtime = getcurrenttime(NULL); +- strcpy(timesincechange, "0 minutes"); ++ strncpy(timesincechange, "0 minutes", sizeof(timesincechange)); + + if (strcmp(service, xgetenv("TRENDSCOLUMN")) == 0) { + if (locatorbased) { +@@ -331,18 +335,20 @@ + } + } + else if (source == SRC_XYMOND) { +- char *xymondreq; ++ SBUF_DEFINE(xymondreq); + int xymondresult; + char *items[25]; + int icount; + time_t logage, clntstamp; +- char *sumline, *msg, *p, *compitem, *complist; ++ char *sumline, *msg, *compitem, *complist; + sendreturn_t *sres; + + if (loadhostdata(hostname, &ip, &displayname, &compacts, 0) != 0) return 1; + + complist = NULL; + if (compacts && *compacts) { ++ char *p; ++ + compitem = strtok(compacts, ","); + while (compitem && !complist) { + p = strchr(compitem, '='); if (p) *p = '\0'; +@@ -363,15 +369,15 @@ + } + + freeregex(dummy); +- xymondreq = (char *)malloc(1024 + strlen(hostname) + strlen(service)); +- sprintf(xymondreq, "xymondlog host=%s test=%s fields=hostname,testname,color,flags,lastchange,logtime,validtime,acktime,disabletime,sender,cookie,ackmsg,dismsg,client,acklist,XMH_IP,XMH_DISPLAYNAME,clntstamp,flapinfo,modifiers", hostname, service); ++ SBUF_MALLOC(xymondreq, 1024 + strlen(hostname) + strlen(service)); ++ snprintf(xymondreq, xymondreq_buflen, "xymondlog host=%s test=%s fields=hostname,testname,color,flags,lastchange,logtime,validtime,acktime,disabletime,sender,cookie,ackmsg,dismsg,client,acklist,XMH_IP,XMH_DISPLAYNAME,clntstamp,flapinfo,modifiers", hostname, service); + } + else { + pcre *dummy = NULL; +- char *re; ++ SBUF_DEFINE(re); + +- re = (char *)malloc(5 + strlen(complist)); +- sprintf(re, "^(%s)$", complist); ++ SBUF_MALLOC(re, 5 + strlen(complist)); ++ snprintf(re, re_buflen, "^(%s)$", complist); + dummy = compileregex(re); + if (dummy == NULL) { + errormsg(500, "Invalid testname pattern"); +@@ -379,8 +385,8 @@ + } + + freeregex(dummy); +- xymondreq = (char *)malloc(1024 + strlen(hostname) + strlen(re)); +- sprintf(xymondreq, "xymondboard host=^%s$ test=%s fields=testname,color,lastchange", hostname, re); ++ SBUF_MALLOC(xymondreq, 1024 + strlen(hostname) + strlen(re)); ++ snprintf(xymondreq, xymondreq_buflen, "xymondboard host=^%s$ test=%s fields=testname,color,lastchange", hostname, re); + } + + sres = newsendreturnbuf(1, NULL); +@@ -393,6 +399,8 @@ + } + + if (!complist) { ++ char *p; ++ + sumline = log; p = strchr(log, '\n'); *p = '\0'; + msg = (p+1); p = strchr(msg, '\n'); + if (!p) { +@@ -438,20 +446,21 @@ + color = parse_color(items[2]); + flags = strdup(items[3]); + logage = getcurrenttime(NULL) - atoi(items[4]); +- timesincechange[0] = '\0'; p = timesincechange; ++ timesincechange[0] = '\0'; ++ p = timesincechange; + { + int days = (int) (logage / 86400); + int hours = (int) ((logage % 86400) / 3600); + int minutes = (int) ((logage % 3600) / 60); + +- if (days > 1) p += sprintf(p, "%d days, ", days); +- else if (days == 1) p += sprintf(p, "1 day, "); ++ if (days > 1) p += snprintf(p, (sizeof(timesincechange) - (p - timesincechange)), "%d days, ", days); ++ else if (days == 1) p += snprintf(p, (sizeof(timesincechange) - (p - timesincechange)), "1 day, "); + +- if (hours == 1) p += sprintf(p, "1 hour, "); +- else p += sprintf(p, "%d hours, ", hours); ++ if (hours == 1) p += snprintf(p, (sizeof(timesincechange) - (p - timesincechange)), "1 hour, "); ++ else p += snprintf(p, (sizeof(timesincechange) - (p - timesincechange)), "%d hours, ", hours); + +- if (minutes == 1) p += sprintf(p, "1 minute"); +- else p += sprintf(p, "%d minutes", minutes); ++ if (minutes == 1) p += snprintf(p, (sizeof(timesincechange) - (p - timesincechange)), "1 minute"); ++ else p += snprintf(p, (sizeof(timesincechange) - (p - timesincechange)), "%d minutes", minutes); + } + logtime = atoi(items[5]); + if (items[7] && strlen(items[7])) acktime = atoi(items[7]); +@@ -481,7 +490,7 @@ + /* Compressed status display */ + strbuffer_t *cmsg; + char *row, *p_row, *p_fld; +- char *nonhistenv; ++ SBUF_DEFINE(nonhistenv); + + color = COL_GREEN; + +@@ -520,15 +529,15 @@ + sethostenv(displayname, ip, service, colorname(color), hostname); + sethostenv_refresh(60); + logtime = getcurrenttime(NULL); +- strcpy(timesincechange, "0 minutes"); ++ strncpy(timesincechange, "0 minutes", sizeof(timesincechange)); + + log = restofmsg = grabstrbuffer(cmsg); + +- firstline = (char *)malloc(1024); +- sprintf(firstline, "%s Compressed status display\n", colorname(color)); ++ SBUF_MALLOC(firstline, 1024); ++ snprintf(firstline, firstline_buflen, "%s Compressed status display\n", colorname(color)); + +- nonhistenv = (char *)malloc(10 + strlen(service)); +- sprintf(nonhistenv, "NONHISTS=%s", service); ++ SBUF_MALLOC(nonhistenv, 10 + strlen(service)); ++ snprintf(nonhistenv, nonhistenv_buflen, "NONHISTS=%s", service); + putenv(nonhistenv); + } + } +@@ -553,7 +562,7 @@ + hostnamedash = strdup(hostname); + p = hostnamedash; while ((p = strchr(p, '.')) != NULL) *p = '_'; + p = hostnamedash; while ((p = strchr(p, ',')) != NULL) *p = '_'; +- sprintf(logfn, "%s/%s/%s/%s", xgetenv("XYMONHISTLOGS"), hostnamedash, service, tstamp); ++ snprintf(logfn, sizeof(logfn), "%s/%s/%s/%s", xgetenv("XYMONHISTLOGS"), hostnamedash, service, tstamp); + xfree(hostnamedash); + p = tstamp; while ((p = strchr(p, '_')) != NULL) *p = ' '; + sethostenv_histlog(tstamp); +@@ -644,8 +653,8 @@ + errprintf("Cannot find hostdata files for host %s\n", hostname); + } + else { +- clienturi = (char *)realloc(clienturi, 1024 + strlen(cgiurl) + strlen(htmlquoted(hostname)) + strlen(clientid)); +- sprintf(clienturi, "%s/svcstatus.sh?CLIENT=%s&TIMEBUF=%s", ++ SBUF_REALLOC(clienturi, 1024 + strlen(cgiurl) + MAX_HTMLQUOTE_FACTOR*strlen(htmlquoted(hostname)) + strlen(clientid)); ++ snprintf(clienturi, clienturi_buflen, "%s/svcstatus.sh?CLIENT=%s&TIMEBUF=%s", + cgiurl, htmlquoted(hostname), clientid); + } + } +@@ -653,12 +662,14 @@ + char logfn[PATH_MAX]; + struct stat st; + +- sprintf(logfn, "%s/%s", hostdatadir, clientid); ++ snprintf(logfn, sizeof(logfn), "%s/%s", hostdatadir, clientid); + clientavail = (stat(logfn, &st) == 0); + + if (clientavail) { +- clienturi = (char *)realloc(clienturi, 1024 + strlen(clienturi) + strlen(clientid)); +- sprintf(clienturi + strlen(clienturi), "&TIMEBUF=%s", clientid); ++ int curlen = strlen(clienturi); ++ ++ SBUF_REALLOC(clienturi, 1024 + curlen + strlen(clientid)); ++ snprintf(clienturi + curlen, (clienturi_buflen - curlen), "&TIMEBUF=%s", clientid); + } + } + } +@@ -708,6 +719,8 @@ + int argi; + char *envarea = NULL; + ++ multigraphs = ",disk,inode,qtree,quotas,snapshot,TblSpace,if_load,"; ++ + for (argi = 1; (argi < argc); argi++) { + if (strcmp(argv[argi], "--historical") == 0) { + source = SRC_HISTLOGS; +@@ -739,8 +752,8 @@ + } + else if (argnmatch(argv[argi], "--multigraphs=")) { + char *p = strchr(argv[argi], '='); +- multigraphs = (char *)malloc(strlen(p+1) + 3); +- sprintf(multigraphs, ",%s,", p+1); ++ SBUF_MALLOC(multigraphs, strlen(p+1) + 3); ++ snprintf(multigraphs, multigraphs_buflen, ",%s,", p+1); + } + else if (strcmp(argv[argi], "--no-disable") == 0) { + showenadis = 0; +Index: xymon/web/history.c +=================================================================== +--- xymon/web/history.c (revision 8059) ++++ xymon/web/history.c (working copy) +@@ -21,7 +21,7 @@ + + #include "libxymon.h" + +-static char selfurl[PATH_MAX]; ++SBUF_DEFINE(selfurl); + static time_t req_endtime = 0; + static char *displayname = NULL; + static int wantserviceid = 1; +@@ -605,8 +605,10 @@ + */ + + if (strcasecmp(cwalk->name, "HISTFILE") == 0) { +- char *p = strrchr(cwalk->value, '.'); ++ char *p = cwalk->value + strspn(cwalk->value, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.,"); ++ *p = '\0'; + ++ p = strrchr(cwalk->value, '.'); + if (p) { *p = '\0'; service = strdup(p+1); } + hostname = strdup(basename(cwalk->value)); + while ((p = strchr(hostname, ','))) *p = '.'; +@@ -644,7 +646,6 @@ + int main(int argc, char *argv[]) + { + char histlogfn[PATH_MAX]; +- char tailcmd[PATH_MAX]; + FILE *fd; + time_t start1d, start1w, start4w, start1y; + reportinfo_t repinfo1d, repinfo1w, repinfo4w, repinfo1y, dummyrep; +@@ -673,22 +674,25 @@ + cgidata = cgi_request(); + parse_query(); + ++ SBUF_MALLOC(selfurl, 4096); ++ + /* Build our own URL */ +- sprintf(selfurl, "%s", histcgiurl(hostname, service)); ++ snprintf(selfurl, selfurl_buflen, "%s", histcgiurl(hostname, service)); + + p = selfurl + strlen(selfurl); +- sprintf(p, "&BARSUMS=%d", barsums); ++ snprintf(p, selfurl_buflen - (p - selfurl), "&BARSUMS=%d", barsums); + + if (strlen(ip)) { ++ SBUF_REALLOC(selfurl, selfurl_buflen + 6*strlen(ip)); + p = selfurl + strlen(selfurl); +- sprintf(p, "&IP=%s", htmlquoted(ip)); ++ snprintf(p, selfurl_buflen - (p - selfurl), "&IP=%s", htmlquoted(ip)); + } + + if (entrycount) { + p = selfurl + strlen(selfurl); +- sprintf(p, "&ENTRIES=%d", entrycount); ++ snprintf(p, selfurl_buflen - (p - selfurl), "&ENTRIES=%d", entrycount); + } +- else strcat(selfurl, "&ENTRIES=ALL"); ++ else strncat(selfurl, "&ENTRIES=ALL", selfurl_buflen - strlen(selfurl)); + + if (usepct) { + /* Must modify 4-week charts to be 5-weeks, or the last day is 19% of the bar */ +@@ -704,7 +708,7 @@ + len1y = 10; bartitle1y = "10 month summary"; + } + +- sprintf(histlogfn, "%s/%s.%s", xgetenv("XYMONHISTDIR"), commafy(hostname), service); ++ snprintf(histlogfn, sizeof(histlogfn), "%s/%s.%s", xgetenv("XYMONHISTDIR"), commafy(hostname), service); + fd = fopen(histlogfn, "r"); + if (fd == NULL) { + errormsg("Cannot open history file"); +@@ -752,9 +756,13 @@ + fclose(fd); + } + else { ++ SBUF_DEFINE(tailcmd); ++ + /* Last 50 entries - we cheat and use "tail" in a pipe to pick the entries */ + fclose(fd); +- sprintf(tailcmd, "tail -%d %s", entrycount, histlogfn); ++ SBUF_MALLOC(tailcmd, 1024 + strlen(histlogfn)); ++ ++ snprintf(tailcmd, tailcmd_buflen, "tail -%d %s", entrycount, histlogfn); + fd = popen(tailcmd, "r"); + if (fd == NULL) errormsg("Cannot run tail on the histfile"); + parse_historyfile(fd, &dummyrep, NULL, NULL, 0, getcurrenttime(NULL), 1, reportwarnlevel, reportgreenlevel, reportwarnstops, NULL); +Index: xymon/web/acknowledge.c +=================================================================== +--- xymon/web/acknowledge.c (revision 8059) ++++ xymon/web/acknowledge.c (working copy) +@@ -158,14 +158,14 @@ + void generate_ackline(FILE *output, char *hname, char *tname, char *ackcode) + { + static int num = 0; +- char numstr[10]; ++ char numstr[15]; + + num++; + if (ackcode) { +- sprintf(numstr, "%d", num); ++ snprintf(numstr, sizeof(numstr), "%d", num); + } + else { +- strcpy(numstr, "all"); ++ strncpy(numstr, "all", sizeof(numstr)); + } + + fprintf(output, "<tr>\n"); +@@ -242,7 +242,7 @@ + NULL, NULL); + } + else { +- char *cmd; ++ SBUF_DEFINE(cmd); + char *respbuf = NULL; + char *hostname, *pagename; + int gotfilter = 0, filtererror = 0; +@@ -251,12 +251,12 @@ + + headfoot(stdout, "acknowledge", "", "header", COL_RED); + +- cmd = (char *)malloc(1024); +- strcpy(cmd, "xymondboard fields=hostname,testname,cookie color="); ++ SBUF_MALLOC(cmd, 1024); ++ strncpy(cmd, "xymondboard fields=hostname,testname,cookie color=", cmd_buflen); + for (col = 0; (col < COL_COUNT); col++) { + if ((1 << col) & alertcolors) { +- if (!firstcolor) strcat(cmd, ","); +- strcat(cmd, colorname(col)); ++ if (!firstcolor) strncat(cmd, ",", cmd_buflen - strlen(cmd)); ++ strncat(cmd, colorname(col), cmd_buflen - strlen(cmd)); + firstcolor = 0; + } + } +@@ -265,16 +265,16 @@ + if (obeycookies && !gotfilter && ((hostname = get_cookie("host")) != NULL)) { + if (*hostname) { + pcre *dummy; +- char *re; +- +- re = (char *)malloc(3+strlen(hostname)); +- sprintf(re, "^%s$", hostname); ++ SBUF_DEFINE(re); ++ ++ SBUF_MALLOC(re, 3+strlen(hostname)); ++ snprintf(re, re_buflen, "^%s$", hostname); + dummy = compileregex(re); + if (dummy) { + /* Valid expression */ + freeregex(dummy); +- cmd = (char *)realloc(cmd, 1024 + strlen(cmd) + strlen(re)); +- sprintf(cmd + strlen(cmd), " host=%s", re); ++ SBUF_REALLOC(cmd, 1024 + strlen(cmd) + strlen(re)); ++ snprintf(cmd + strlen(cmd), cmd_buflen - strlen(cmd), " host=%s", re); + gotfilter = 1; + } + else { +@@ -287,16 +287,16 @@ + if (obeycookies && !gotfilter && ((pagename = get_cookie("pagepath")) != NULL)) { + if (*pagename) { + pcre *dummy; +- char *re; ++ SBUF_DEFINE(re); + +- re = (char *)malloc(8 + strlen(pagename)*2); +- sprintf(re, "%s$|^%s/.+", pagename, pagename); ++ SBUF_MALLOC(re, 8 + strlen(pagename)*2); ++ snprintf(re, re_buflen, "%s$|^%s/.+", pagename, pagename); + dummy = compileregex(re); + if (dummy) { + /* Valid expression */ + freeregex(dummy); +- cmd = (char *)realloc(cmd, 1024 + strlen(cmd) + strlen(re)); +- sprintf(cmd + strlen(cmd), " page=%s", re); ++ SBUF_REALLOC(cmd, 1024 + strlen(cmd) + strlen(re)); ++ snprintf(cmd + strlen(cmd), cmd_buflen - strlen(cmd), " page=%s", re); + gotfilter = 1; + } + else { +@@ -353,12 +353,13 @@ + } + } + else if ( (nopin && (cgi_method == CGI_POST)) || (!nopin && (cgidata != NULL)) ) { +- char *xymonmsg; +- char *acking_user = ""; ++ SBUF_DEFINE(xymonmsg); ++ SBUF_DEFINE(acking_user); + acklist_t *awalk; + strbuffer_t *response = newstrbuffer(0); + int count = 0; + ++ acking_user = ""; + + /* We only want to accept posts from certain pages */ + { +@@ -375,9 +376,9 @@ + if (getenv("REMOTE_USER")) { + char *remaddr = getenv("REMOTE_ADDR"); + +- acking_user = (char *)malloc(1024 + strlen(getenv("REMOTE_USER")) + (remaddr ? strlen(remaddr) : 0)); +- sprintf(acking_user, "\nAcked by: %s", getenv("REMOTE_USER")); +- if (remaddr) sprintf(acking_user + strlen(acking_user), " (%s)", remaddr); ++ SBUF_MALLOC(acking_user, 1024 + strlen(getenv("REMOTE_USER")) + (remaddr ? strlen(remaddr) : 0)); ++ snprintf(acking_user, acking_user_buflen, "\nAcked by: %s", getenv("REMOTE_USER")); ++ if (remaddr) snprintf(acking_user + strlen(acking_user), acking_user_buflen - strlen(acking_user), " (%s)", remaddr); + } + + /* Load the host data (for access control) */ +@@ -388,8 +389,10 @@ + + addtobuffer(response, "<center>\n"); + for (awalk = ackhead; (awalk); awalk = awalk->next) { +- char *msgline = (char *)malloc(1024 + (awalk->hostname ? strlen(awalk->hostname) : 0) + (awalk->testname ? strlen(awalk->testname) : 0)); ++ SBUF_DEFINE(msgline); + ++ SBUF_MALLOC(msgline, 1024 + (awalk->hostname ? MAX_HTMLQUOTE_FACTOR*strlen(awalk->hostname) : 0) + (awalk->testname ? MAX_HTMLQUOTE_FACTOR*strlen(awalk->testname) : 0)); ++ + if (!awalk->checked) continue; + if (accessfn && (!web_access_allowed(getenv("REMOTE_USER"), awalk->hostname, awalk->testname, WEB_ACCESS_CONTROL))) continue; + +@@ -407,35 +410,35 @@ + count++; + if (!awalk->ackmsg || !awalk->validity || !awalk->acknum) { + if (awalk->hostname && awalk->testname) { +- sprintf(msgline, "<b>NO ACK</b> sent for host %s / test %s", ++ snprintf(msgline, msgline_buflen, "<b>NO ACK</b> sent for host %s / test %s", + htmlquoted(awalk->hostname), htmlquoted(awalk->testname)); + } + else { +- sprintf(msgline, "<b>NO ACK</b> sent for item %d", awalk->id); ++ snprintf(msgline, msgline_buflen, "<b>NO ACK</b> sent for item %d", awalk->id); + } + addtobuffer(response, msgline); + addtobuffer(response, ": Duration or message not set<br>\n"); + continue; + } + +- xymonmsg = (char *)malloc(1024 + strlen(awalk->ackmsg) + strlen(acking_user)); +- sprintf(xymonmsg, "xymondack %d %d %s %s", awalk->acknum, awalk->validity, awalk->ackmsg, acking_user); ++ SBUF_MALLOC(xymonmsg, 1024 + strlen(awalk->ackmsg) + strlen(acking_user)); ++ snprintf(xymonmsg, xymonmsg_buflen, "xymondack %d %d %s %s", awalk->acknum, awalk->validity, awalk->ackmsg, acking_user); + if (sendmessage(xymonmsg, NULL, XYMON_TIMEOUT, NULL) == XYMONSEND_OK) { + if (awalk->hostname && awalk->testname) { +- sprintf(msgline, "Acknowledge sent for host %s / test %s<br>\n", ++ snprintf(msgline, msgline_buflen, "Acknowledge sent for host %s / test %s<br>\n", + htmlquoted(awalk->hostname), htmlquoted(awalk->testname)); + } + else { +- sprintf(msgline, "Acknowledge sent for code %d<br>\n", awalk->acknum); ++ snprintf(msgline, msgline_buflen, "Acknowledge sent for code %d<br>\n", awalk->acknum); + } + } + else { + if (awalk->hostname && awalk->testname) { +- sprintf(msgline, "Failed to send acknowledge for host %s / test %s<br>\n", ++ snprintf(msgline, msgline_buflen, "Failed to send acknowledge for host %s / test %s<br>\n", + htmlquoted(awalk->hostname), htmlquoted(awalk->testname)); + } + else { +- sprintf(msgline, "Failed to send acknowledge for code %d<br>\n", awalk->acknum); ++ snprintf(msgline, msgline_buflen, "Failed to send acknowledge for code %d<br>\n", awalk->acknum); + } + } + +Index: xymon/web/appfeed.c +=================================================================== +--- xymon/web/appfeed.c (revision 8059) ++++ xymon/web/appfeed.c (working copy) +@@ -85,7 +85,7 @@ + + FILE *output = stdout; + +- char *xymondreq; ++ SBUF_DEFINE(xymondreq); + sendreturn_t *sres; + int xymondresult; + char *log, *bol, *eoln, *endkey; +@@ -117,15 +117,17 @@ + + /* Setup the query for xymond */ + parse_query(); +- xymondreq = (char *)malloc(strlen(boardcmd) + strlen(fieldlist) + strlen(colorlist) + strlen(queryfilter) + 5); +- sprintf(xymondreq, "%s %s %s %s", boardcmd, fieldlist, colorlist, queryfilter); ++ SBUF_MALLOC(xymondreq, strlen(boardcmd) + strlen(fieldlist) + strlen(colorlist) + strlen(queryfilter) + 5); ++ snprintf(xymondreq, xymondreq_buflen, "%s %s %s %s", boardcmd, fieldlist, colorlist, queryfilter); + + /* Get the current status */ + sres = newsendreturnbuf(1, NULL); + xymondresult = sendmessage(xymondreq, NULL, XYMON_TIMEOUT, sres); + if (xymondresult != XYMONSEND_OK) { +- char *errtxt = (char *)malloc(1024 + strlen(xymondreq)); +- sprintf(errtxt, "Status not available: Req=%s, result=%d\n", htmlquoted(xymondreq), xymondresult); ++ SBUF_DEFINE(errtxt); ++ ++ SBUF_MALLOC(errtxt, 1024 + MAX_HTMLQUOTE_FACTOR*strlen(xymondreq)); ++ snprintf(errtxt, errtxt_buflen, "Status not available: Req=%s, result=%d\n", htmlquoted(xymondreq), xymondresult); + errormsg(errtxt); + return 1; + } +Index: xymon/web/reportlog.c +=================================================================== +--- xymon/web/reportlog.c (revision 8059) ++++ xymon/web/reportlog.c (working copy) +@@ -25,7 +25,7 @@ + char *hostname = NULL; + char *displayname = NULL; + char *ip = NULL; +-char *reporttime = NULL; ++SBUF_DEFINE(reporttime); + char *service = NULL; + time_t st, end; + int style; +@@ -55,21 +55,27 @@ + */ + + if (strcasecmp(cwalk->name, "HOSTSVC") == 0) { +- char *p = strrchr(cwalk->value, '.'); ++ char *p = cwalk->value + strspn(cwalk->value, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.,"); ++ *p = '\0'; + ++ p = strrchr(cwalk->value, '.'); + if (p) { *p = '\0'; service = strdup(p+1); } + hostname = strdup(basename(cwalk->value)); + while ((p = strchr(hostname, ','))) *p = '.'; + } + else if (strcasecmp(cwalk->name, "HOST") == 0) { ++ char *p = cwalk->value + strspn(cwalk->value, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.,"); ++ *p = '\0'; + hostname = strdup(basename(cwalk->value)); + } + else if (strcasecmp(cwalk->name, "SERVICE") == 0) { ++ char *p = cwalk->value + strspn(cwalk->value, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.,"); ++ *p = '\0'; + service = strdup(basename(cwalk->value)); + } + else if (strcasecmp(cwalk->name, "REPORTTIME") == 0) { +- reporttime = (char *) malloc(strlen(cwalk->value)+strlen("REPORTTIME=")+1); +- sprintf(reporttime, "REPORTTIME=%s", cwalk->value); ++ SBUF_MALLOC(reporttime, strlen(cwalk->value)+strlen("REPORTTIME=")+1); ++ snprintf(reporttime, reporttime_buflen, "REPORTTIME=%s", cwalk->value); + } + else if (strcasecmp(cwalk->name, "WARNPCT") == 0) { + reportwarnlevel = atof(cwalk->value); +@@ -87,8 +93,10 @@ + end = atol(cwalk->value); + } + else if (strcasecmp(cwalk->name, "COLOR") == 0) { +- char *colstr = (char *) malloc(strlen(cwalk->value)+2); +- sprintf(colstr, "%s ", cwalk->value); ++ SBUF_DEFINE(colstr); ++ ++ SBUF_MALLOC(colstr, strlen(cwalk->value)+2); ++ snprintf(colstr, colstr_buflen, "%s ", cwalk->value); + color = parse_color(colstr); + xfree(colstr); + } +@@ -102,15 +110,19 @@ + + int main(int argc, char *argv[]) + { +- char histlogfn[PATH_MAX]; ++ SBUF_DEFINE(histlogfn); + FILE *fd; +- char *textrepfn = NULL, *textrepfullfn = NULL, *textrepurl = NULL; ++ SBUF_DEFINE(textrepfn); ++ SBUF_DEFINE(textrepfullfn); ++ SBUF_DEFINE(textrepurl); + FILE *textrep; + reportinfo_t repinfo; + int argi; + char *envarea = NULL; + void *hinfo; + ++ SBUF_MALLOC(histlogfn, PATH_MAX); ++ + for (argi=1; (argi < argc); argi++) { + if (argnmatch(argv[argi], "--env=")) { + char *p = strchr(argv[argi], '='); +@@ -135,7 +147,7 @@ + displayname = xmh_item(hinfo, XMH_DISPLAYNAME); + if (!displayname) displayname = hostname; + +- sprintf(histlogfn, "%s/%s.%s", xgetenv("XYMONHISTDIR"), commafy(hostname), service); ++ snprintf(histlogfn, histlogfn_buflen, "%s/%s.%s", xgetenv("XYMONHISTDIR"), commafy(hostname), service); + fd = fopen(histlogfn, "r"); + if (fd == NULL) { + errormsg("Cannot open history file"); +@@ -144,12 +156,12 @@ + color = parse_historyfile(fd, &repinfo, hostname, service, st, end, 0, reportwarnlevel, reportgreenlevel, reportwarnstops, reporttime); + fclose(fd); + +- textrepfn = (char *)malloc(1024 + strlen(hostname) + strlen(service)); +- sprintf(textrepfn, "avail-%s-%s-%u-%lu.txt", hostname, service, (unsigned int)getcurrenttime(NULL), (unsigned long)getpid()); +- textrepfullfn = (char *)malloc(1024 + strlen(xgetenv("XYMONREPDIR")) + strlen(textrepfn)); +- sprintf(textrepfullfn, "%s/%s", xgetenv("XYMONREPDIR"), textrepfn); +- textrepurl = (char *)malloc(1024 + strlen(xgetenv("XYMONREPURL")) + strlen(textrepfn)); +- sprintf(textrepurl, "%s/%s", xgetenv("XYMONREPURL"), textrepfn); ++ SBUF_MALLOC(textrepfn, 1024 + strlen(hostname) + strlen(service)); ++ snprintf(textrepfn, textrepfn_buflen, "avail-%s-%s-%u-%lu.txt", hostname, service, (unsigned int)getcurrenttime(NULL), (unsigned long)getpid()); ++ SBUF_MALLOC(textrepfullfn, 1024 + strlen(xgetenv("XYMONREPDIR")) + strlen(textrepfn)); ++ snprintf(textrepfullfn, textrepfullfn_buflen, "%s/%s", xgetenv("XYMONREPDIR"), textrepfn); ++ SBUF_MALLOC(textrepurl, 1024 + strlen(xgetenv("XYMONREPURL")) + strlen(textrepfn)); ++ snprintf(textrepurl, textrepurl_buflen, "%s/%s", xgetenv("XYMONREPURL"), textrepfn); + textrep = fopen(textrepfullfn, "w"); + + /* Now generate the webpage */ diff -Nru xymon-4.3.28/debian/patches/series xymon-4.3.28/debian/patches/series --- xymon-4.3.28/debian/patches/series 2017-01-18 17:27:33.000000000 +0100 +++ xymon-4.3.28/debian/patches/series 2019-08-23 01:09:07.000000000 +0200 @@ -17,3 +17,4 @@ 66_apache2.4.patch 69_disk-no-duplicate-root.patch 84_fix_compilation_on_GNU_Hurd.patch +91_4.3.29-CVEs.patch -- System Information: Debian Release: bullseye/sid APT prefers unstable APT policy: (990, 'unstable'), (980, 'unstable-debug'), (600, 'testing'), (111, 'buildd-unstable'), (111, 'buildd-experimental'), (110, 'experimental'), (105, 'experimental-debug') Architecture: amd64 (x86_64) Kernel: Linux 4.19.0-5-amd64 (SMP w/2 CPU cores) Locale: LANG=C.UTF-8, LC_CTYPE=C.UTF-8 (charmap=UTF-8), LANGUAGE=C.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Init: systemd (via /run/systemd/system) LSM: AppArmor: enabled