NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

lib/60050: libedit doesn't handle long lines correctly



>Number:         60050
>Category:       lib
>Synopsis:       libedit doesn't handle long lines correctly
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    lib-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Mar 03 01:05:00 +0000 2026
>Originator:     Kristofer Peterson
>Release:        NetBSD-current
>Organization:
Tranception Limited
>Environment:
>Description:
If the current input line is long (i.e. greater than EL_BUFSIZ which is 1024 bytes), going to a previous history line will only copy the first EL_BUFSIZ characters into the history but still set the length to full buffer, thus including trailing garbage in the history which if one then returns to the current line can then see.

This was first observed in /bin/sh in FreeBSD-15.0 which incorporates libedit under contrib/libedit, the upstream snapshot was 2025-01-03.

I applied the patch against a clean checkout of https://github.com/NetBSD/src, branch trunk, commit d78321bcf99595ead2ef93fe8624f32d4299d430 (HEAD -> trunk); I include the git diff output below.
>How-To-Repeat:
- run /bin/sh interactively (or another application using libedit)
- enter a long line exceeding EL_BUFSIZ (1024) characters
- go to the previous history line (^P in emacs mode, up arrow, etc.)
- go back to the next history line (^N in emacs mode, down arrow, etc.)
- observe the long line is truncated followed by garbage (nulls etc.)
>Fix:
diff --git a/lib/libedit/chared.c b/lib/libedit/chared.c
index e66fed1faae3..a52296e02ca4 100644
--- a/lib/libedit/chared.c
+++ b/lib/libedit/chared.c
@@ -561,7 +561,7 @@ ch_enlargebufs(EditLine *el, size_t addlen)
                        (el->el_chared.c_redo.lim - el->el_chared.c_redo.buf);
        el->el_chared.c_redo.buf = newbuffer;
 
-       if (!hist_enlargebuf(el, sz, newsz))
+       if (!hist_enlargebuf(el, newsz))
                return 0;
 
        /* Safe to set enlarged buffer size */
diff --git a/lib/libedit/common.c b/lib/libedit/common.c
index b1756b87235d..eb593c12d686 100644
--- a/lib/libedit/common.c
+++ b/lib/libedit/common.c
@@ -569,7 +569,7 @@ ed_prev_history(EditLine *el, wint_t c __attribute__((__unused__)))
        if (el->el_history.eventno == 0) {      /* save the current buffer
                                                 * away */
                (void) wcsncpy(el->el_history.buf, el->el_line.buffer,
-                   EL_BUFSIZ);
+                   el->el_history.sz);
                el->el_history.last = el->el_history.buf +
                    (el->el_line.lastchar - el->el_line.buffer);
        }
@@ -641,7 +641,7 @@ ed_search_prev_history(EditLine *el, wint_t c __attribute__((__unused__)))
        }
        if (el->el_history.eventno == 0) {
                (void) wcsncpy(el->el_history.buf, el->el_line.buffer,
-                   EL_BUFSIZ);
+                   el->el_history.sz);
                el->el_history.last = el->el_history.buf +
                    (el->el_line.lastchar - el->el_line.buffer);
        }
diff --git a/lib/libedit/hist.c b/lib/libedit/hist.c
index 19ce1c161722..89ad8c7deaf1 100644
--- a/lib/libedit/hist.c
+++ b/lib/libedit/hist.c
@@ -223,9 +223,13 @@ hist_command(EditLine *el, int argc, const wchar_t **argv)
  */
 libedit_private int
 /*ARGSUSED*/
-hist_enlargebuf(EditLine *el, size_t oldsz, size_t newsz)
+hist_enlargebuf(EditLine *el, size_t newsz)
 {
        wchar_t *newbuf;
+       const size_t oldsz = el->el_history.sz;
+
+       if (newsz <= oldsz)
+               return 1;
 
        newbuf = el_realloc(el->el_history.buf, newsz * sizeof(*newbuf));
        if (!newbuf)
diff --git a/lib/libedit/hist.h b/lib/libedit/hist.h
index 8f5ab08390d2..6d1b7feb3ce8 100644
--- a/lib/libedit/hist.h
+++ b/lib/libedit/hist.h
@@ -74,7 +74,7 @@ libedit_private void          hist_end(EditLine *);
 libedit_private el_action_t    hist_get(EditLine *);
 libedit_private int            hist_set(EditLine *, hist_fun_t, void *);
 libedit_private int            hist_command(EditLine *, int, const wchar_t **);
-libedit_private int            hist_enlargebuf(EditLine *, size_t, size_t);
+libedit_private int            hist_enlargebuf(EditLine *, size_t);
 libedit_private wchar_t        *hist_convert(EditLine *, int, void *);
 
 #endif /* _h_el_hist */



Home | Main Index | Thread Index | Old Index