On 14/04/21(Wed) 18:33, Klemens Nanni wrote:
> A bogus libvorbisenc.so.3.1 causes ld.so(1) to crash on my Pinebook Pro
> which saw a few NVMe/power related panics:
>
> $ ogg123 song62.ogg
> Segmentation fault (core dumped)
>
> $ egdb -q ogg123 ogg123.core
> Reading symbols from ogg123...(no debugging symbols found)...done.
> [New process 512916]
> Core was generated by `ogg123'.
> Program terminated with signal SIGSEGV, Segmentation fault.
> #0 0x0000000d388623e4 in _dl_find_symbol_obj (obj=0xcfae56000,
> sl=0x7ffffdd728) at /usr/src/libexec/ld.so/resolve.c:614
> 614 for (si = obj->buckets_elf[sl->sl_elf_hash %
> obj->nbuckets];
> (gdb) p obj->buckets_elf
> There is no member named buckets_elf.
>
> (`buckets_elf' is a macro)
>
> (gdb) p obj->hash_u.u_elf.buckets
> $1 = (const Elf_Hash_Word *) 0x0
> (gdb) p obj->nbuckets
> $2 = 0
>
> Backtrace for completeness:
>
> (gdb) bt
> #0 0x0000000d388623e4 in _dl_find_symbol_obj (obj=0xcfae56000,
> sl=0x7ffffdd728) at /usr/src/libexec/ld.so/resolve.c:614
> #1 0x0000000d38862210 in _dl_find_symbol (name=0xd9e9e6919
> "malloc_options", flags=16, ref_sym=0xd9e9d23f8, req_obj=0xcfae52000) at
> /usr/src/libexec/ld.so/resolve.c:704
> #2 0x0000000d388603b8 in _dl_md_reloc (object=<optimized out>,
> rel=<optimized out>, relsz=<optimized out>) at
> /usr/src/libexec/ld.so/aarch64/rtld_machine.c:170
> #3 0x0000000d38864714 in _dl_rtld (object=0xcfae52000) at
> /usr/src/libexec/ld.so/loader.c:722
> #4 0x0000000d388646dc in _dl_rtld (object=0xcfae52400) at
> /usr/src/libexec/ld.so/loader.c:712
> #5 0x0000000d388646dc in _dl_rtld (object=0xd6d641400) at
> /usr/src/libexec/ld.so/loader.c:712
> #6 0x0000000d388646dc in _dl_rtld (object=0xcfae52800) at
> /usr/src/libexec/ld.so/loader.c:712
> #7 0x0000000d388646dc in _dl_rtld (object=0xcfae53c00) at
> /usr/src/libexec/ld.so/loader.c:712
> #8 0x0000000d388646dc in _dl_rtld (object=0xcfae56800) at
> /usr/src/libexec/ld.so/loader.c:712
> #9 0x0000000d388646dc in _dl_rtld (object=0xcfae56400) at
> /usr/src/libexec/ld.so/loader.c:712
> #10 0x0000000d388646dc in _dl_rtld (object=0xcfae56c00) at
> /usr/src/libexec/ld.so/loader.c:712
> #11 0x0000000d388646dc in _dl_rtld (object=0xd0b867400) at
> /usr/src/libexec/ld.so/loader.c:712
> #12 0x0000000d388646dc in _dl_rtld (object=0xd6d63f400) at
> /usr/src/libexec/ld.so/loader.c:712
> #13 0x0000000d388646dc in _dl_rtld (object=0xcfae53400) at
> /usr/src/libexec/ld.so/loader.c:712
> #14 0x0000000d388646dc in _dl_rtld (object=0xd6d63f800) at
> /usr/src/libexec/ld.so/loader.c:712
> #15 0x0000000d388646dc in _dl_rtld (object=0xcfae52c00) at
> /usr/src/libexec/ld.so/loader.c:712
> #16 0x0000000d388646dc in _dl_rtld (object=0xcfae53000) at
> /usr/src/libexec/ld.so/loader.c:712
> #17 0x0000000d388646dc in _dl_rtld (object=0xd0b867c00) at
> /usr/src/libexec/ld.so/loader.c:712
> #18 0x0000000d388646dc in _dl_rtld (object=0xd6d640000) at
> /usr/src/libexec/ld.so/loader.c:712
> #19 0x0000000d388646dc in _dl_rtld (object=0xd6d640c00) at
> /usr/src/libexec/ld.so/loader.c:712
> #20 0x0000000d388646dc in _dl_rtld (object=0xd0b867000) at
> /usr/src/libexec/ld.so/loader.c:712
> #21 0x0000000d388646dc in _dl_rtld (object=0xcfae56000) at
> /usr/src/libexec/ld.so/loader.c:712
> #22 0x0000000d388646dc in _dl_rtld (object=0xd0b867800) at
> /usr/src/libexec/ld.so/loader.c:712
> #23 0x0000000d3886b618 in _dl_boot (argv=<optimized out>,
> envp=<optimized out>, dyn_loff=56782815232, dl_data=0x7ffffddde4) at
> /usr/src/libexec/ld.so/loader.c:663
> #24 0x0000000d3886a044 in _dl_start () at
> /usr/src/libexec/ld.so/aarch64/ldasm.S:59
> Backtrace stopped: previous frame identical to this frame (corrupt
> stack?)
>
>
> libvorbis being the culprit wasn't clear at all, but I went through
> pkg_check(1) to see checksum mismatches in the "libvorbis" package.
>
> tl;dr: I Upgraded to the latest snapshot, saved the currupted libraries,
> deinstalled all packages with `pkg_delete -X', installed "vorbis-tools"
> for ogg123(1) (pulling in "libvorbis") and the song played fine using
> valid files.
>
> Forcing the corrupted library I can reproduce, though:
>
> $ LD_PRELOAD=./libvorbisenc.so.3.1 ogg123 song62.ogg
> Segmentation fault (core dumped)
>
> So that's really this shared object and not any other currupted files.
>
> I'm not familiar with ld.so internals but the NULL dereference seems
> easy to avoid based on the condition that is used to set the `buckets'
> member in resolve.c:408f:
>
> if (object->Dyn.info[DT_HASH] != 0) {
> Elf_Hash_Word *hashtab =
> (Elf_Hash_Word *)(object->Dyn.info[DT_HASH] + obase);
>
> object->nchains = hashtab[1];
> if (object->nbuckets == 0) {
> object->nbuckets = hashtab[0];
> object->buckets_elf = hashtab + 2;
> object->chains_elf = object->buckets_elf +
> object->nbuckets;
> }
> }
>
> Hence, only access buckets in _dl_find_symbol_obj() if there are any;
> this fixes the crash and in fact allows me to play the song even when
> preloading the currupted library, i.e.
>
> $ LD_PRELOAD=./libvorbisenc.so.3.1 ogg123 song62.ogg
>
> now also works with patched ld.so installed -- I'd expected ld.so,
> libvorbis or ogg123 to crash on some other place...
>
> I'm not sure what to make of this, I also don't know enough about ld.so
> to judge this diff in context, it does however fix an obvious error.
> FWIW, regress/libexec/ld.so runs fine with this diff.
I'm not sure if silently ignoring the corruption is the best way to go.
Do you know why `nbuckets' and `buckets_elf' aren't initialized for this
object? Do you know if _dl_finalize_object() has been call for it?
> Is this a code path that can happen with intact objects?
> Given that the file is obviously corrupted but programs using it still
> (partially) work, should a warning be printed in this case?
Indicating that the library is corrupted might indeed be better than
crashing. However it isn't clear to me where such check should happen.
> Feedback?
>
> PS: I can upload/mail the corrupted library if someone wants to poke it.
>
> Index: resolve.c
> ===================================================================
> RCS file: /cvs/src/libexec/ld.so/resolve.c,v
> retrieving revision 1.94
> diff -u -p -r1.94 resolve.c
> --- resolve.c 4 Oct 2019 17:42:16 -0000 1.94
> +++ resolve.c 14 Apr 2021 15:56:14 -0000
> @@ -608,7 +608,7 @@ _dl_find_symbol_obj(elf_object_t *obj, s
> return r > 0;
> }
> } while ((*hashval++ & 1U) == 0);
> - } else {
> + } else if (obj->nbuckets > 0) {
> Elf_Word si;
>
> for (si = obj->buckets_elf[sl->sl_elf_hash % obj->nbuckets];
>