Bug 279772 - use (write) after free in libedit's em_copy_prev_word()
Summary: use (write) after free in libedit's em_copy_prev_word()
Status: Open
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: CURRENT
Hardware: Any Any
: --- Affects Some People
Assignee: Baptiste Daroussin
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-06-15 20:17 UTC by Robert Morris
Modified: 2025-04-15 00:27 UTC (History)
2 users (show)

See Also:


Attachments
demo of a use-after-free in libedit's em_copy_prev_word() (2.30 KB, text/plain)
2024-06-15 20:17 UTC, Robert Morris
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Robert Morris 2024-06-15 20:17:43 UTC
Created attachment 251479 [details]
demo of a use-after-free in libedit's em_copy_prev_word()

em_copy_prev_word() in contrib/libedit/emacs.c:

        oldc = el->el_line.cursor;
        /* does a bounds check */
        cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
            el->el_state.argument, ce__isword);

        c_insert(el, (int)(oldc - cp));
        for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++)
                *dp++ = *cp;

c_insert() can call realloc() on el->el_line.buffer. This means that
oldc and cp can end up pointing into the old buffer that realloc()
freed. Then the assignment in the for loop reads and writes freed
memory.

I've attached a demo of this in sh's use of libedit. The demo requires
/usr/local/bin/valgrind.

