-
Notifications
You must be signed in to change notification settings - Fork 208
Description
Affected Projects
Augeas 1.14.1 (https://github.com/hercules-team/augeas)
Problem Type
CWE-416: Use After Free
Description
A heap-use-after-free vulnerability was discovered in the eval_else function within Augeas. This issue occurs when evaluating certain expressions, potentially leading to a crash.
Details
The vulnerability arises in the eval_else function defined in src/pathx.c at line 1014.
The vulnerability is caused by the fact that in function rpl_realloc, when pointer p exists and n is a number larger than the address space pointed to by the current pointer p, a pointer pointing to a different address from p is returned. However, in function eval_else, no effective judgment is made and the original address is still used, resulting in heap-use-after-free.
static void eval_else(struct state *state, struct expr *expr, struct locpath_trace *lpt_right) {
struct value *r = pop_value(state);
struct value *l = pop_value(state);
if ( l->tag == T_NODESET && r->tag == T_NODESET ) {
int discard_maxns=0;
struct nodeset **discard_ns=NULL;
struct locpath_trace *lpt = state->locpath_trace;
value_ind_t vind = make_value(T_NODESET, state);
if (l->nodeset->used >0 || expr->left_matched) { //heap-use-after-free
expr->left_matched = 1;
state->value_pool[vind].nodeset = clone_nodeset(l->nodeset, state);
if( lpt_right != NULL ) {
discard_maxns = lpt_right->maxns;
discard_ns = lpt_right->ns;
}
}
// ...
} else {
// ...
}
}void *
rpl_realloc (void *p, size_t n)
{
if (p == NULL)
return malloc (n);
if (n == 0)
{
free (p); //set p to NULL after free?
return NULL;
}
if (xalloc_oversized (n, 1))
{
errno = ENOMEM;
return NULL;
}
void *result = realloc (p, n); //Free original address when n is greater than the current address space size
#if !HAVE_MALLOC_POSIX
if (result == NULL)
errno = ENOMEM;
#endif
return result;
}PoC
Steps to reproduce:
- Clone the Augeas repository and build it with the OSS-Fuzz configuration.
- ENV
export CC='clang'
export CXX='clang++'
export CFLAGS='-fsanitize=address -g'
export CXXFLAGS='-fsanitize=address -g'- harness from OSS-Fuzz
#include "config.h"
#include "augeas.h"
#include "internal.h"
#include "memory.h"
#include "syntax.h"
#include "transform.h"
#include "errcode.h"
#include <fnmatch.h>
#include <argz.h>
#include <string.h>
#include <stdarg.h>
#include <locale.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if(size<3){
return 0;
}
char *loadpath = NULL;
const char *value;
const char *label;
char *new_str = (char *)malloc(size+1);
if (new_str == NULL){
return 0;
}
memcpy(new_str, data, size);
new_str[size] = '\0';
struct augeas *aug = aug_init(new_str, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
aug_defvar(aug, new_str, &new_str[1]);
aug_get(aug, new_str, &value);
aug_label(aug, new_str, &label);
aug_rename(aug, new_str, &new_str[1]);
aug_text_store(aug, &new_str[1], new_str, &new_str[2]);
aug_print(aug, stdout, new_str);
aug_setm(aug, new_str, NULL, &new_str[1]);
free(new_str);
aug_close(aug);
return 0;
}- Compile the fuzzer
clang++ -fsanitize=address,fuzzer -g -std=c++11 -Isrc/ `xml2-config --cflags` augeas_api_fuzzer.cc -o augeas_api_fuzzer src/.libs/libaugeas.a src/.libs/libfa.a ./gnulib/lib/.libs/libgnu.a /usr/lib/x86_64-linux-gnu/libxml2.a- Run the fuzzer to trigger the segmentation fault:
./augeas_api_fuzzer ./eval_else-huafThe invalid read access will cause AddressSanitizer to report a segmentation fault during the execution of the post-processing logic.
Report
Running: ./eval_else-huaf
=================================================================
==115092==ERROR: AddressSanitizer: heap-use-after-free on address 0x60c000002ca8 at pc 0x5d2d9466589e bp 0x7ffd8eb7fb20 sp 0x7ffd8eb7fb18
READ of size 8 at 0x60c000002ca8 thread T0
#0 0x5d2d9466589d in eval_else /fuzz/project/augeas/src/pathx.c:1014:16
#1 0x5d2d946604fd in eval_binary /fuzz/project/augeas/src/pathx.c:1209:9
#2 0x5d2d9465ee55 in eval_expr /fuzz/project/augeas/src/pathx.c:1499:9
#3 0x5d2d9464ab1e in pathx_eval /fuzz/project/augeas/src/pathx.c:2869:5
#4 0x5d2d9464d8b0 in pathx_symtab_define /fuzz/project/augeas/src/pathx.c:3159:13
#5 0x5d2d9463ce68 in aug_defvar /fuzz/project/augeas/src/augeas.c:900:18
#6 0x5d2d946351fc in LLVMFuzzerTestOneInput /fuzz/project/augeas/augeas_api_fuzzer.cc:53:2
#7 0x5d2d9455b563 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/fuzz/fuzzers/cs/augeas_api_fuzzer+0x68563) (BuildId: c970f2227c313c5fcf7dac784e2536ef9e443a1e)
#8 0x5d2d945452df in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/fuzz/fuzzers/cs/augeas_api_fuzzer+0x522df) (BuildId: c970f2227c313c5fcf7dac784e2536ef9e443a1e)
#9 0x5d2d9454b036 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/fuzz/fuzzers/cs/augeas_api_fuzzer+0x58036) (BuildId: c970f2227c313c5fcf7dac784e2536ef9e443a1e)
#10 0x5d2d94574e52 in main (/fuzz/fuzzers/cs/augeas_api_fuzzer+0x81e52) (BuildId: c970f2227c313c5fcf7dac784e2536ef9e443a1e)
#11 0x7d01ffb4dd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#12 0x7d01ffb4de3f in __libc_start_main csu/../csu/libc-start.c:392:3
#13 0x5d2d9453fba4 in _start (/fuzz/fuzzers/cs/augeas_api_fuzzer+0x4cba4) (BuildId: c970f2227c313c5fcf7dac784e2536ef9e443a1e)
0x60c000002ca8 is located 40 bytes inside of 128-byte region [0x60c000002c80,0x60c000002d00)
freed by thread T0 here:
#0 0x5d2d945f8006 in __interceptor_realloc (/fuzz/fuzzers/cs/augeas_api_fuzzer+0x105006) (BuildId: c970f2227c313c5fcf7dac784e2536ef9e443a1e)
#1 0x5d2d9473e4b3 in rpl_realloc /fuzz/project/augeas/gnulib/lib/realloc.c:55:18
#2 0x5d2d9466cdc1 in mem_realloc_n /fuzz/project/augeas/src/memory.c:98:11
#3 0x5d2d94657a7b in make_value /fuzz/project/augeas/src/pathx.c:564:13
#4 0x5d2d94665874 in eval_else /fuzz/project/augeas/src/pathx.c:1013:28
#5 0x5d2d946604fd in eval_binary /fuzz/project/augeas/src/pathx.c:1209:9
#6 0x5d2d9465ee55 in eval_expr /fuzz/project/augeas/src/pathx.c:1499:9
#7 0x5d2d9464ab1e in pathx_eval /fuzz/project/augeas/src/pathx.c:2869:5
#8 0x5d2d9464d8b0 in pathx_symtab_define /fuzz/project/augeas/src/pathx.c:3159:13
#9 0x5d2d9463ce68 in aug_defvar /fuzz/project/augeas/src/augeas.c:900:18
#10 0x5d2d946351fc in LLVMFuzzerTestOneInput /fuzz/project/augeas/augeas_api_fuzzer.cc:53:2
#11 0x5d2d9455b563 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/fuzz/fuzzers/cs/augeas_api_fuzzer+0x68563) (BuildId: c970f2227c313c5fcf7dac784e2536ef9e443a1e)
#12 0x5d2d945452df in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/fuzz/fuzzers/cs/augeas_api_fuzzer+0x522df) (BuildId: c970f2227c313c5fcf7dac784e2536ef9e443a1e)
#13 0x5d2d9454b036 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/fuzz/fuzzers/cs/augeas_api_fuzzer+0x58036) (BuildId: c970f2227c313c5fcf7dac784e2536ef9e443a1e)
#14 0x5d2d94574e52 in main (/fuzz/fuzzers/cs/augeas_api_fuzzer+0x81e52) (BuildId: c970f2227c313c5fcf7dac784e2536ef9e443a1e)
#15 0x7d01ffb4dd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
previously allocated by thread T0 here:
#0 0x5d2d945f7dc8 in __interceptor_calloc (/fuzz/fuzzers/cs/augeas_api_fuzzer+0x104dc8) (BuildId: c970f2227c313c5fcf7dac784e2536ef9e443a1e)
#1 0x5d2d9466cbbc in mem_alloc_n /fuzz/project/augeas/src/memory.c:66:23
#2 0x5d2d94648b3b in pathx_parse /fuzz/project/augeas/src/pathx.c:2669:9
#3 0x5d2d946365e3 in pathx_aug_parse /fuzz/project/augeas/src/augeas.c:295:5
#4 0x5d2d9463cdd7 in aug_defvar /fuzz/project/augeas/src/augeas.c:898:13
#5 0x5d2d946351fc in LLVMFuzzerTestOneInput /fuzz/project/augeas/augeas_api_fuzzer.cc:53:2
#6 0x5d2d9455b563 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/fuzz/fuzzers/cs/augeas_api_fuzzer+0x68563) (BuildId: c970f2227c313c5fcf7dac784e2536ef9e443a1e)
#7 0x5d2d945452df in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/fuzz/fuzzers/cs/augeas_api_fuzzer+0x522df) (BuildId: c970f2227c313c5fcf7dac784e2536ef9e443a1e)
#8 0x5d2d9454b036 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/fuzz/fuzzers/cs/augeas_api_fuzzer+0x58036) (BuildId: c970f2227c313c5fcf7dac784e2536ef9e443a1e)
#9 0x5d2d94574e52 in main (/fuzz/fuzzers/cs/augeas_api_fuzzer+0x81e52) (BuildId: c970f2227c313c5fcf7dac784e2536ef9e443a1e)
#10 0x7d01ffb4dd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
SUMMARY: AddressSanitizer: heap-use-after-free /fuzz/project/augeas/src/pathx.c:1014:16 in eval_else
Shadow bytes around the buggy address:
0x0c187fff8540: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
0x0c187fff8550: fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa
0x0c187fff8560: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c187fff8570: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
0x0c187fff8580: fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa
=>0x0c187fff8590: fd fd fd fd fd[fd]fd fd fd fd fd fd fd fd fd fd
0x0c187fff85a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c187fff85b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c187fff85c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c187fff85d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c187fff85e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==115092==ABORTING