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.

Reply via email to