$ cc sh11a.c -lutil
$ ./a.out
...
  Invalid read of size 4
     at 0x487C1AC: em_copy_prev_word (rtm/freebsd/contrib/libedit/emacs.c:458)
     by 0x4889747: el_wgets (rtm/freebsd/contrib/libedit/read.c:540)
     by 0x4879B3C: el_gets (rtm/freebsd/contrib/libedit/eln.c:75)
     by 0x123D6E: preadfd (rtm/freebsd/bin/sh/input.c:138)
     by 0x12387A: preadbuffer (rtm/freebsd/bin/sh/input.c:210)
     by 0x1326C5: xxreadtoken (rtm/freebsd/bin/sh/parser.c:910)
     by 0x12E4FC: readtoken (rtm/freebsd/bin/sh/parser.c:827)
     by 0x12E379: parsecmd (rtm/freebsd/bin/sh/parser.c:222)
     by 0x129786: cmdloop (rtm/freebsd/bin/sh/main.c:206)
     by 0x1295D2: main (rtm/freebsd/bin/sh/main.c:167)
   Address 0x553d160 is 0 bytes inside a block of size 8,192 free'd
     at 0x4851951: realloc (vg_replace_malloc.c:1694)
     by 0x48732AA: ch_enlargebufs (rtm/freebsd/contrib/libedit/chared.c:502)
     by 0x487318C: c_insert (rtm/freebsd/contrib/libedit/chared.c:104)
     by 0x487C16A: em_copy_prev_word (rtm/freebsd/contrib/libedit/emacs.c:456)
     by 0x4889747: el_wgets (rtm/freebsd/contrib/libedit/read.c:540)
     by 0x4879B3C: el_gets (rtm/freebsd/contrib/libedit/eln.c:75)
     by 0x123D6E: preadfd (rtm/freebsd/bin/sh/input.c:138)
     by 0x12387A: preadbuffer (rtm/freebsd/bin/sh/input.c:210)
     by 0x1326C5: xxreadtoken (rtm/freebsd/bin/sh/parser.c:910)
     by 0x12E4FC: readtoken (rtm/freebsd/bin/sh/parser.c:827)
     by 0x12E379: parsecmd (rtm/freebsd/bin/sh/parser.c:222)
     by 0x129786: cmdloop (rtm/freebsd/bin/sh/main.c:206)
   Block was alloc'd at
     at 0x4851951: realloc (vg_replace_malloc.c:1694)
     by 0x48732AA: ch_enlargebufs (rtm/freebsd/contrib/libedit/chared.c:502)
     by 0x4875B8D: ed_insert (rtm/freebsd/contrib/libedit/common.c:86)
     by 0x4889747: el_wgets (rtm/freebsd/contrib/libedit/read.c:540)
     by 0x4879B3C: el_gets (rtm/freebsd/contrib/libedit/eln.c:75)
     by 0x123D6E: preadfd (rtm/freebsd/bin/sh/input.c:138)
     by 0x12387A: preadbuffer (rtm/freebsd/bin/sh/input.c:210)
     by 0x1326C5: xxreadtoken (rtm/freebsd/bin/sh/parser.c:910)
     by 0x12E4FC: readtoken (rtm/freebsd/bin/sh/parser.c:827)
     by 0x12E379: parsecmd (rtm/freebsd/bin/sh/parser.c:222)
     by 0x129786: cmdloop (rtm/freebsd/bin/sh/main.c:206)
     by 0x1295D2: main (rtm/freebsd/bin/sh/main.c:167)
  
  Invalid write of size 4
     at 0x487C1BD: em_copy_prev_word (rtm/freebsd/contrib/libedit/emacs.c:458)
     by 0x4889747: el_wgets (rtm/freebsd/contrib/libedit/read.c:540)
     by 0x4879B3C: el_gets (rtm/freebsd/contrib/libedit/eln.c:75)
     by 0x123D6E: preadfd (rtm/freebsd/bin/sh/input.c:138)
     by 0x12387A: preadbuffer (rtm/freebsd/bin/sh/input.c:210)
     by 0x1326C5: xxreadtoken (rtm/freebsd/bin/sh/parser.c:910)
     by 0x12E4FC: readtoken (rtm/freebsd/bin/sh/parser.c:827)
     by 0x12E379: parsecmd (rtm/freebsd/bin/sh/parser.c:222)
     by 0x129786: cmdloop (rtm/freebsd/bin/sh/main.c:206)
     by 0x1295D2: main (rtm/freebsd/bin/sh/main.c:167)
   Address 0x553e164 is 4,100 bytes inside a block of size 8,192 free'd
     at 0x4851951: realloc (vg_replace_malloc.c:1694)
     by 0x48732AA: ch_enlargebufs (rtm/freebsd/contrib/libedit/chared.c:502)
     by 0x487318C: c_insert (rtm/freebsd/contrib/libedit/chared.c:104)
     by 0x487C16A: em_copy_prev_word (rtm/freebsd/contrib/libedit/emacs.c:456)
     by 0x4889747: el_wgets (rtm/freebsd/contrib/libedit/read.c:540)
     by 0x4879B3C: el_gets (rtm/freebsd/contrib/libedit/eln.c:75)
     by 0x123D6E: preadfd (rtm/freebsd/bin/sh/input.c:138)
     by 0x12387A: preadbuffer (rtm/freebsd/bin/sh/input.c:210)
     by 0x1326C5: xxreadtoken (rtm/freebsd/bin/sh/parser.c:910)
     by 0x12E4FC: readtoken (rtm/freebsd/bin/sh/parser.c:827)
     by 0x12E379: parsecmd (rtm/freebsd/bin/sh/parser.c:222)
     by 0x129786: cmdloop (rtm/freebsd/bin/sh/main.c:206)
   Block was alloc'd at
     at 0x4851951: realloc (vg_replace_malloc.c:1694)
     by 0x48732AA: ch_enlargebufs (rtm/freebsd/contrib/libedit/chared.c:502)
     by 0x4875B8D: ed_insert (rtm/freebsd/contrib/libedit/common.c:86)
     by 0x4889747: el_wgets (rtm/freebsd/contrib/libedit/read.c:540)
     by 0x4879B3C: el_gets (rtm/freebsd/contrib/libedit/eln.c:75)
     by 0x123D6E: preadfd (rtm/freebsd/bin/sh/input.c:138)
     by 0x12387A: preadbuffer (rtm/freebsd/bin/sh/input.c:210)
     by 0x1326C5: xxreadtoken (rtm/freebsd/bin/sh/parser.c:910)
     by 0x12E4FC: readtoken (rtm/freebsd/bin/sh/parser.c:827)
     by 0x12E379: parsecmd (rtm/freebsd/bin/sh/parser.c:222)
     by 0x129786: cmdloop (rtm/freebsd/bin/sh/main.c:206)
     by 0x1295D2: main (rtm/freebsd/bin/sh/main.c:167)
Comment 1 Mark Johnston freebsd_committer freebsd_triage 2024-06-30 15:18:32 UTC
This is fixed upstream now: https://github.com/NetBSD/src/commit/427b3799c0bef6c2025e1a9124677f02c6c64cb3
Comment 2 John Baldwin freebsd_committer freebsd_triage 2025-04-15 00:27:41 UTC
Baptiste,

Can you do a new vendor import of libedit to pull in the upstream fix for this bug?