Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

elf: expand $ORIGIN in RUNPATH/RPATH entries #17149

Merged
merged 1 commit into from Apr 27, 2024

Conversation

alebcay
Copy link
Member

@alebcay alebcay commented Apr 25, 2024

  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same change?
  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes? Here's an example.
  • Have you successfully run brew style with your changes locally?
  • Have you successfully run brew typecheck with your changes locally?
  • Have you successfully run brew tests with your changes locally?

Follow-up to #17136. It's possible for RPATH or RUNPATH to have entries that contain $ORIGIN, which expands to the directory where the ELF object is located.

We need to expand $ORIGIN and search for dependencies in paths containing $ORIGIN, too.

@alebcay alebcay changed the title elf: expand in RUNPATH/RPATH entries elf: expand $ORIGIN in RUNPATH/RPATH entries Apr 25, 2024
Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me so far! Will request a few more reviews here.

Comment on lines 152 to 154
local_paths = (path.patchelf_patcher.runpath || path.patchelf_patcher.rpath)&.split(":")&.map do |rp|
# Expand instances of $ORIGIN in the R(UN)PATH
rp.gsub "$ORIGIN", path.parent
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
local_paths = (path.patchelf_patcher.runpath || path.patchelf_patcher.rpath)&.split(":")&.map do |rp|
# Expand instances of $ORIGIN in the R(UN)PATH
rp.gsub "$ORIGIN", path.parent
local_paths = (path.patchelf_patcher.runpath || path.patchelf_patcher.rpath)&.split(":")&.map do |runpath|
runpath.gsub "$ORIGIN", path.parent

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could move this #gsub call into the local_paths&.each block below, I think.

Also: I'm not sure if we want #gsub, since $ORIGIN is only replaced by the dynamic linker if it is the prefix of the path, IIUC.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if we want #gsub, since $ORIGIN is only replaced by the dynamic linker if it is the prefix of the path, IIUC.

$ORIGIN gets substituted even if it's not the prefix; check this. Or TL;DR: a quick example:

linuxbrew@9c46a48f740f:~/.linuxbrew/opt/python/bin$ patchelf --print-rpath python3.12
/home/linuxbrew/.linuxbrew/Cellar/[email protected]/3.12.3/lib
linuxbrew@9c46a48f740f:~/.linuxbrew/opt/python/bin$ ldd python3.12
	linux-vdso.so.1 (0x00007fff28bb6000)
	libpython3.12.so.1.0 => /home/linuxbrew/.linuxbrew/Cellar/[email protected]/3.12.3/lib/libpython3.12.so.1.0 (0x00007b09b6838000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007b09b660c000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007b09b6523000)
	/home/linuxbrew/.linuxbrew/lib/ld.so => /lib64/ld-linux-x86-64.so.2 (0x00007b09b6eb9000)
linuxbrew@9c46a48f740f:~/.linuxbrew/opt/python/bin$ patchelf --set-rpath '$ORIGIN/../lib' python3.12
linuxbrew@9c46a48f740f:~/.linuxbrew/opt/python/bin$ ldd python3.12
	linux-vdso.so.1 (0x00007ffcba9d2000)
	libpython3.12.so.1.0 => /home/linuxbrew/.linuxbrew/Cellar/[email protected]/3.12.3/bin/./../lib/libpython3.12.so.1.0 (0x0000701941109000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x0000701940edd000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x0000701940df4000)
	/home/linuxbrew/.linuxbrew/lib/ld.so => /lib64/ld-linux-x86-64.so.2 (0x000070194178a000)
linuxbrew@9c46a48f740f:~/.linuxbrew/opt/python/bin$ patchelf --set-rpath '/usr/bin/../../$ORIGIN/../lib' python3.12
linuxbrew@9c46a48f740f:~/.linuxbrew/opt/python/bin$ ldd python3.12
	linux-vdso.so.1 (0x00007ffc6119c000)
	libpython3.12.so.1.0 => /usr/bin/../..//home/linuxbrew/.linuxbrew/Cellar/[email protected]/3.12.3/bin/./../lib/libpython3.12.so.1.0 (0x00007cd2a2506000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007cd2a22da000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007cd2a21f1000)
	/home/linuxbrew/.linuxbrew/lib/ld.so => /lib64/ld-linux-x86-64.so.2 (0x00007cd2a2b8a000)

Also, as can be seen in the path expansion logic, two more such tokens exist: $PLATFORM and $LIB. See https://www.akkadia.org/drepper/dsohowto.pdf, page 40, paragraph "$ORIGIN is not the only DST available...". Though, I think they are less commonly seen and can be followed up later.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved the expansion into the local_paths&.each block that follows, and replaced #gsub with just #sub (and only matches $ORIGIN from beginning of string for each path in the list).

Copy link
Member Author

@alebcay alebcay Apr 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, oops. Will switch it back to a gsub for anywhere in the string (looks like multiple occurrences of $ORIGIN are also accepted - can't imagine in what scenario such a case would occur, but not really harder for us to handle).

linuxbrew@ac7f2339ac92:~/.linuxbrew/opt/python/bin$ patchelf --set-rpath '$ORIGIN/../../../../../../..$ORIGIN/../lib' python3.12
linuxbrew@ac7f2339ac92:~/.linuxbrew/opt/python/bin$ ldd python3.12
	libpython3.12.so.1.0 => /home/linuxbrew/.linuxbrew/Cellar/[email protected]/3.12.3/bin/./../../../../../../../home/linuxbrew/.linuxbrew/Cellar/[email protected]/3.12.3/bin/./../lib/libpython3.12.so.1.0 (0x0000004002849000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x0000004002ec4000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00000040030ef000)
	/home/linuxbrew/.linuxbrew/lib/ld.so => /lib64/ld-linux-x86-64.so.2 (0x0000004000000000)
linuxbrew@ac7f2339ac92:~/.linuxbrew/opt/python/bin$ file /home/linuxbrew/.linuxbrew/Cellar/[email protected]/3.12.3/bin/./../../../../../../../home/linuxbrew/.linuxbrew/Cellar/[email protected]/3.12.3/bin/./../lib/libpython3.12.so.1.0
/home/linuxbrew/.linuxbrew/Cellar/[email protected]/3.12.3/bin/./../../../../../../../home/linuxbrew/.linuxbrew/Cellar/[email protected]/3.12.3/bin/./../lib/libpython3.12.so.1.0: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=34400f728c92b58b1adf2df38f5c3693b3bdc38c, not stripped

Copy link
Member

@ZhongRuoyu ZhongRuoyu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@Bo98
Copy link
Member

Bo98 commented Apr 25, 2024

I think technically ${ORIGIN} can happen, and strings like $ORIGINa are not substituted (must not be followed by [A-Za-z0-9_], unless in curly quotes).

glibc algorithm is here: https://github.com/bminor/glibc/blob/41903cb6f460d62ba6dd2f4883116e2a624ee6f8/elf/dl-load.c#L182-L228

@alebcay alebcay force-pushed the elf-expand-origin branch 2 times, most recently from 45f7b1e to 8c979cc Compare April 25, 2024 19:15
@alebcay
Copy link
Member Author

alebcay commented Apr 25, 2024

Moved the logic out into a separate function (and module) to make testing it easier, especially with the corner cases that have been noted so far.

Copy link
Member

@ZhongRuoyu ZhongRuoyu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

@carlocab carlocab merged commit 5e027bf into Homebrew:master Apr 27, 2024
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants