> Date: Thu, 15 Apr 2021 14:20:00 +0200
> From: Martin Pieuchot <m...@openbsd.org>
> Content-Type: text/plain; charset=utf-8
> Content-Disposition: inline
> 
> 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.

It certainly isn't.  If corruption is detected, the prcess should
terminate immedtaley.
 
> 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];
> > 
> 
> 

Reply via email to