All of lore.kernel.org
 help / color / mirror / Atom feed
From: Simon Glass <sjg@chromium.org>
To: u-boot@lists.denx.de
Subject: [PATCH 05/10] setexpr: Split the core logic into its own function
Date: Sun,  1 Nov 2020 14:15:39 -0700	[thread overview]
Message-ID: <20201101211544.3579850-6-sjg@chromium.org> (raw)
In-Reply-To: <20201101211544.3579850-1-sjg@chromium.org>

At present this function always allocates a large amount of stack, and
selects its own size for buffers. This makes it hard to test the code
for buffer overflow.

Separate out the inner logic of the substitution so that tests can call
this directly. This will allow checking that the algorithm does not
overflow the buffer.

Fix up one of the error lines at the same time, since it should be
printing nbuf_size, not data_size.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 cmd/setexpr.c | 156 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 98 insertions(+), 58 deletions(-)

diff --git a/cmd/setexpr.c b/cmd/setexpr.c
index dd9c2574fdc..fe3435b4d99 100644
--- a/cmd/setexpr.c
+++ b/cmd/setexpr.c
@@ -58,9 +58,6 @@ static ulong get_arg(char *s, int w)
 
 #include <slre.h>
 
-#define SLRE_BUFSZ	16384
-#define SLRE_PATSZ	4096
-
 /*
  * memstr - Find the first substring in memory
  * @s1: The string to be searched
@@ -83,13 +80,24 @@ static char *memstr(const char *s1, int l1, const char *s2, int l2)
 	return NULL;
 }
 
-static char *substitute(char *string,	/* string buffer */
-			int *slen,	/* current string length */
-			int ssize,	/* string bufer size */
-			const char *old,/* old (replaced) string */
-			int olen,	/* length of old string */
-			const char *new,/* new (replacement) string */
-			int nlen)	/* length of new string */
+/**
+ * substitute() - Substitute part of one string with another
+ *
+ * This updates @string so that the first occurrence of @old is replaced with
+ * @new
+ *
+ * @string: String buffer containing string to update at the start
+ * @slen: Pointer to current string length, updated on success
+ * @ssize: Size of string buffer
+ * @old: Old string to find in the buffer (no terminator needed)
+ * @olen: Length of @old excluding terminator
+ * @new: New string to replace @old with
+ * @nlen: Length of @new excluding terminator
+ * @return pointer to immediately after the copied @new in @string, or NULL if
+ *	no replacement took place
+ */
+static char *substitute(char *string, int *slen, int ssize,
+			const char *old, int olen, const char *new, int nlen)
 {
 	char *p = memstr(string, *slen, old, olen);
 
@@ -118,7 +126,7 @@ static char *substitute(char *string,	/* string buffer */
 		memmove(p + nlen, p + olen, tail);
 	}
 
-	/* insert substitue */
+	/* insert substitute */
 	memcpy(p, new, nlen);
 
 	*slen += nlen - olen;
@@ -126,52 +134,33 @@ static char *substitute(char *string,	/* string buffer */
 	return p + nlen;
 }
 
-/*
- * Perform regex operations on a environment variable
+/**
+ * regex_sub() - Replace a regex pattern with a string
  *
- * Returns 0 if OK, 1 in case of errors.
+ * @data: Buffer containing the string to update
+ * @data_size: Size of buffer (must be large enough for the new string)
+ * @nbuf: Back-reference buffer
+ * @nbuf_size: Size of back-reference buffer (must be larger enough for @s plus
+ *	all back-reference expansions)
+ * @r: Regular expression to find
+ * @s: String to replace with
+ * @global: true to replace all matches in @data, false to replace just the
+ *	first
+ * @return 0 if OK, 1 on error
  */
-static int regex_sub(const char *name,
-	const char *r, const char *s, const char *t,
-	int global)
+static int regex_sub(char *data, uint data_size, char *nbuf, uint nbuf_size,
+		     const char *r, const char *s, bool global)
 {
 	struct slre slre;
-	char data[SLRE_BUFSZ];
 	char *datap = data;
-	const char *value;
 	int res, len, nlen, loop;
 
-	if (name == NULL)
-		return 1;
-
 	if (slre_compile(&slre, r) == 0) {
 		printf("Error compiling regex: %s\n", slre.err_str);
 		return 1;
 	}
 
-	if (t == NULL) {
-		value = env_get(name);
-
-		if (value == NULL) {
-			printf("## Error: variable \"%s\" not defined\n", name);
-			return 1;
-		}
-		t = value;
-	}
-
-	debug("REGEX on %s=%s\n", name, t);
-	debug("REGEX=\"%s\", SUBST=\"%s\", GLOBAL=%d\n",
-		r, s ? s : "<NULL>", global);
-
-	len = strlen(t);
-	if (len + 1 > SLRE_BUFSZ) {
-		printf("## error: subst buffer overflow: have %d, need %d\n",
-			SLRE_BUFSZ, len + 1);
-		return 1;
-	}
-
-	strcpy(data, t);
-
+	len = strlen(data);
 	if (s == NULL)
 		nlen = 0;
 	else
@@ -179,7 +168,6 @@ static int regex_sub(const char *name,
 
 	for (loop = 0;; loop++) {
 		struct cap caps[slre.num_caps + 2];
-		char nbuf[SLRE_PATSZ];
 		const char *old;
 		char *np;
 		int i, olen;
@@ -199,7 +187,7 @@ static int regex_sub(const char *name,
 
 		if (res == 0) {
 			if (loop == 0) {
-				printf("%s: No match\n", t);
+				printf("%s: No match\n", data);
 				return 1;
 			} else {
 				break;
@@ -208,17 +196,15 @@ static int regex_sub(const char *name,
 
 		debug("## MATCH ## %s\n", data);
 
-		if (s == NULL) {
-			printf("%s=%s\n", name, t);
+		if (!s)
 			return 1;
-		}
 
 		old = caps[0].ptr;
 		olen = caps[0].len;
 
-		if (nlen + 1 >= SLRE_PATSZ) {
+		if (nlen + 1 >= nbuf_size) {
 			printf("## error: pattern buffer overflow: have %d, need %d\n",
-				SLRE_BUFSZ, nlen + 1);
+			       nbuf_size, nlen + 1);
 			return 1;
 		}
 		strcpy(nbuf, s);
@@ -263,7 +249,7 @@ static int regex_sub(const char *name,
 					break;
 
 				np = substitute(np, &nlen,
-					SLRE_PATSZ,
+					nbuf_size,
 					backref, 2,
 					caps[i].ptr, caps[i].len);
 
@@ -273,9 +259,8 @@ static int regex_sub(const char *name,
 		}
 		debug("## SUBST(2) ## %s\n", nbuf);
 
-		datap = substitute(datap, &len, SLRE_BUFSZ,
-				old, olen,
-				nbuf, nlen);
+		datap = substitute(datap, &len, data_size, old, olen,
+				   nbuf, nlen);
 
 		if (datap == NULL)
 			return 1;
@@ -289,6 +274,61 @@ static int regex_sub(const char *name,
 	}
 	debug("## FINAL (now env_set()) :  %s\n", data);
 
+	return 0;
+}
+
+#define SLRE_BUFSZ	16384
+#define SLRE_PATSZ	4096
+
+/*
+ * Perform regex operations on a environment variable
+ *
+ * Returns 0 if OK, 1 in case of errors.
+ */
+static int regex_sub_var(const char *name, const char *r, const char *s,
+			 const char *t, int global)
+{
+	struct slre slre;
+	char data[SLRE_BUFSZ];
+	char nbuf[SLRE_PATSZ];
+	const char *value;
+	int len;
+	int ret;
+
+	if (!name)
+		return 1;
+
+	if (slre_compile(&slre, r) == 0) {
+		printf("Error compiling regex: %s\n", slre.err_str);
+		return 1;
+	}
+
+	if (!t) {
+		value = env_get(name);
+		if (!value) {
+			printf("## Error: variable \"%s\" not defined\n", name);
+			return 1;
+		}
+		t = value;
+	}
+
+	debug("REGEX on %s=%s\n", name, t);
+	debug("REGEX=\"%s\", SUBST=\"%s\", GLOBAL=%d\n", r, s ? s : "<NULL>",
+	      global);
+
+	len = strlen(t);
+	if (len + 1 > SLRE_BUFSZ) {
+		printf("## error: subst buffer overflow: have %d, need %d\n",
+		       SLRE_BUFSZ, len + 1);
+		return 1;
+	}
+
+	strcpy(data, t);
+
+	ret = regex_sub(data, SLRE_BUFSZ, nbuf, SLRE_PATSZ, r, s, global);
+	if (ret)
+		return 1;
+
 	printf("%s=%s\n", name, data);
 
 	return env_set(name, data);
@@ -331,10 +371,10 @@ static int do_setexpr(struct cmd_tbl *cmdtp, int flag, int argc,
 	 * with 5 args, "t" will be NULL
 	 */
 	if (strcmp(argv[2], "gsub") == 0)
-		return regex_sub(argv[1], argv[3], argv[4], argv[5], 1);
+		return regex_sub_var(argv[1], argv[3], argv[4], argv[5], 1);
 
 	if (strcmp(argv[2], "sub") == 0)
-		return regex_sub(argv[1], argv[3], argv[4], argv[5], 0);
+		return regex_sub_var(argv[1], argv[3], argv[4], argv[5], 0);
 #endif
 
 	/* standard operators: "setexpr name val1 op val2" */
-- 
2.29.1.341.ge80a0c044ae-goog

  parent reply	other threads:[~2020-11-01 21:15 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-01 21:15 [PATCH 00/10] setexpr: Correct various bugs and add tests plus string support Simon Glass
2020-11-01 21:15 ` [PATCH 01/10] test: Add some tests for setexpr Simon Glass
2020-12-02 21:22   ` Tom Rini
2020-11-01 21:15 ` [PATCH 02/10] command: Add constants for cmd_get_data_size string / error Simon Glass
2020-12-02 21:22   ` Tom Rini
2020-11-01 21:15 ` [PATCH 03/10] setexpr: Add explicit support for 32- and 64-bit ints Simon Glass
2020-12-02 21:22   ` Tom Rini
2020-11-01 21:15 ` [PATCH 04/10] test: Add some setexpr regex tests Simon Glass
2020-12-02 21:22   ` Tom Rini
2020-11-01 21:15 ` Simon Glass [this message]
2020-12-02 21:22   ` [PATCH 05/10] setexpr: Split the core logic into its own function Tom Rini
2020-11-01 21:15 ` [PATCH 06/10] setexpr: Add some tests for buffer overflow and backref Simon Glass
2020-12-02 21:23   ` Tom Rini
2021-01-17 22:52   ` CRASH caused by: " Heinrich Schuchardt
2021-01-19 18:06     ` Simon Glass
2021-01-19 19:07       ` Heinrich Schuchardt
2021-01-19 19:45       ` Tom Rini
2021-01-20  0:17         ` Simon Glass
2020-11-01 21:15 ` [PATCH 07/10] setexpr: Correct dropping of final unmatched string Simon Glass
2020-12-02 21:23   ` Tom Rini
2020-11-01 21:15 ` [PATCH 08/10] setexpr: Correct buffer overflow bug and enable tests Simon Glass
2020-12-02 21:23   ` Tom Rini
2020-11-01 21:15 ` [PATCH 09/10] setexpr: Convert to use a struct for values Simon Glass
2020-12-02 21:23   ` Tom Rini
2020-11-01 21:15 ` [PATCH 10/10] setexpr: Add support for strings Simon Glass
2020-11-01 23:08   ` Marek Behun
2020-11-03 15:12     ` Simon Glass
2020-11-03 16:30       ` Marek Behun
2020-11-05 16:49         ` Wolfgang Denk
2020-11-05 17:27         ` Simon Glass
2020-11-06 20:58           ` Tom Rini
2020-11-06 21:48             ` Simon Glass
2020-11-05 16:47       ` Wolfgang Denk
2020-11-05 17:27         ` Simon Glass
2020-11-05 17:50           ` Marek Behun
2020-11-05 19:10           ` Wolfgang Denk
2020-11-05 20:15             ` Simon Glass
2020-12-02 21:23   ` Tom Rini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201101211544.3579850-6-sjg@chromium.org \
    --to=sjg@chromium.org \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.