https://sourceware.org/bugzilla/show_bug.cgi?id=28101
Bug ID: 28101
Summary: elf_strptr slow with address sanitizer, passes entire
section range to memrchr.
Product: elfutils
Version: unspecified
Status: UNCONFIRMED
Severity: enhancement
Priority: P2
Component: libelf
Assignee: unassigned at sourceware dot org
Reporter: jan.smets at nokia dot com
CC: elfutils-devel at sourceware dot org
Target Milestone: ---
This code block calls out to validate_str which calls to memrchr.
The to= is the size of the entire section.
I believe Address Sanitizer does validate the entire memory range.
Passing the entire range to the memrchr null char check makes it very costly.
191 else if (likely (strscn->data_list_rear == NULL))
192 {
193 // XXX The above is currently correct since elf_newdata will
194 // make sure to convert the rawdata into the datalist if
195 // necessary. But it would be more efficient to keep the rawdata
196 // unconverted and only then iterate over the rest of the (newly
197 // added data) list. Note that when the ELF file is mmapped
198 // rawdata_base can be set while rawdata.d hasn't been
199 // initialized yet (when data_read is zero). So we cannot just
200 // look at the rawdata.d.d_size.
201
202 /* Make sure the string is NUL terminated. Start from the end,
203 which very likely is a NUL char. */
204 if (likely (validate_str (strscn->rawdata_base, offset, sh_size)))
205 result = &strscn->rawdata_base[offset];
206 else
207 __libelf_seterrno (ELF_E_INVALID_INDEX);
208 }
* libelf compiled with HAVE_DECL_MEMRCHR (default)
* recent GCC toolchain (GCC6 and up)
* files themselves don't even need to be compiled with asan, just enabling it
at link time so the runtime wrapping/intercepting of libc et all fires.
Testcase:
test.c is attached.
Generate a source file with dummy symbols to populate the symbol table.
for i in {A..Z}{A..Z}{A..Z}{A..Z}; do echo "int sym$i;"; done > symbols.c
gcc -c symbols.c -o symbols.o
gcc -c test.c -o test.o -I /tmp/jan-test/elfutils/libelf/ #-fsanitize=address
gcc test.o symbols.o -o test -l:libelf.a -L/tmp/jan-test/elfutils/libelf/ -lz
-fsanitize=address
echo -n "default asan:"
time ./test test
echo -n "asan disabled"
gcc test.o symbols.o -o test -l:libelf.a -L/tmp/jan-test/elfutils/libelf/ -lz
time ./test test
I don't know of any ASAN_OPTIONS parameter that would change this behavior and
make it less strict.
On my machine the asan testcase takes 5+ sec, whereas the non-asan 0.04s.
Can this code please be optimized to reduce the range passed to memrchr?
Is this NUL check even required?
--
You are receiving this mail because:
You are on the CC list for the bug.