autofs-5.1.7 - add some buffer length checks to master map parser

From: Ian Kent <raven@themaw.net>

Add some checks for buffer overflow to the master map parser.

Signed-off-by: Ian Kent <raven@themaw.net>
---
 CHANGELOG             |    1 +
 daemon/master_parse.y |   38 +++++++++++++++-----------
 daemon/master_tok.l   |   73 ++++++++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 88 insertions(+), 24 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index be0b9d85..ded0f00f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -85,6 +85,7 @@
 - fix incorrect print format specifiers in get_pkt().
 - add mapent path length check in handle_packet_expire_direct().
 - add copy length check in umount_autofs_indirect().
+- add some buffer length checks to master map parser.
 
 25/01/2021 autofs-5.1.7
 - make bind mounts propagation slave by default.
diff --git a/daemon/master_parse.y b/daemon/master_parse.y
index 7480c36a..2d78f082 100644
--- a/daemon/master_parse.y
+++ b/daemon/master_parse.y
@@ -29,6 +29,7 @@
 #include "master.h"
 
 #define MAX_ERR_LEN	512
+#define STRTYPE_LEN	2048
 
 extern struct master *master_list;
 
@@ -79,6 +80,7 @@ static int local_argc;
 static unsigned int propagation;
 
 static char errstr[MAX_ERR_LEN];
+static int errlen;
 
 static unsigned int verbose;
 static unsigned int debug;
@@ -521,10 +523,11 @@ dnattrs: DNATTR EQUAL DNNAME
 		    strcasecmp($1, "ou") &&
 		    strcasecmp($1, "automountMapName") &&
 		    strcasecmp($1, "nisMapName")) {
-			strcpy(errstr, $1);
-			strcat(errstr, "=");
-			strcat(errstr, $3);
-			master_notify(errstr);
+			errlen = snprintf(errstr, MAX_ERR_LEN, "%s=%s", $1, $3);
+			if (errlen < MAX_ERR_LEN)
+				master_notify(errstr);
+			else
+				master_notify("error string too long");
 			YYABORT;
 		}
 		strcpy($$, $1);
@@ -537,10 +540,11 @@ dnattrs: DNATTR EQUAL DNNAME
 		    strcasecmp($1, "ou") &&
 		    strcasecmp($1, "automountMapName") &&
 		    strcasecmp($1, "nisMapName")) {
-			strcpy(errstr, $1);
-			strcat(errstr, "=");
-			strcat(errstr, $3);
-			master_notify(errstr);
+			errlen = snprintf(errstr, MAX_ERR_LEN, "%s=%s", $1, $3);
+			if (errlen < MAX_ERR_LEN)
+				master_notify(errstr);
+			else
+				master_notify("error string too long");
 			YYABORT;
 		}
 		strcpy($$, $1);
@@ -565,10 +569,11 @@ dnattr: DNATTR EQUAL DNNAME
 	{
 		if (!strcasecmp($1, "automountMapName") ||
 		    !strcasecmp($1, "nisMapName")) {
-			strcpy(errstr, $1);
-			strcat(errstr, "=");
-			strcat(errstr, $3);
-			master_notify(errstr);
+			errlen = snprintf(errstr, MAX_ERR_LEN, "%s=%s", $1, $3);
+			if (errlen < MAX_ERR_LEN)
+				master_notify(errstr);
+			else
+				master_notify("error string too long");
 			YYABORT;
 		}
 		strcpy($$, $1);
@@ -579,10 +584,11 @@ dnattr: DNATTR EQUAL DNNAME
 	{
 		if (!strcasecmp($1, "automountMapName") ||
 		    !strcasecmp($1, "nisMapName")) {
-			strcpy(errstr, $1);
-			strcat(errstr, "=");
-			strcat(errstr, $3);
-			master_notify(errstr);
+			errlen = snprintf(errstr, MAX_ERR_LEN, "%s=%s", $1, $3);
+			if (errlen < MAX_ERR_LEN)
+				master_notify(errstr);
+			else
+				master_notify("error string too long");
 			YYABORT;
 		}
 		strcpy($$, $1);
diff --git a/daemon/master_tok.l b/daemon/master_tok.l
index 87a6b958..e2d15bce 100644
--- a/daemon/master_tok.l
+++ b/daemon/master_tok.l
@@ -23,6 +23,7 @@
 #endif /* ECHO */
 static void master_echo(void);	/* forward definition */
 #define ECHO master_echo()
+static void master_error(char *s);
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -80,6 +81,8 @@ char *bptr;
 char *optr = buff;
 unsigned int tlen;
 
+#define STRTYPE_LEN	2048
+
 %}
 
 %option nounput
@@ -217,7 +220,13 @@ MODE		(--mode{OPTWS}|--mode{OPTWS}={OPTWS})
 			bptr += tlen;
 			yyless(tlen);
 		} else {
-			strcpy(master_lval.strtype, master_text);
+			if (tlen <= STRTYPE_LEN)
+				strcpy(master_lval.strtype, master_text);
+			else {
+				master_error("MULTITYPE: value too large, truncated");
+				strncpy(master_lval.strtype, master_text, STRTYPE_LEN - 2);
+				master_lval.strtype[STRTYPE_LEN - 1] = 0;
+			}
 			return(MULTITYPE);
 		}
 	}
