def process_elf_dependencies(action, pkg_vars, dyn_tok_conv, kernel_paths, **kwargs): """Produce the elf dependencies for the file delivered in the action provided. 'action' is the file action to analyze. 'pkg_vars' is the list of variants against which the package delivering the action was published. 'dyn_tok_conv' is the dictionary which maps the dynamic tokens, like $PLATFORM, to the values they should be expanded to. 'kernel_paths' contains the run paths which kernel modules should use. """ if not action.name == "file": return [], [], {} installed_path = action.attrs[action.key_attr] proto_file = action.attrs[PD_LOCAL_PATH] if not os.path.exists(proto_file): raise base.MissingFile(proto_file) if not elf.is_elf_object(proto_file): return [], [], {} try: ei = elf.get_info(proto_file) ed = elf.get_dynamic(proto_file) except elf.ElfError, e: raise BadElfFile(proto_file, e)
def test_non_elf(self): """Test that elf routines gracefully handle non-elf objects.""" p = "this-is-not-an-elf-file.so" self.make_misc_files({p: "this is only a test"}) os.chdir(self.test_root) self.assertEqual(elf.is_elf_object(p), False) self.assertRaises(elf.ElfError, elf.get_dynamic, p) self.assertRaises(elf.ElfError, elf.get_info, p)
def test_valid_elf(self): """Test that elf routines work on a small set of objects.""" arch = pkg.portable.get_isainfo()[0] for p in self.elf_paths: p = re.sub("__ARCH__", arch, p) self.debug("testing elf file {0}".format(p)) self.assertTrue(os.path.exists(p), "{0} does not exist".format(p)) self.assertEqual(elf.is_elf_object(p), True) elf.get_dynamic(p) elf.get_info(p)
def test_valid_elf(self): """Test that elf routines work on a small set of objects.""" arch = pkg.portable.get_isainfo()[0] for p in self.elf_paths: p = re.sub("__ARCH__", arch, p) self.debug("testing elf file %s" % p) self.assert_(os.path.exists(p)) self.assertEqual(elf.is_elf_object(p), True) elf.get_dynamic(p) elf.get_info(p)
def file_action(self, action, manifest, engine, pkglint_id="001"): """Checks for existence in the proto area.""" if action.name not in ["file"]: return path = action.hash if path == None or path == 'NOHASH': path = action.attrs["path"] # check for writable files without a preserve attribute if "mode" in action.attrs: mode = action.attrs["mode"] if (int(mode, 8) & 0222) != 0 and "preserve" not in action.attrs: engine.error( _("%(path)s is writable (%(mode)s), but missing a preserve" " attribute") % {"path": path, "mode": mode}, msgid="%s%s.0" % (self.name, pkglint_id)) elif "preserve" in action.attrs: if "mode" in action.attrs: mode = action.attrs["mode"] if (int(mode, 8) & 0222) == 0: engine.error( _("%(path)s has a preserve action, but is not writable (%(mode)s)") % {"path": path, "mode": mode}, msgid="%s%s.4" % (self.name, pkglint_id)) else: engine.error( _("%(path)s has a preserve action, but no mode") % {"path": path, "mode": mode}, msgid="%s%s.3" % (self.name, pkglint_id)) # checks that require a physical file to look at if self.proto_path is not None: for directory in self.proto_path: fullpath = directory + "/" + path if os.path.exists(fullpath): break if not os.path.exists(fullpath): engine.info( _("%s missing from proto area, skipping" " content checks") % path, msgid="%s%s.1" % (self.name, pkglint_id)) elif elf.is_elf_object(fullpath): # 32/64 bit in wrong place result = self.__elf_wrong_location_check(fullpath) if result != None: engine.error(result % path, msgid="%s%s.2" % (self.name, pkglint_id)) result = self.__elf_runpath_check(fullpath, engine) if result != None: engine.error(result % path, msgid="%s%s.3" % (self.name, pkglint_id)) result = self.__elf_aslr_check(fullpath, engine)
def file_action(self, action, manifest, engine, pkglint_id="001"): """Checks for existence in the proto area.""" if action.name not in ["file"]: return path = action.hash if path == None or path == 'NOHASH': path = action.attrs["path"] # check for writable files without a preserve attribute if "mode" in action.attrs: mode = action.attrs["mode"] if (int(mode, 8) & 0222) != 0 and "preserve" not in action.attrs: engine.error( _("%(path)s is writable (%(mode)s), but missing a preserve" " attribute") % {"path": path, "mode": mode}, msgid="%s%s.0" % (self.name, pkglint_id)) elif "preserve" in action.attrs: if "mode" in action.attrs: mode = action.attrs["mode"] if (int(mode, 8) & 0222) == 0: engine.error( _("%(path)s has a preserve action, but is not writable (%(mode)s)") % {"path": path, "mode": mode}, msgid="%s%s.4" % (self.name, pkglint_id)) else: engine.error( _("%(path)s has a preserve action, but no mode") % {"path": path, "mode": mode}, msgid="%s%s.3" % (self.name, pkglint_id)) # checks that require a physical file to look at if self.proto_path is not None: for directory in self.proto_path: fullpath = directory + "/" + path if os.path.exists(fullpath): break if not os.path.exists(fullpath): engine.info( _("%s missing from proto area, skipping" " content checks") % path, msgid="%s%s.1" % (self.name, pkglint_id)) elif elf.is_elf_object(fullpath): # 32/64 bit in wrong place result = self.__elf_wrong_location_check(fullpath) if result != None: engine.error(result % path, msgid="%s%s.2" % (self.name, pkglint_id)) result = self.__elf_runpath_check(fullpath, engine) if result != None: engine.error(result % path, msgid="%s%s.3" % (self.name, pkglint_id))
def file_action(self, action, manifest, engine, pkglint_id="001"): """Various file checks.""" if action.name not in ["file"]: return # path to the delivered file inspath = action.attrs["path"] # path to the file within the prototype area path = action.hash if path is None or path == "NOHASH": path = inspath # verify that preserve attribute is correctly used when # file is writable and not in other cases if "mode" in action.attrs: mode = action.attrs["mode"] writable = bool(int(mode, 8) & 0o222) if writable and "preserve" not in action.attrs: engine.error( f"{path} is writable ({mode}), but missing a preserve attribute", msgid=f"{self.name}{pkglint_id}.0") elif not writable and "preserve" in action.attrs: engine.error( f"{path} has a preserve action, but is not writable ({mode})", msgid=f"{self.name}{pkglint_id}.4") elif "preserve" in action.attrs: engine.error(f"{path} has a preserve action, but no mode", msgid=f"{self.name}{pkglint_id}.3") # checks that require a physical file to look at if self.proto_path is not None: for directory in self.proto_path: fullpath = directory + "/" + path if os.path.exists(fullpath): break if not os.path.exists(fullpath): engine.info( f"{path} missing from proto area, skipping content checks", msgid=f"{self.name}{pkglint_id}.1") elif elf.is_elf_object(fullpath): # 32/64 bit in wrong place self.__elf_location_check(fullpath, inspath, engine, pkglint_id) # verify that correct RUNPATH is present self.__elf_runpath_check(fullpath, engine, pkglint_id) # verify that ASLR is enabled when appropriate self.__elf_aslr_check(fullpath, engine, pkglint_id)
def process_elf_dependencies(action, proto_dir, pkg_vars, **kwargs): """Given a file action and proto directory, produce the elf dependencies for that file.""" if not action.name == "file": return [] installed_path = action.attrs[action.key_attr] proto_file = os.path.join(proto_dir, installed_path) if not os.path.exists(proto_file): raise base.MissingFile(proto_file) if not elf.is_elf_object(proto_file): return [] try: ei = elf.get_info(proto_file) ed = elf.get_dynamic(proto_file) except elf.ElfError, e: raise BadElfFile(proto_file, e)
def process_elf_dependencies(action, pkg_vars, dyn_tok_conv, run_paths, **kwargs): """Produce the elf dependencies for the file delivered in the action provided. 'action' is the file action to analyze. 'pkg_vars' is the list of variants against which the package delivering the action was published. 'dyn_tok_conv' is the dictionary which maps the dynamic tokens, like $PLATFORM, to the values they should be expanded to. 'run_paths' contains the run paths which elf binaries should use. """ if not action.name == "file": return [], [], {} installed_path = action.attrs[action.key_attr] proto_file = action.attrs[PD_LOCAL_PATH] if not os.path.exists(proto_file): raise base.MissingFile(proto_file) if not elf.is_elf_object(proto_file): return [], [], {} try: ei = elf.get_info(proto_file) ed = elf.get_dynamic(proto_file) except elf.ElfError as e: raise BadElfFile(proto_file, e) deps = [ d[0] for d in ed.get("deps", []) ] rp = ed.get("runpath", "").split(":") if len(rp) == 1 and rp[0] == "": rp = [] dyn_tok_conv["$ORIGIN"] = [os.path.join("/", os.path.dirname(installed_path))] kernel64 = None # For kernel modules, default path resolution is /platform/<platform>, # /kernel, /usr/kernel. But how do we know what <platform> would be for # a given module? Does it do fallbacks to, say, sun4u? if installed_path.startswith("kernel") or \ installed_path.startswith("usr/kernel") or \ (installed_path.startswith("platform") and \ installed_path.split("/")[2] == "kernel"): if rp and (len(rp) > 1 or not re.match(r'^/usr/gcc/\d/lib$', rp[0])): raise RuntimeError("RUNPATH set for kernel module " "({0}): {1}".format(installed_path, rp)) # Add this platform to the search path. if installed_path.startswith("platform"): rp.append("/platform/{0}/kernel".format( installed_path.split("/")[1])) else: for p in dyn_tok_conv.get("$PLATFORM", []): rp.append("/platform/{0}/kernel".format(p)) # Default kernel search path rp.extend(["/kernel", "/usr/kernel"]) # What subdirectory should we look in for 64-bit kernel modules? if ei["bits"] == 64: if ei["arch"] == "i386": kernel64 = "amd64" elif ei["arch"] == "sparc": kernel64 = "sparcv9" else: raise RuntimeError("Unknown arch:{0}".format( ei["arch"])) else: for p in default_run_paths: if ei["bits"] == 64: p += "/64" if p not in rp: rp.append(p) elist = [] if run_paths: # add our detected runpaths into the user-supplied one (if any) rp = base.insert_default_runpath(rp, run_paths) rp, errs = expand_variables(rp, dyn_tok_conv) elist.extend([ UnsupportedDynamicToken(proto_file, installed_path, p, tok) for p, tok in errs ]) res = [] for d in deps: pn, fn = os.path.split(d) pathlist = [] for p in rp: if kernel64: # Find 64-bit modules the way krtld does. # XXX We don't resolve dependencies found in # /platform, since we don't know where under # /platform to look. deppath = \ os.path.join(p, pn, kernel64, fn).lstrip( os.path.sep) else: deppath = os.path.join(p, d).lstrip(os.path.sep) # deppath includes filename; remove that. head, tail = os.path.split(deppath) if head: pathlist.append(head) res.append(ElfDependency(action, fn, pathlist, pkg_vars, action.attrs[PD_PROTO_DIR])) del dyn_tok_conv["$ORIGIN"] return res, elist, {}