Bug 15871

Summary: [busybox 1.36.1] use-after-free in awk
Product: Busybox Reporter: zclin <zclin21>
Component: OtherAssignee: unassigned
Status: NEW ---    
Severity: normal CC: busybox-cvs, uwe
Priority: P5    
Version: unspecified   
Target Milestone: ---   
Hardware: All   
OS: Linux   
Host: Target:
Build:
Attachments: POC file
awk_t1_input file

Description zclin 2023-11-23 04:43:46 UTC
Hi, busybox developers,
We found a use-after-free vulnerability in awk applet of busybox v1.36.1. The affected component is awk.c:1064 in copyvar function. Following is the reproduction process, and we put the poc file in the attachment.
[1.] Environment
Ubuntu 18.04, 64 bit
BusyBox 1.36.1
Clang 6.0.0

[2.] Compilation
2.1 Modify the Makefile:
HOSTCC=clang -fsanitize=address
HOSTCXX=clang++ -fsanitize=address
CC=clang
CFLAGS=-fsanitize=address
CPPFLAGS=-fsanitize=address
LDFLAGS="-Wl,--allow-multiple-definition"
2.2 Modify the Config.in file, switch the following configs to y:
DEBUG: y
DEBUG_PESSIMIZE: y
FEATURE_CLEAN_UP: y
DEBUG_SANITIZE: y
2.3 Commands for compilation:
export ASAN_OPTIONS=detect_leaks=0
make defconfig
make install

[3.] Reproduction
export ASAN_OPTIONS="abort_on_error=1 symbolize=0"
./busybox_unstripped awk -f $poc ./awk_t1_input
[ASAN report]:

==32093==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000003080 at pc 0x000000e7dfe2 bp 0x7fff6ee9b930 sp 0x7fff6ee9b928
READ of size 4 at 0x606000003080 thread T0
    #0 0xe7dfe1  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe7dfe1)
    #1 0xe4bbdf  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe4bbdf)
    #2 0xe4eb16  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe4eb16)
    #3 0xe4886f  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe4886f)
    #4 0xe4886f  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe4886f)
    #5 0xe4062d  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe4062d)
    #6 0x50ac81  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0x50ac81)
    #7 0x50dbaf  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0x50dbaf)
    #8 0x51036d  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0x51036d)
    #9 0x50db58  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0x50db58)
    #10 0x50c3fd  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0x50c3fd)
    #11 0x7f8358526c86  (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
    #12 0x41e459  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0x41e459)

0x606000003080 is located 0 bytes inside of 64-byte region [0x606000003080,0x6060000030c0)
freed by thread T0 here:
    #0 0x4dc500  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0x4dc500)
    #1 0xe7f4ca  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe7f4ca)
    #2 0xe4886f  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe4886f)
    #3 0xe4eb16  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe4eb16)
    #4 0xe4886f  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe4886f)
    #5 0xe4886f  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe4886f)
    #6 0xe4062d  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe4062d)
    #7 0x50ac81  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0x50ac81)

previously allocated by thread T0 here:
    #0 0x4dc6d0  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0x4dc6d0)
    #1 0x519df2  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0x519df2)
    #2 0xe4886f  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe4886f)
    #3 0xe4eb16  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe4eb16)
    #4 0xe4886f  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe4886f)
    #5 0xe4886f  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe4886f)
    #6 0xe4062d  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe4062d)
    #7 0x50ac81  (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0x50ac81)

SUMMARY: AddressSanitizer: heap-use-after-free (/home/zclin/afl-vul-score/llvm_mode/research/path-collect-all-new-0524/path-collect-all-new/busybox/reproduce/busybox-1_36_1/fuzz_check/awk/busybox_unstripped+0xe7dfe1)
 

[line number]:

addr2line -e ./busybox_unstripped 0xe7dfe1
.../busybox-1_36_1/editors/awk.c:1064

Best wishes,
Zclin
Comment 1 zclin 2023-11-23 04:44:10 UTC
Created attachment 9673 [details]
POC file
Comment 2 zclin 2023-11-23 04:44:30 UTC
Created attachment 9676 [details]
awk_t1_input file
Comment 3 Valery Ushakov 2024-01-25 00:50:34 UTC
The result of OC_REPLACE may be a TEMPVAR0 via L.v

  res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : L.v, ...);
Comment 4 Natanael Copa 2024-05-20 15:50:40 UTC
This appears to be fixed in git master. valgrind with the attached POC does not show anything.

But I am not sure which commit fixes it?
Comment 5 Natanael Copa 2024-05-20 17:25:19 UTC
A git bisect with the POC shows that it was fixed with

commit 0256e00a9d077588bd3a39f5a1ef7e2eaa2911e4 (HEAD)
Author: Denys Vlasenko <vda.linux@googlemail.com>
Date:   Tue May 30 16:42:18 2023 +0200

    awk: fix precedence of = relative to ==


https://git.busybox.net/busybox/commit/editors/awk.c?id=0256e00a9d077588bd3a39f5a1ef7e2eaa2911e4
Comment 6 Natanael Copa 2024-05-21 15:10:20 UTC
(In reply to Natanael Copa from comment #5)

The commit that "fixes" it also introduces a regression.

  awk 'BEGIN { a = 0 ? \"yes\": \"no\"; print a }'

Prints '0' instead of 'no'. But that is a different issue.

I have a smaller reproducer for the use-after-free:

```
function f1(v) {
	return v
}

function f2(a)
{
	return f1(a) -= 0
}

function f3(a)
{
	return missingfunc(a)
}

BEGIN {
	f2() || f3()
}
```


Or:
awk 'function f1(v) { return v } function f2(a) { return f1(a) -= 0 } function f3(a) { return missingfunc(a) } BEGIN { f2() || f3() }'