From d10e20da0dbd6d6438d55a5e9c6e22cee70aec20 Mon Sep 17 00:00:00 2001
From: Mark Andrews <marka@isc.org>
Date: Fri, 1 Jul 2022 11:13:51 +1000
Subject: [PATCH] Tighten $GENERATE directive parsing

The original sscanf processing allowed for a number of syntax errors
to be accepted.  This included missing the closing brace in
${modifiers}

Look for both comma and right brace as intermediate seperators as
well as consuming the final right brace in the sscanf processing
for ${modifiers}.  Check when we got right brace to determine if
the sscanf consumed more input than expected and if so behave as
if it had stopped at the first right brace.

(cherry picked from commit 7be64c0e94c967c0014a0b960a495c4fb05f1fc2)
Conflict: NA
Reference: https://gitlab.isc.org/isc-projects/bind9/-/commit/d10e20da0dbd6d6438d55a5e9c6e22cee70aec20
---
 .../checkzone/zones/bad-generate-garbage.db   | 17 ++++++++++
 .../zones/bad-generate-missing-brace.db       | 17 ++++++++++
 .../checkzone/zones/good-generate-modifier.db | 20 +++++++++++
 lib/dns/master.c                              | 33 ++++++++++++-------
 4 files changed, 76 insertions(+), 11 deletions(-)
 create mode 100644 bin/tests/system/checkzone/zones/bad-generate-garbage.db
 create mode 100644 bin/tests/system/checkzone/zones/bad-generate-missing-brace.db
 create mode 100644 bin/tests/system/checkzone/zones/good-generate-modifier.db

diff --git a/bin/tests/system/checkzone/zones/bad-generate-garbage.db b/bin/tests/system/checkzone/zones/bad-generate-garbage.db
new file mode 100644
index 0000000000..0d66e753b6
--- /dev/null
+++ b/bin/tests/system/checkzone/zones/bad-generate-garbage.db
@@ -0,0 +1,17 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0.  If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 600
+@		SOA	ns hostmaster 2011012708 3600 1200 604800 1200
+		NS	ns
+ns		A	192.0.2.1
+
+$GENERATE 0-7   host$	A 1.2.3.${1,0,dgarbagegarbage}
diff --git a/bin/tests/system/checkzone/zones/bad-generate-missing-brace.db b/bin/tests/system/checkzone/zones/bad-generate-missing-brace.db
new file mode 100644
index 0000000000..314583e71a
--- /dev/null
+++ b/bin/tests/system/checkzone/zones/bad-generate-missing-brace.db
@@ -0,0 +1,17 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0.  If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 600
+@		SOA	ns hostmaster 2011012708 3600 1200 604800 1200
+		NS	ns
+ns		A	192.0.2.1
+
+$GENERATE 0-7   host$	A 1.2.3.${1000
diff --git a/bin/tests/system/checkzone/zones/good-generate-modifier.db b/bin/tests/system/checkzone/zones/good-generate-modifier.db
new file mode 100644
index 0000000000..3c811d60e0
--- /dev/null
+++ b/bin/tests/system/checkzone/zones/good-generate-modifier.db
@@ -0,0 +1,20 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0.  If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 600
+@		SOA	ns hostmaster 2011012708 3600 1200 604800 1200
+		NS	ns
+ns		A	192.0.2.1
+
+$GENERATE 0-7   host$	A 1.2.3.${1,0,d}
+$GENERATE 8-9   host$	A 1.2.3.${1,0}
+$GENERATE 10-11 host$	A 1.2.3.${1}
+$GENERATE 1024-1026 ${0,3,n}	AAAA 2001:db8::${0,4,x}
diff --git a/lib/dns/master.c b/lib/dns/master.c
index e938b15a0e..1ad658b7f4 100644
--- a/lib/dns/master.c
+++ b/lib/dns/master.c
@@ -683,7 +683,10 @@ genname(char *name, int it, char *buffer, size_t length) {
 	char fmt[sizeof("%04000000000d")];
 	char numbuf[128];
 	char *cp;
-	char mode[2];
+	char mode[2] = { 0 };
+	char brace[2] = { 0 };
+	char comma1[2] = { 0 };
+	char comma2[2] = { 0 };
 	int delta = 0;
 	isc_textregion_t r;
 	unsigned int n;
@@ -708,23 +711,31 @@ genname(char *name, int it, char *buffer, size_t length) {
 			strlcpy(fmt, "%d", sizeof(fmt));
 			/* Get format specifier. */
 			if (*name == '{') {
-				n = sscanf(name, "{%d,%u,%1[doxXnN]}", &delta,
-					   &width, mode);
-				switch (n) {
-				case 1:
-					break;
-				case 2:
+				n = sscanf(name,
+					   "{%d%1[,}]%u%1[,}]%1[doxXnN]%1[}]",
+					   &delta, comma1, &width, comma2, mode,
+					   brace);
+				if (n < 2 || n > 6) {
+					return (DNS_R_SYNTAX);
+				}
+				if (comma1[0] == '}') {
+					/* %{delta} */
+				} else if (comma1[0] == ',' && comma2[0] == '}')
+				{
+					/* %{delta,width} */
 					n = snprintf(fmt, sizeof(fmt), "%%0%ud",
 						     width);
-					break;
-				case 3:
+				} else if (comma1[0] == ',' &&
+					   comma2[0] == ',' && mode[0] != 0 &&
+					   brace[0] == '}')
+				{
+					/* %{delta,width,format} */
 					if (mode[0] == 'n' || mode[0] == 'N') {
 						nibblemode = true;
 					}
 					n = snprintf(fmt, sizeof(fmt),
 						     "%%0%u%c", width, mode[0]);
-					break;
-				default:
+				} else {
 					return (DNS_R_SYNTAX);
 				}
 				if (n >= sizeof(fmt)) {
-- 
2.23.0

