| Summary: | A use-after-free in busybox's bc applet | ||
|---|---|---|---|
| Product: | Busybox | Reporter: | xiechengliang <xiechengliang1> |
| Component: | Other | Assignee: | unassigned |
| Status: | RESOLVED FIXED | ||
| Severity: | major | CC: | busybox-cvs |
| Priority: | P5 | ||
| Version: | 1.33.x | ||
| Target Milestone: | --- | ||
| Hardware: | All | ||
| OS: | Linux | ||
| Host: | Target: | ||
| Build: | |||
| Attachments: | poc | ||
|
Description
xiechengliang
2022-08-09 14:30:22 UTC
Debug with gdb, print stack ========================================================================== Adapted from https://github.com/gavinhoward/bc Original code (c) 2018 Gavin D. Howard and contributors Breakpoint 1, bc_vec_grow (v=v@entry=0x69b160, n=n@entry=1) at miscutils/bc.c:1095 1095 { (gdb) bt #0 bc_vec_grow (v=v@entry=0x69b160, n=n@entry=1) at miscutils/bc.c:1095 #1 0x000000000040adf4 in bc_vec_npush (v=v@entry=0x69b160, n=n@entry=1, data=data@entry=0x7fffffffda9f) at miscutils/bc.c:1149 #2 0x000000000040ae2b in bc_vec_push (v=v@entry=0x69b160, data=data@entry=0x7fffffffda9f) at miscutils/bc.c:1157 #3 0x000000000040cfe2 in bc_vec_pushByte (data=94 '^', v=0x69b160) at miscutils/bc.c:1182 #4 xc_read_line (vec=vec@entry=0x69b160, fp=0x69f6b0) at miscutils/bc.c:2654 #5 0x000000000040d03f in peek_inbuf () at miscutils/bc.c:2893 #6 0x000000000040d0d2 in zxc_lex_number (last=52 '4') at miscutils/bc.c:2969 #7 0x000000000040d6be in zbc_lex_token () at miscutils/bc.c:3343 #8 zxc_lex_next () at miscutils/bc.c:3057 #9 0x000000000040e2c3 in zbc_parse_name (type=type@entry=0x7fffffffdbec, flags=flags@entry=2 '\002') at miscutils/bc.c:3961 #10 0x000000000040df58 in zbc_parse_expr (flags=flags@entry=2 '\002') at miscutils/bc.c:4908 #11 0x000000000040e5bf in zbc_parse_stmt_possibly_auto (auto_allowed=auto_allowed@entry=false) at miscutils/bc.c:4707 #12 0x000000000040ed83 in zbc_parse_stmt () at miscutils/bc.c:3818 #13 zbc_parse_stmt_or_funcdef () at miscutils/bc.c:4782 #14 zxc_vm_process (text=text@entry=0x497b06 "") at miscutils/bc.c:6959 #15 0x00000000004104de in zxc_vm_execute_FILE (fp=fp@entry=0x69f6b0, filename=filename@entry=0x7fffffffe586 "new_txt") at miscutils/bc.c:7060 #16 0x00000000004107e3 in zxc_vm_file (file=0x7fffffffe586 "new_txt") at miscutils/bc.c:7077 #17 zxc_vm_exec () at miscutils/bc.c:7347 #18 xc_vm_run () at miscutils/bc.c:7508 #19 bc_main (argc=<optimized out>, argv=<optimized out>) at miscutils/bc.c:7541 #20 0x000000000040784d in run_applet_no_and_exit (applet_no=applet_no@entry=10, name=name@entry=0x7fffffffe583 "bc", argv=argv@entry=0x7fffffffe1b0) at libbb/appletlib.c:1023 #21 0x0000000000407bd2 in run_applet_and_exit (name=0x7fffffffe583 "bc", argv=argv@entry=0x7fffffffe1b0) at libbb/appletlib.c:1046 #22 0x0000000000407b23 in busybox_main (argv=0x7fffffffe1b0) at libbb/appletlib.c:973 #23 run_applet_and_exit (name=<optimized out>, argv=argv@entry=0x7fffffffe1a8) at libbb/appletlib.c:1035 #24 0x0000000000407c62 in main (argc=<optimized out>, argv=0x7fffffffe1a8) at libbb/appletlib.c:1180 ===================================================================== In zxc_lex_next(): p->lex_next_at = p->lex_inbuf; then, zbc_len_token->...->bc_vec_grow will realloc lex_inbuf, The reallocation is done by either: a) expanding or contracting the existing area pointed to by ptr, if possible. The contents of the area remain unchanged up to the lesser of the new and old sizes. If the area is expanded, the contents of the new part of the array are undefined. b) allocating a new memory block of size new_size bytes, copying memory area with size equal the lesser of the new and the old sizes, and freeing the old block. In the b scenario, continuing to use lex_next_at leads to use-after-free. In in bc_error_at miscutils/bc.c:988 leads to use-after-free static ERRORFUNC int bc_error_at(const char *msg) { const char *err_at = G.prs.lex_next_at; if (err_at) { IF_ERROR_RETURN_POSSIBLE(return) bc_error_fmt( "%s at '%.*s'", msg, (int)(strchrnul(err_at, '\n') - err_at), err_at ); } ..... } Possible fix:
diff --git a/miscutils/bc.c b/miscutils/bc.c
index ab785bbc8..44e55eeea 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -3048,16 +3048,16 @@ static BC_STATUS zxc_lex_next(void)
if (peek_inbuf() == '\0')
RETURN_STATUS(BC_STATUS_SUCCESS);
}
- p->lex_next_at = p->lex_inbuf;
- dbg_lex("next string to parse:'%.*s'",
- (int)(strchrnul(p->lex_next_at, '\n') - p->lex_next_at),
- p->lex_next_at
- );
if (IS_BC) {
IF_BC(s = zbc_lex_token());
} else {
IF_DC(s = zdc_lex_token());
}
+ p->lex_next_at = p->lex_inbuf;
+ dbg_lex("next string to parse:'%.*s'",
+ (int)(strchrnul(p->lex_next_at, '\n') - p->lex_next_at),
+ p->lex_next_at
+ );
} while (!s && p->lex == XC_LEX_WHITESPACE);
dbg_lex("p->lex from string:%d", p->lex);
I can't reproduce it.
Does this fix work for you?
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -2892,6 +2892,8 @@ static char peek_inbuf(void)
) {
xc_read_line(&G.input_buffer, G.prs.lex_input_fp);
G.prs.lex_inbuf = G.input_buffer.v;
+ /* lex_next_at may point to now-freed data, update it */
+ G.prs.lex_next_at = G.prs.lex_inbuf;
if (G.input_buffer.len <= 1) // on EOF, len is 1 (NUL byte)
G.prs.lex_input_fp = NULL;
}
yes, fix it |