@@ -239,7 +248,13 @@ MODE		(--mode{OPTWS}|--mode{OPTWS}={OPTWS})
 			bptr += tlen;
 			yyless(tlen);
 		} else {
-			strcpy(master_lval.strtype, master_text);
+			if (tlen <= STRTYPE_LEN)
+				strcpy(master_lval.strtype, master_text);
+			else {
+				master_error("MAPTYPE: value too large, truncated");
+				strncpy(master_lval.strtype, master_text, STRTYPE_LEN - 2);
+				master_lval.strtype[STRTYPE_LEN - 1] = 0;
+			}
 			return(MAPTYPE);
 		}
 	}
@@ -327,12 +342,24 @@ MODE		(--mode{OPTWS}|--mode{OPTWS}={OPTWS})
 	{OPTWS}\\\n{OPTWS} {}
 
 	{DNSERVERSTR} {
-		strcpy(master_lval.strtype, master_text);
+		if (master_leng < STRTYPE_LEN)
+			strcpy(master_lval.strtype, master_text);
+		else {
+			master_error("DNSERVER: value too large, truncated");
+			strncpy(master_lval.strtype, master_text, STRTYPE_LEN - 2);
+			master_lval.strtype[STRTYPE_LEN - 1] = 0;
+		}
 		return DNSERVER;
 	}
 
 	{DNATTRSTR}/"=" {
-		strcpy(master_lval.strtype, master_text);
+		if (master_leng < STRTYPE_LEN)
+			strcpy(master_lval.strtype, master_text);
+		else {
+			master_error("DNATTR: value too large, truncated");
+			strncpy(master_lval.strtype, master_text, STRTYPE_LEN - 2);
+			master_lval.strtype[STRTYPE_LEN - 1] = 0;
+		}
 		return DNATTR;
 	}
 
@@ -341,12 +368,24 @@ MODE		(--mode{OPTWS}|--mode{OPTWS}={OPTWS})
 	}
 
 	{DNNAMESTR1}/","{DNATTRSTR}"=" {
-		strcpy(master_lval.strtype, master_text);
+		if (master_leng < STRTYPE_LEN)
+			strcpy(master_lval.strtype, master_text);
+		else {
+			master_error("DNNAME: value too large, truncated");
+			strncpy(master_lval.strtype, master_text, STRTYPE_LEN - 2);
+			master_lval.strtype[STRTYPE_LEN - 1] = 0;
+		}
 		return DNNAME;
 	}
 
 	{DNNAMESTR2} {
-		strcpy(master_lval.strtype, master_text);
+		if (master_leng < STRTYPE_LEN)
+			strcpy(master_lval.strtype, master_text);
+		else {
+			master_error("DNNAME: value too large, truncated");
+			strncpy(master_lval.strtype, master_text, STRTYPE_LEN - 2);
+			master_lval.strtype[STRTYPE_LEN - 1] = 0;
+		}
 		return DNNAME;
 	}
 
@@ -357,7 +396,13 @@ MODE		(--mode{OPTWS}|--mode{OPTWS}={OPTWS})
 	{WS}"=" |
 	"="{WS} {
 		BEGIN(INITIAL);
-		strcpy(master_lval.strtype, master_text);
+		if (master_leng < STRTYPE_LEN)
+			strcpy(master_lval.strtype, master_text);
+		else {
+			master_error("SPACE: value too large, truncated");
+			strncpy(master_lval.strtype, master_text, STRTYPE_LEN - 2);
+			master_lval.strtype[STRTYPE_LEN - 1] = 0;
+		}
 		return SPACE;
 	}
 
@@ -419,7 +464,13 @@ MODE		(--mode{OPTWS}|--mode{OPTWS}={OPTWS})
 	}
 
 	{OPTIONSTR} {
-		strcpy(master_lval.strtype, master_text);
+		if (master_leng < STRTYPE_LEN)
+			strcpy(master_lval.strtype, master_text);
+		else {
+			master_error("OPTION: value too large, truncated");
+			strncpy(master_lval.strtype, master_text, STRTYPE_LEN - 2);
+			master_lval.strtype[STRTYPE_LEN - 1] = 0;
+		}
 		return(OPTION);
 	}
 
@@ -459,6 +510,12 @@ static void master_echo(void)
 	return;
 }
 
+static void master_error(char *s)
+{
+	logmsg("%s");
+	return;
+}
+
 #ifdef FLEX_SCANNER
 
 void master_set_scan_buffer(const char *buffer)