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.

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?

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];

Reply via email to