lib/60593: libedit: buffer overruns and arithmetic overflow

"[email protected] via gnats" <[email protected]>
Newsgroups gmane.os.netbsd.bugs
Message-ID <[email protected]>
>Number:         60593
>Category:       lib
>Synopsis:       libedit: buffer overruns and arithmetic overflow
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    lib-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Aug 14 22:35:00 +0000 2026
>Originator:     Taylor R Campbell
>Release:        current, 11, 10, 9
>Organization:
The NetBSD Editation, Inc.
>Environment:
>Description:

1.	In libedit/readline.c getfrom, a 2021 fix for an off-by-one
	error in a bounds check (to verify that there is space in the
	buffer for len bytes plus a NUL byte) inadvertently turned it
	into an off-by-two error in a bounds check:

    693 	char *what = el_realloc(*fromp, size * sizeof(*what));
...
    699 	for (; *cmd && *cmd != delim; cmd++) {
    700 		if (*cmd == '\\' && cmd[1] == delim)
    701 			cmd++;
 => 702 		if (len - 1 >= size) {
    703 			char *nwhat;
    704 			nwhat = el_realloc(what, (size <<= 1) * sizeof(*nwhat));
    705 			if (nwhat == NULL) {
    706 				el_free(what);
    707 				el_free(*fromp);
    708 				*cmdp = cmd;
    709 				*fromp = NULL;
    710 				return 0;
    711 			}
    712 			what = nwhat;
    713 		}
    714 		what[len++] = *cmd;
    715 	}
    716 	what[len] = '\0';

https://nxr.netbsd.org/xref/src/lib/libedit/readline.c?r=1.184#687

	The attempted fix was in rev. 1.166:

@@ -676,7 +674,7 @@ getfrom(const char **cmdp, char **fromp, const char *search, int delim)
 	for (; *cmd && *cmd != delim; cmd++) {
 		if (*cmd == '\\' && cmd[1] == delim)
 			cmd++;
-		if (len >= size) {
+		if (len - 1 >= size) {
 			char *nwhat;
 			nwhat = el_realloc(what, (size <<= 1) * sizeof(*nwhat));
 			if (nwhat == NULL) {

	Additionally, size << 1 (i.e., size * 2) could in principle
	overflow; should verify size < SIZE_MAX/2/sizeof(*nwhat) before
	computing (size << 1) * sizeof(*nwhat).

2. 	Possible three-wchar buffer overrun in vi mode searching:

     73 	el->el_search.patbuf = el_calloc(EL_BUFSIZ,
     74 	    sizeof(*el->el_search.patbuf));
...
    489 		if (el->el_search.patbuf[0] != '.' &&
    490 		    el->el_search.patbuf[0] != '*') {
    491 			(void) wcsncpy(tmpbuf, el->el_search.patbuf,
    492 			    sizeof(tmpbuf) / sizeof(*tmpbuf) - 1);
    493 			el->el_search.patbuf[0] = '.';
    494 			el->el_search.patbuf[1] = '*';
    495 			(void) wcsncpy(&el->el_search.patbuf[2], tmpbuf,
    496 			    EL_BUFSIZ - 3);
    497 			el->el_search.patlen++;
    498 			el->el_search.patbuf[el->el_search.patlen++] = '.';
    499 			el->el_search.patbuf[el->el_search.patlen++] = '*';
    500 			el->el_search.patbuf[el->el_search.patlen] = '\0';
    501 		}

https://nxr.netbsd.org/xref/src/lib/libedit/search.c?r=1.53#488

	If, on input, the search already has a maximum-length patbuf
	(and I see no way to rule this out), el->el_search.patlen++ may
	advance past the end of the buffer.

	Reported by Miroslav Lichvar <[email protected]>.

>How-To-Repeat:

	code inspection
	abuse^Wheavy use of interactive history editing or search features


>Fix:

1.	Fix the bounds check by saying `+ 1' instead of `- 1', and
	check for arithmetic overflow.

2.	Fail if el->el_search.patlen >= EL_BUFSIZE - 3.
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.