If an ELF file specifies a list of RPATHs, for each shared library dependency search each RPATH and see if the package contains it in that location. FS#43239 <https://bugs.archlinux.org/task/43239?string=namcap&project=1&type[0]=&sev[0]=&pri[0]=&due[0]=&reported[0]=&cat[0]=&status[0]=open&percent[0]=&opened=&dev=&closed=&duedatefrom=&duedateto=&changedfrom=&changedto=&openedfrom=&openedto=&closedfrom=&closedto=> Signed-off-by: Nicola Squartini <tensor5@gmail.com> --- Namcap/rules/sodepends.py | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/Namcap/rules/sodepends.py b/Namcap/rules/sodepends.py index 92826af..527f511 100644 --- a/Namcap/rules/sodepends.py +++ b/Namcap/rules/sodepends.py @@ -28,6 +28,7 @@ import subprocess import tempfile import Namcap.package from Namcap.ruleclass import * +from Namcap.rules.rpath import get_rpaths libcache = {'i686': {}, 'x86-64': {}} @@ -43,7 +44,7 @@ def figurebitsize(line): else: return 'i686' -def scanlibs(fileobj, filename, sharedlibs): +def scanlibs(fileobj, filename, sharedlibs, tarlist): """ Run "readelf -d" on a file-like object (e.g. a TarFile) @@ -52,6 +53,7 @@ def scanlibs(fileobj, filename, sharedlibs): sharedlibs: a dictionary { library => set(ELF files using that library) } """ shared = re.compile('Shared library: \[(.*)\]') + origin = re.compile('^\$ORIGIN|^\$\{ORIGIN\}') # test magic bytes magic = fileobj.read(4) @@ -71,18 +73,31 @@ def scanlibs(fileobj, filename, sharedlibs): var = p.communicate() assert(p.returncode == 0) for j in var[0].decode('ascii').splitlines(): + found = False n = shared.search(j) # Is this a Shared library: line? if n != None: # Find out its architecture architecture = figurebitsize(j) - try: - libpath = os.path.abspath( - libcache[architecture][n.group(1)])[1:] - sharedlibs.setdefault(libpath, set()).add(filename) - except KeyError: - # We didn't know about the library, so add it for fail later - sharedlibs.setdefault(n.group(1), set()).add(filename) + # If file has RPATH, check if shared library is already packaged + for rpath in get_rpaths(tmp.name): + # Expand $ORIGIN + realrpath = origin.sub(os.path.dirname(filename), rpath) + libpath = os.path.normpath(os.path.join(realrpath, n.group(1))) + # Remove possible leading '/' + libpath = re.sub('^/', '', libpath) + if libpath in tarlist: + sharedlibs.setdefault(libpath, set()).add(filename) + found = True + break + if not found: + try: + libpath = os.path.abspath( + libcache[architecture][n.group(1)])[1:] + sharedlibs.setdefault(libpath, set()).add(filename) + except KeyError: + # We didn't know about the library, so add it for fail later + sharedlibs.setdefault(n.group(1), set()).add(filename) finally: os.unlink(tmp.name) @@ -157,7 +172,7 @@ class SharedLibsRule(TarballRule): if not entry.isfile(): continue f = tar.extractfile(entry) - scanlibs(f, entry.name, liblist) + scanlibs(f, entry.name, liblist, tar.getnames()) f.close() # Ldd all the files and find all the link and script dependencies -- 2.8.2