PATCH: zformat: fix some misparse and overrun issues

Mikael Magnusson <[email protected]>
Newsgroups gmane.comp.shells.zsh.devel
Message-ID <[email protected]>
Not closing a %( would simply read garbage memory
  % zformat -f result 'before%(a-after' 'a:hello'  ; echo $result
  beforeaftera:hello
  % zformat -f result 'before%(a-after' 'a:hello'  ; echo $result
  beforeafter#

It was possible to overwrite the %% and %) sequences with arbitrary
text, and %% was also undocumented. Hopefully nobody relied on this
spacekey heater.
---
 Doc/Zsh/mod_zutil.yo |  2 +-
 Src/Modules/zutil.c  | 12 ++++++++----
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/Doc/Zsh/mod_zutil.yo b/Doc/Zsh/mod_zutil.yo
index 62f87fc286..c33e3c7216 100644
--- a/Doc/Zsh/mod_zutil.yo
+++ b/Doc/Zsh/mod_zutil.yo
@@ -178,7 +178,7 @@ can be achieved by giving a negative minimum field width.  If a maximum
 field width is specified, the var(string) will be truncated after that
 many characters.  After all `tt(%)' sequences for the given var(spec)s
 have been processed, the resulting string is stored in the parameter
-var(param).
+var(param).  The sequence `tt(%%)' can be used to produce a literal tt(%).
 
 The tt(%)-escapes also understand ternary expressions in the form used by
 prompts.  The tt(%) is followed by a `tt(LPAR())' and then an ordinary
diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c
index 28c6e8accd..e50f68ece6 100644
--- a/Src/Modules/zutil.c
+++ b/Src/Modules/zutil.c
@@ -880,10 +880,10 @@ static char *zformat_substring(char* instr, char **specs, char **outp,
 		 * vice versa... unless we are already skipping.
 		 */
 		if (!(s = zformat_substring(s+1, specs, outp, ousedp,
-			    olenp, endcharl, presence, skip || actval)))
+			    olenp, endcharl, presence, skip || actval)) || !*s)
 		    return NULL;
 		if (!(s = zformat_substring(s+1, specs, outp, ousedp,
-			    olenp, ')', presence, skip || !actval)))
+			    olenp, ')', presence, skip || !actval)) || !*s)
 		    return NULL;
 	    } else if (skip) {
 		continue;
@@ -978,6 +978,7 @@ bin_zformat(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
 	    /* Parse the specs in argv. */
 	    for (ap = args + 2; *ap; ap++) {
 		if (!ap[0][0] || ap[0][0] == '-' || ap[0][0] == '.' ||
+		    ap[0][0] == '%' || ap[0][0] == ')' ||
 		    idigit(ap[0][0]) || ap[0][1] != ':') {
 		    zwarnnam(nam, "invalid argument: %s", *ap);
 		    return 1;
@@ -986,8 +987,11 @@ bin_zformat(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
 	    }
 	    out = (char *) zhalloc(olen = 128);
 
-	    zformat_substring(args[1], specs, &out, &oused, &olen, '\0',
-		    presence, 0);
+	    if (!zformat_substring(args[1], specs, &out, &oused, &olen, '\0',
+			presence, 0)) {
+		zwarnnam(nam, "malformed format string");
+		return 1;
+	    }
 	    out[oused] = '\0';
 
 	    setsparam(args[0], ztrdup(out));
-- 
2.38.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.