kiss-community / kiss

KISS - Package Manager, mirror of https://codeberg.org/kiss-community/kiss
https://kisslinux.org/package-manager
MIT License
20 stars 11 forks source link

KISS doesn't respect RPATH/RUNPATH #64

Closed git-bruh closed 2 years ago

git-bruh commented 2 years ago

Description

KISS doesn't check the RPATH/RUNPATH of executables which leads it to falsely add some packages as dependencies. Eg, if nss is installed in /usr/lib and firefox is installed in /usr/lib/firefox with bundled nss/nspr, kiss will add a dependency on nss for firefox

Error message

/home/build/kiss/reproducer/zlib-bundle $ kiss b
-> Building: explicit: zlib-bundle 
-> Checking for pre-built dependencies 
-> zlib-bundle Reading sources
-> zlib-bundle Verifying sources
-> zlib-bundle Building package (1/1)
-> zlib-bundle Extracting sources
-> zlib-bundle Starting build
-> zlib-bundle Successfully built package
-> zlib-bundle Generating manifest
-> zlib-bundle Stripping binaries and libraries
strip -s -R .comment -R .note /tmp/817/pkg/zlib-bundle/usr/lib/ineedzlib/libz.so.1.2.12
strip -s -R .comment -R .note /tmp/817/pkg/zlib-bundle/usr/lib/ineedzlib/ineedzlib.so
strip -s -R .comment -R .note /tmp/817/pkg/zlib-bundle/usr/lib/ineedzlib/ineedzlib
-> zlib-bundle looking for dependencies (using readelf)
--- /tmp/817/tmp/zlib-bundle-depends
+++ /tmp/817/tmp/zlib-bundle-depends-fixed
@@ -0,0 +1 @@
+zlib
-> zlib-bundle Generating manifest
-> zlib-bundle Generating etcsums
-> zlib-bundle Creating tarball
-> zlib-bundle Successfully created tarball
-> Install built packages? [zlib-bundle] 
-> Continue?: Press Enter to continue or Ctrl+C to abort 

Package

#!/bin/sh -e

mkdir -p "$1/usr/lib/ineedzlib"

cd "$1/usr/lib/ineedzlib"

$CC -shared -o libz.so.1.2.12 -fPIC -x c - <<EOF
void *gzopen(void) { return (void *) gzopen; }
EOF

ln -s libz.so.1.2.12 libz.so

$CC -shared -o ineedzlib.so libz.so -Wl,-rpath=/usr/lib/ineedzlib -x c - <<EOF
void call(void) { void *gzopen(void); gzopen(); }
EOF

$CC -o ineedzlib ineedzlib.so -Wl,-rpath=/usr/lib/ineedzlib -x c - <<EOF
int main(void) { void call(void); call(); }
EOF

The issue is similar to https://github.com/kiss-community/kiss/issues/20

See https://github.com/kiss-community/repo/pull/86#issuecomment-1234069350

CC @illiliti @ioraff @cemkeylan

cemkeylan commented 2 years ago

I thought we solved this issue when multilib support was added. Apparently not.

git-bruh commented 2 years ago

I thought we solved this issue when multilib support was added. Apparently not.

The exact commit didn't propagate to upstream KISS, it was fixed in a different way with dependency rework by dylan. Multilib still works fine tho

cemkeylan commented 2 years ago

Is there a way to actually determine the full path of a linked shared library?

git-bruh commented 2 years ago

Is there a way to actually determine the full path of a linked shared library?

Running ldd seems to give the correct paths, not sure what's going wrong in KISS code

cemkeylan commented 2 years ago

Okay, I see the issue now. The directory where you are building the package is not part of the rpath. So ldd fails to locate the shared library. When the library can't be located in the rpath it fallsback to the zlib installed on the system, that's how rpath works. Going to the package directory and adding it to the LD_LIBRARY_PATH seems to resolve it. However, I'm not sure how reliable this solution is.

git-bruh commented 2 years ago

Ahh, that explains the firefox bug aswell. /usr/lib/firefox is originally present with nss inside of it, and firefox's rpath is set to that dir regardless of build config, so kiss detects that nss instead of the one in /usr/lib

git-bruh commented 2 years ago

http://blog.tremily.us/posts/rpath/

The relevant linker flags are -rpath and --enable-new-dtags. Without --enable-new-dtags, you'll just set the RPATH flag, which is probably not what you want. With --enable-new-dtags, you'll set both RPAH and RUNPATH to the same value. From ld(1):

The DT_RPATH entries are ignored if DT_RUNPATH entries exist.

so setting both is the same as just setting RUNPATH (except for tools like chrpath which are only designed to handle a single tag). You can use readelf to see if the tags were set:

git-bruh commented 2 years ago

Should the fix account for such cases?

Dynamic section at offset 0x2de0 contains 26 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [./Library rpath: [asdfaffqfewffsd].so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000f (RPATH)              Library rpath: [/tmp/test]
 0x000000000000000c (INIT)               0x1000
 0x000000000000000d (FINI)               0x1134
 0x0000000000000019 (INIT_ARRAY)         0x3dd0

This part could probably benefit from being written in C

git-bruh commented 2 years ago
λ readelf -d /usr/bin/llvm-readelf 

Dynamic section at offset 0x1c7ca0 contains 32 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libLLVM-14.so]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000f (RPATH)              Library rpath: [$ORIGIN/../lib]

$ORIGIN needs to be handled too