From 29feb44e05cd2dbdc0724753102574bf4ce12c3f Mon Sep 17 00:00:00 2001 From: Scott Garman Date: Wed, 4 Jan 2012 22:30:35 -0800 Subject: insane.bbclass: add QA tests for unsafe references to exec_prefix 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] (From OE-Core rev: 3e9c368a8045044736fc7e348404060498c7491b) Signed-off-by: Scott Garman Signed-off-by: Richard Purdie --- meta/classes/insane.bbclass | 111 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 2 deletions(-) (limited to 'meta/classes/insane.bbclass') diff --git a/meta/classes/insane.bbclass b/meta/classes/insane.bbclass index 5726e69e71..b8d45073ef 100644 --- a/meta/classes/insane.bbclass +++ b/meta/classes/insane.bbclass @@ -11,6 +11,10 @@ # -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 # @@ -19,9 +23,14 @@ # 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): """ -- cgit v1.2.3-54-g00ecf