[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#935473: stretch-pu: package xymon/4.3.28-2+deb9u1



Package: release.debian.org
Severity: normal
Tags: stretch
User: release.debian.org@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 <abe@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 <cleaver@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? ' ' --> '&nbsp;' */
++#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&amp;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&amp;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), "&amp;TIMEBUF=%s", clientid);
++					int curlen = strlen(clienturi);
++
++					SBUF_REALLOC(clienturi, 1024 + curlen + strlen(clientid));
++					snprintf(clienturi + curlen, (clienturi_buflen - curlen), "&amp;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, "&amp;BARSUMS=%d", barsums);
++	snprintf(p, selfurl_buflen - (p - selfurl), "&amp;BARSUMS=%d", barsums);
+ 
+ 	if (strlen(ip)) {
++		SBUF_REALLOC(selfurl, selfurl_buflen + 6*strlen(ip));
+ 		p = selfurl + strlen(selfurl);
+-		sprintf(p, "&amp;IP=%s", htmlquoted(ip));
++		snprintf(p, selfurl_buflen - (p - selfurl), "&amp;IP=%s", htmlquoted(ip));
+ 	}
+ 
+ 	if (entrycount) {
+ 		p = selfurl + strlen(selfurl);
+-		sprintf(p, "&amp;ENTRIES=%d", entrycount);
++		snprintf(p, selfurl_buflen - (p - selfurl), "&amp;ENTRIES=%d", entrycount);
+ 	}
+-	else strcat(selfurl, "&amp;ENTRIES=ALL");
++	else strncat(selfurl, "&amp;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


Reply to: