Module Name:    src
Committed By:   rillig
Date:           Sat Oct 30 16:18:51 UTC 2021

Modified Files:
        src/usr.bin/indent: indent.c

Log Message:
indent: prevent buffer overflows in 'if (expr) ... stmt'


To generate a diff of this commit:
cvs rdiff -u -r1.188 -r1.189 src/usr.bin/indent/indent.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/indent/indent.c
diff -u src/usr.bin/indent/indent.c:1.188 src/usr.bin/indent/indent.c:1.189
--- src/usr.bin/indent/indent.c:1.188	Sat Oct 30 15:26:58 2021
+++ src/usr.bin/indent/indent.c	Sat Oct 30 16:18:51 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: indent.c,v 1.188 2021/10/30 15:26:58 rillig Exp $	*/
+/*	$NetBSD: indent.c,v 1.189 2021/10/30 16:18:51 rillig Exp $	*/
 
 /*-
  * SPDX-License-Identifier: BSD-4-Clause
@@ -43,7 +43,7 @@ static char sccsid[] = "@(#)indent.c	5.1
 
 #include <sys/cdefs.h>
 #if defined(__NetBSD__)
-__RCSID("$NetBSD: indent.c,v 1.188 2021/10/30 15:26:58 rillig Exp $");
+__RCSID("$NetBSD: indent.c,v 1.189 2021/10/30 16:18:51 rillig Exp $");
 #elif defined(__FreeBSD__)
 __FBSDID("$FreeBSD: head/usr.bin/indent/indent.c 340138 2018-11-04 19:24:49Z oshogbo $");
 #endif
@@ -158,6 +158,34 @@ diag(int level, const char *msg, ...)
 }
 
 static void
+sc_check_size(size_t n)
+{
+    if ((size_t)(sc_end - sc_buf) + n <= sc_size)
+	return;
+
+    diag(1, "Internal buffer overflow - "
+	"Move big comment from right after if, while, or whatever");
+    fflush(output);
+    exit(1);
+}
+
+static void
+sc_add_char(char ch)
+{
+    sc_check_size(1);
+    *sc_end++ = ch;
+}
+
+static void
+sc_add_range(const char *s, const char *e)
+{
+    size_t len = (size_t)(e - s);
+    sc_check_size(len);
+    memcpy(sc_end, s, len);
+    sc_end += len;
+}
+
+static void
 search_stmt_newline(bool *force_nl)
 {
     if (sc_end == NULL) {
@@ -165,7 +193,7 @@ search_stmt_newline(bool *force_nl)
 	save_com[0] = save_com[1] = ' ';
 	sc_end = &save_com[2];
     }
-    *sc_end++ = '\n';
+    sc_add_char('\n');
 
     line_no++;
 
@@ -203,23 +231,16 @@ search_stmt_comment(bool *comment_buffer
     }
 
     *comment_buffered = true;
-    *sc_end++ = '/';		/* copy in start of comment */
-    *sc_end++ = '*';
+    sc_add_char('/');
+    sc_add_char('*');
 
     for (;;) {			/* loop until the end of the comment */
-	*sc_end++ = inbuf_next();
-	if (sc_end[-1] == '*' && *inp.s == '/')
-	    break;		/* we are at end of comment */
-	if (sc_end >= &save_com[sc_size]) {	/* check for temp buffer
-						 * overflow */
-	    diag(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever");
-	    fflush(output);
-	    exit(1);
+	sc_add_char(inbuf_next());
+	if (sc_end[-1] == '*' && *inp.s == '/') {
+	    sc_add_char(inbuf_next());
+	    break;
 	}
     }
-
-    *sc_end++ = '/';		/* add ending slash */
-    inbuf_skip();		/* get past / in buffer */
 }
 
 static bool
@@ -272,9 +293,8 @@ search_stmt_other(lexer_symbol lsym, boo
     if (opt.swallow_optional_blanklines ||
 	(!comment_buffered && remove_newlines)) {
 	*force_nl = !remove_newlines;
-	while (sc_end > save_com && sc_end[-1] == '\n') {
+	while (sc_end > save_com && sc_end[-1] == '\n')
 	    sc_end--;
-	}
     }
 
     if (*force_nl) {		/* if we should insert a nl here, put it into
@@ -282,15 +302,14 @@ search_stmt_other(lexer_symbol lsym, boo
 	*force_nl = false;
 	--line_no;		/* this will be re-increased when the newline
 				 * is read from the buffer */
-	*sc_end++ = '\n';
-	*sc_end++ = ' ';
+	sc_add_char('\n');
+	sc_add_char(' ');
 	if (opt.verbose)	/* warn if the line was not already broken */
 	    diag(0, "Line broken");
     }
 
-    /* XXX: buffer overflow? This is essentially a strcpy. */
     for (const char *t_ptr = token.s; *t_ptr != '\0'; ++t_ptr)
-	*sc_end++ = *t_ptr;
+	sc_add_char(*t_ptr);
     return true;
 }
 
@@ -302,7 +321,7 @@ switch_buffer(void)
     saved_inp_e = inp.e;
     inp.s = save_com;		/* fix so that subsequent calls to lexi will
 				 * take tokens out of save_com */
-    *sc_end++ = ' ';		/* add trailing blank, just in case */
+    sc_add_char(' ');		/* add trailing blank, just in case */
     inp.e = sc_end;
     sc_end = NULL;
     debug_println("switched inp.s to save_com");
@@ -332,13 +351,8 @@ search_stmt_lookahead(lexer_symbol *lsym
      * into the buffer so that the later lexi() call will read them.
      */
     if (sc_end != NULL) {
-	while (ch_isblank(*inp.s)) {
-	    *sc_end++ = *inp.s++;
-	    if (sc_end >= &save_com[sc_size])
-		errx(1, "input too long");
-	}
-	if (inp.s >= inp.e)
-	    inbuf_read_line();
+	while (ch_isblank(*inp.s))
+	    sc_add_char(inbuf_next());
     }
 
     struct parser_state backup_ps = ps;
@@ -1240,14 +1254,11 @@ read_preprocessing_line(void)
 	    save_com = sc_buf;
 	    sc_end = save_com;
 	} else {
-	    *sc_end++ = '\n';	/* add newline between comments */
-	    *sc_end++ = ' ';
+	    sc_add_char('\n');	/* add newline between comments */
+	    sc_add_char(' ');
 	    --line_no;
 	}
-	if (sc_end - save_com + com_end - com_start > sc_size)
-	    errx(1, "input too long");
-	memmove(sc_end, lab.s + com_start, (size_t)(com_end - com_start));
-	sc_end += com_end - com_start;
+	sc_add_range(lab.s + com_start, lab.s + com_end);
 	lab.e = lab.s + com_start;
 	while (lab.e > lab.s && ch_isblank(lab.e[-1]))
 	    lab.e--;
@@ -1255,7 +1266,7 @@ read_preprocessing_line(void)
 	saved_inp_e = inp.e;
 	inp.s = save_com;	/* fix so that subsequent calls to lexi will
 				 * take tokens out of save_com */
-	*sc_end++ = ' ';	/* add trailing blank, just in case */
+	sc_add_char(' ');	/* add trailing blank, just in case */
 	inp.e = sc_end;
 	sc_end = NULL;
 	debug_println("switched inp.s to save_com");

Reply via email to