On Mon, Jun 06, 2022 at 03:01:34PM -0000, Frank R Dana Jr. wrote:
> Hi all.
> 
> I know we're all busy people, but I'm hoping I can impose on someone with the 
> necessary rights to take a look at this, as it's been in limbo for several 
> months now.
> 
> Basically, I discovered a fairly nasty bug in chrpath — a package for which 
> upstream has vanished, so we're pretty much on our own — which fortunately 
> only occurs under rare circumstances. "Fortunately" because, when those 
> circumstances arise and it DOES occur, using chrpath to set the RUNPATH for a 
> shared library can instead corrupt (silently!) the library's dynamic string 
> tables. While failing to actually modify the RUNPATH.
> 
> My bug report about the issue, with steps to reproduce, is here:
> https://bugzilla.redhat.com/show_bug.cgi?id=2022931
> 
> A few months after reporting, I revisited the problem, isolated the bug, and 
> fixed (at least in my testing) chrpath to no longer exhibit that buggy 
> behavior. I submitted the patch as a PR against our chrpath package repo, 
> since the upstream URL points to an unreachable host.
> 
> That PR can be found here:
> https://src.fedoraproject.org/rpms/chrpath/pull-request/6
> 
> It's been open for five weeks now. As I said, the conditions that trigger the 
> bug are fairly rare, so I wouldn't say it's URGENT per se. But it does feel 
> like it should be addressed, and I even have a patch that (I believe) does 
> so. Perhaps someone has a few minutes to look it over, verify that I haven't 
> done anything stupid, and help move the process along? (Or provide some 
> guidance on how I should go about doing so.)
> 
> Thanks!
> 
> 
> (Everything past this point is additional detail for the morbidly curious. 
> Bail out now if you don't want to end up getting bored to tears with very 
> tedious details, or don't say I didn't warn you.)
> 
> 
> Those fortunately-rare trigger conditions
> ---------------------------------------------------
> The library being modified by chrpath will only be corrupted if its .dynstr 
> section is located at an unexpected location in the ELF header. chrpath 
> blindly assumes that the first section of type SHT_STRTAB it encounters when 
> walking the headers must be the .dynstr table, into which the RUNPATH is to 
> be placed at the offset 'rpathoff'.  The assumption chrpath makes APPEARS to 
> be a correct one, 99% of the time. For all executables, and most if not all 
> "normal" libraries, the header is laid out as it assumes and it can update 
> RUNPATH strings without incident.
> 
> However, should that assumption turn out to be INCORRECT, chrpath will insert 
> a RUNPATH string into the **wrong** table. Whichever section of type 
> SHT_STRTAB it encounters first, that table gets the RUNPATH inserted into it. 
> When it's not the .dynstr table, some other symbol name gets partly or 
> completely overwritten with the new RUNPATH string. Meanwhile, the library's 
> *actual* RUNPATH doesn't change, since the real, correct location in the 
> .dynstr section still has the same value it did before running chrpath.
> 
> One of the ways a library with unexpected table ordering can be created is 
> the series of events that led me to initially discover the bug: Using a 
> different library-editing tool, patchelf, to insert a new RUNPATH into a 
> library that previously lacked one, then subsequently running chrpath on that 
> library.
> 
> (Adding a RUNPATH to a library is something patchelf can do that chrpath 
> cannot. chrpath is limited to overwriting existing RUNPATH strings with one 
> of the same length or shorter, using space that's already allocated in th 
> header. It has no ability to allocate additional space for a RUNPATH where 
> none previously existed. patchelf *can* carve out space for a RUNPATH string 
> in a library without one — it rewrites the ELF headers to allocate additional 
> space for the new string. In the process of doing so, it seems to relocate 
> (or create?) the dynamic string (.dynstr) table in a header section located 
> *after* the other, previously-allocated sections.)
> 
> So, when allocating new space to add a RUNPATH, patchelf places .dynstr 
> somewhere that chrpath assumes it will never be located. A patchelf-modified 
> shared library is effectively a trap waiting to be sprung by an unpatched 
> chrpath, which will make a mess of its string tables the moment it tries to 
> modify them.
> 
> 
> My proposed fix, as implemented in the submitted PR
> -------------------------------------------------------------------
> My patch is as simple as I could make it, and no simpler. It adds two 
> functions to chrpath:
> 
> read_section_names() retrieves the names for all of the sections from the 
> file's ELF header. The table contains the name for each section, located at 
> an offset that's stored in the .sh_name member of the section header struct.
> 
> get_section_name() takes a .sh_name value, and returns the corresponding 
> string located at that offset in the section names table.
> 
> Patched chrpath still walks the ELF headers to find the dynamic string table, 
> when it needs to write a new RUNPATH into a binary. But instead of stopping 
> at the first SHT_STRTAB section it finds and assuming that's the dynamic 
> string table, the loop now calls get_section_name(sh_name) and checks that 
> the string returned is exactly ".dynstr". If it's not, the loop continues on. 
> Only when both the section type AND name are a match, will it proceed to 
> write the new RUNPATH into the table.

Thanks for the detail and history here.  I played with this a bit locally and
did hit the same problem you have encountered.  What I don't understand is why
you can't use patchelf here instead of chrpath.  The only mention I found was
combining the use of chrpath and patchelf on an ELF object can lead to bad
things.  You mention modifications to the DT_RUNPATH and with the exception of
--delete-rpath, I think that patchelf only modifies DT_RPATH and not
DT_RUNPATH.  I did not verify this though.

I ask this because I used to use chrpath until upstream dried up and migrated
to using patchelf.  In my cases, I am fine with modifications to DT_RPATH.
You may have a different set of circumstances.  Since chrpath is no longer
active upstream, submitting a PR for patchelf may be the better long term way
to go.

-- 
David Cantrell <dcantr...@redhat.com>
Red Hat, Inc. | Boston, MA | EST5EDT
_______________________________________________
devel mailing list -- devel@lists.fedoraproject.org
To unsubscribe send an email to devel-le...@lists.fedoraproject.org
Fedora Code of Conduct: 
https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org
Do not reply to spam on the list, report it: 
https://pagure.io/fedora-infrastructure

Reply via email to