]> code.ossystems Code Review - openembedded-core.git/commitdiff
insane.bbclass: add QA tests for unsafe references to exec_prefix
authorScott Garman <scott.a.garman@intel.com>
Thu, 5 Jan 2012 06:30:35 +0000 (22:30 -0800)
committerRichard Purdie <richard.purdie@linuxfoundation.org>
Thu, 5 Jan 2012 11:18:18 +0000 (11:18 +0000)
Files under exec_prefix (commonly /usr) may not be available during
system recovery. exec_prefix may also be kept on a separate partition
that is mounted late in the boot process.

This QA test throws an warning if a binary in base_[bindir|sbindir|libdir]
is dynamically linked to a file under exec_prefix. The intention is to
turn this into an error in the near future.

It also checks executable non-binaries (e.g, shell scripts) in the above
base directories with a simple grep test to look for references to
exec_prefix. This test only produces a warning, since false positives
are likely.

This fixes [YOCTO #1008]

Signed-off-by: Scott Garman <scott.a.garman@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
meta/classes/insane.bbclass

index 5726e69e71ab6cdb4f5b4757b49522f412612c27..b8d45073ef272656c05da7e67c453df9a2457856 100644 (file)
 #  -Check if packages contains .debug directories or .so files
 #   where they should be in -dev or -dbg
 #  -Check if config.log contains traces to broken autoconf tests
+#  -Ensure that binaries in base_[bindir|sbindir|libdir] do not link
+#   into exec_prefix
+#  -Check that scripts in base_[bindir|sbindir|libdir] do not reference
+#   files under exec_prefix
 
 
 #
 # The package.bbclass can help us here.
 #
 inherit package
-PACKAGE_DEPENDS += "pax-utils-native desktop-file-utils-native"
+PACKAGE_DEPENDS += "pax-utils-native desktop-file-utils-native ${QADEPENDS}"
 PACKAGEFUNCS += " do_package_qa "
 
+# unsafe-references-in-binaries requires prelink-rtld from
+# prelink-native, but we don't want this DEPENDS for -native builds
+QADEPENDS = "prelink-native"
+QADEPENDS_virtclass-native = ""
+QADEPENDS_virtclass-nativesdk = ""
 
 #
 # dictionary for elf headers
@@ -100,7 +109,7 @@ def package_qa_get_machine_dict():
 
 
 # Currently not being used by default "desktop"
-WARN_QA ?= "ldflags useless-rpaths rpaths"
+WARN_QA ?= "ldflags useless-rpaths rpaths unsafe-references-in-binaries unsafe-references-in-scripts"
 ERROR_QA ?= "dev-so debug-deps dev-deps debug-files arch la2 pkgconfig la perms"
 
 def package_qa_clean_path(path,d):
@@ -201,6 +210,104 @@ def package_qa_check_perm(path,name,d, elf, messages):
     """
     return
 
+QAPATHTEST[unsafe-references-in-binaries] = "package_qa_check_unsafe_references_in_binaries"
+def package_qa_check_unsafe_references_in_binaries(path, name, d, elf, messages):
+       """
+       Ensure binaries in base_[bindir|sbindir|libdir] do not link to files under exec_prefix
+       """
+       if unsafe_references_skippable(path, name, d):
+               return
+
+       if elf:
+               import subprocess as sub
+               pn = d.getVar('PN', True)
+
+               exec_prefix = d.getVar('exec_prefix', True)
+               sysroot_path = d.getVar('STAGING_DIR_TARGET', True)
+               sysroot_path_usr = sysroot_path + exec_prefix
+
+               try:
+                       ldd_output = sub.check_output(["prelink-rtld", "--root", sysroot_path, path])
+               except sub.CalledProcessError as e:
+                       if e.returncode != 127:
+                               error_msg = pn + ": prelink-rtld aborted when processing %s" % path
+                               package_qa_handle_error("unsafe-references-in-binaries", error_msg, d)
+                               return False
+                       else:
+                               # Sometimes this is done deliberately (e.g, e2fsprogs), so only warn
+                               bb.warn("%s has missing library dependencies" % path)
+                               return
+               if sysroot_path_usr in ldd_output:
+                       error_msg = pn + ": %s links to something under exec_prefix" % path
+                       package_qa_handle_error("unsafe-references-in-binaries", error_msg, d)
+                       error_msg = "ldd reports: %s" % ldd_output
+                       package_qa_handle_error("unsafe-references-in-binaries", error_msg, d)
+                       return False
+
+QAPATHTEST[unsafe-references-in-scripts] = "package_qa_check_unsafe_references_in_scripts"
+def package_qa_check_unsafe_references_in_scripts(path, name, d, elf, messages):
+       """
+       Warn if scripts in base_[bindir|sbindir|libdir] reference files under exec_prefix
+       """
+       if unsafe_references_skippable(path, name, d):
+               return
+
+       if not elf:
+               import stat
+               pn = d.getVar('PN', True)
+
+               # Ensure we're checking an executable script
+               statinfo = os.stat(path)
+               if bool(statinfo.st_mode & stat.S_IXUSR):
+                       # grep shell scripts for possible references to /exec_prefix/
+                       exec_prefix = d.getVar('exec_prefix', True)
+                       statement = "grep -e '%s/' %s > /dev/null" % (exec_prefix, path)
+                       if os.system(statement) == 0:
+                               error_msg = pn + ": Found a reference to %s/ in %s" % (exec_prefix, path)
+                               package_qa_handle_error("unsafe-references-in-scripts", error_msg, d)
+                               error_msg = "Shell scripts in base_bindir and base_sbindir should not reference anything in exec_prefix"
+                               package_qa_handle_error("unsafe-references-in-scripts", error_msg, d)
+
+def unsafe_references_skippable(path, name, d):
+       if bb.data.inherits_class('native', d) or bb.data.inherits_class('nativesdk', d):
+               return True
+
+       if "-dbg" in name or "-dev" in name:
+               return True
+
+       # Other package names to skip:
+       if name.startswith("kernel-module-"):
+               return True
+
+       # Skip symlinks
+       if os.path.islink(path):
+               return True
+
+       # Skip unusual rootfs layouts which make these tests irrelevant
+       exec_prefix = d.getVar('exec_prefix', True)
+       if exec_prefix == "":
+               return True
+
+       pkgdest = d.getVar('PKGDEST', True)
+       pkgdest = pkgdest + "/" + name
+       pkgdest = os.path.abspath(pkgdest)
+       base_bindir = pkgdest + d.getVar('base_bindir', True)
+       base_sbindir = pkgdest + d.getVar('base_sbindir', True)
+       base_libdir = pkgdest + d.getVar('base_libdir', True)
+       bindir = pkgdest + d.getVar('bindir', True)
+       sbindir = pkgdest + d.getVar('sbindir', True)
+       libdir = pkgdest + d.getVar('libdir', True)
+
+       if base_bindir == bindir and base_sbindir == sbindir and base_libdir == libdir:
+               return True
+
+       # Skip files not in base_[bindir|sbindir|libdir]
+       path = os.path.abspath(path)
+       if not (base_bindir in path or base_sbindir in path or base_libdir in path):
+               return True
+
+       return False
+
 QAPATHTEST[arch] = "package_qa_check_arch"
 def package_qa_check_arch(path,name,d, elf, messages):
     """