Exemple #1
0
 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)
Exemple #2
0
 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)
Exemple #3
0
	def __elf_wrong_location_check(self, path):
		result = None

		ei = elf.get_info(path)
		bits = ei.get("bits")
		type = ei.get("type");
                elems = os.path.dirname(path).split("/")

                if ("amd64" in elems) or ("sparcv9" in elems) or ("64" in elems):
                    path64 = True
                else:
                    path64 = False

                if ("i86" in elems) or ("sparcv7" in elems) or ("32" in elems):
                    path32 = True
                else:
                    path32 = False

		# ignore 64-bit executables in normal (non-32-bit-specific)
		# locations, that's ok now.
		if (type == "exe" and bits == 64 and path32 == False and path64 == False):
			return result

		if bits == 32 and path64:
			result = _("32-bit object '%s' in 64-bit path")
		elif bits == 64 and not path64:
			result = _("64-bit object '%s' in 32-bit path")
		return result
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)
Exemple #5
0
	def __elf_aslr_check(self, path, engine):
		result = None

		ei = elf.get_info(path)
		type = ei.get("type");
		if type != "exe":
			return result

		# get the ASLR tag string for this binary
		aslr_tag_process = subprocess.Popen(
			"/usr/bin/elfedit -r -e 'dyn:sunw_aslr' "
			+ path, shell=True,
			stdout=subprocess.PIPE, stderr=subprocess.PIPE)

		# aslr_tag_string will get stdout; err will get stderr
		aslr_tag_string, err = aslr_tag_process.communicate()

		# No ASLR tag was found; everthing must be tagged
		if aslr_tag_process.returncode != 0:
			engine.error(
				_("'%s' is not tagged for aslr") % (path),
				msgid="%s%s.5" % (self.name, "001"))
			return result

		# look for "ENABLE" anywhere in the string;
		# warn about binaries which are not ASLR enabled
		if re.search("ENABLE", aslr_tag_string) is not None:
			return result
		engine.warning(
			_("'%s' does not have aslr enabled") % (path),
			msgid="%s%s.6" % (self.name, "001"))
		return result
Exemple #6
0
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)
Exemple #7
0
    def __elf_aslr_check(self, path, engine):
        result = None

        ei = elf.get_info(path)
        type = ei.get("type")
        if type != "exe":
            return result

        # get the ASLR tag string for this binary
        aslr_tag_process = subprocess.Popen(
            "/usr/bin/elfedit -r -e 'dyn:sunw_aslr' " + path,
            shell=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE)

        # aslr_tag_string will get stdout; err will get stderr
        aslr_tag_string, err = aslr_tag_process.communicate()

        # No ASLR tag was found; everthing must be tagged
        if aslr_tag_process.returncode != 0:
            engine.error(_("'%s' is not tagged for aslr") % (path),
                         msgid="%s%s.5" % (self.name, "001"))
            return result

        # look for "ENABLE" anywhere in the string;
        # warn about binaries which are not ASLR enabled
        if re.search("ENABLE", aslr_tag_string) is not None:
            return result
        engine.warning(_("'%s' does not have aslr enabled") % (path),
                       msgid="%s%s.6" % (self.name, "001"))
        return result
Exemple #8
0
    def __elf_wrong_location_check(self, path, inspath):
        result = None

        ei = elf.get_info(path)
        bits = ei.get("bits")
        type = ei.get("type")
        elems = os.path.dirname(inspath).split("/")

        path32 = False
        path64 = False

        # Walk through the path elements backward and at the first
        # 32/64 bit specific element, flag it and break.
        for p in elems[::-1]:
            if (p in self.pathlist32):
                path32 = True
                break
            if (p in self.pathlist64):
                path64 = True
                break

        # ignore 64-bit executables in normal (non-32-bit-specific)
        # locations, that's ok now.
        if (type == "exe" and bits == 64 and path32 == False
                and path64 == False):
            return result

        if bits == 32 and path64:
            result = _("32-bit object '%%s' in 64-bit path(%s)" % elems)
        elif bits == 64 and not path64:
            result = _("64-bit object '%s' in 32-bit path")
        return result
Exemple #9
0
    def __elf_wrong_location_check(self, path):
        result = None

        ei = elf.get_info(path)
        bits = ei.get("bits")
        type = ei.get("type")
        elems = os.path.dirname(path).split("/")

        path64 = False
        for p in self.pathlist64:
            if (p in elems):
                path64 = True

        path32 = False
        for p in self.pathlist32:
            if (p in elems):
                path32 = True

        # ignore 64-bit executables in normal (non-32-bit-specific)
        # locations, that's ok now.
        if (type == "exe" and bits == 64 and path32 == False
                and path64 == False):
            return result

        if bits == 32 and path64:
            result = _("32-bit object '%s' in 64-bit path")
        elif bits == 64 and not path64:
            result = _("64-bit object '%s' in 32-bit path")
        return result
Exemple #10
0
    def __elf_runpath_check(self, path, engine):
        result = None
        list = []

        ed = elf.get_dynamic(path)
        ei = elf.get_info(path)
        bits = ei.get("bits")
        for dir in ed.get("runpath", "").split(":"):
            if dir == None or dir == '':
                continue

            match = False
            for expr in self.runpath_re:
                if expr.match(dir):
                    match = True
                    break

            # The RUNPATH shouldn't contain any runtime linker
            # default paths (or the /64 equivalent link)
            if dir in [
                    '/lib', '/lib/64', '/lib/amd64', '/lib/sparcv9',
                    '/usr/lib', '/usr/lib/64', '/usr/lib/amd64',
                    '/usr/lib/sparcv9'
            ]:
                list.append(dir)

            if match == False:
                list.append(dir)

            if bits == 32:
                for expr in self.runpath_64_re:
                    if expr.search(dir):
                        engine.warning(_(
                            "64-bit runpath in 32-bit binary, '%s' includes '%s'"
                        ) % (path, dir),
                                       msgid="%s%s.3" % (self.name, "001"))
            else:
                match = False
                for expr in self.runpath_64_re:
                    if expr.search(dir):
                        match = True
                        break
                if match == False:
                    engine.warning(
                        _("32-bit runpath in 64-bit binary, '%s' includes '%s'"
                          ) % (path, dir),
                        msgid="%s%s.3" % (self.name, "001"))
        if len(list) > 0:
            result = _("bad RUNPATH, '%%s' includes '%s'" % ":".join(list))

        return result
Exemple #11
0
	def __elf_wrong_location_check(self, path):
		result = None

		ei = elf.get_info(path)
		bits = ei.get("bits")
                elems = os.path.dirname(path).split("/")

                if ("amd64" in elems) or ("sparcv9" in elems) or ("64" in elems):
                    path64 = True
                else:
                    path64 = False

		if bits == 32 and path64:
			result = _("32-bit object '%s' in 64-bit path")
		elif bits == 64 and not path64:
			result = _("64-bit object '%s' in 32-bit path")
		return result
Exemple #12
0
    def __elf_runpath_check(self, path, engine):
        result = None
        list = []

        ed = elf.get_dynamic(path)
        ei = elf.get_info(path)
        bits = ei.get("bits")
        for dir in ed.get("runpath", "").split(":"):
            if dir == None or dir == '':
                continue

            match = False
            for expr in self.runpath_re:
                if expr.match(dir):
                    match = True
                    break

            if match == False:
                list.append(dir)

            if bits == 32:
                for expr in self.runpath_64_re:
                    if expr.search(dir):
                        engine.warning(_(
                            "64-bit runpath in 32-bit binary, '%s' includes '%s'"
                        ) % (path, dir),
                                       msgid="%s%s.3" % (self.name, "001"))
            else:
                match = False
                for expr in self.runpath_64_re:
                    if expr.search(dir):
                        match = True
                        break
                if match == False:
                    engine.warning(
                        _("32-bit runpath in 64-bit binary, '%s' includes '%s'"
                          ) % (path, dir),
                        msgid="%s%s.3" % (self.name, "001"))
        if len(list) > 0:
            result = _("bad RUNPATH, '%%s' includes '%s'" % ":".join(list))

        return result
Exemple #13
0
	def __elf_runpath_check(self, path, engine):
		result = None
		list = []

		ed = elf.get_dynamic(path)
		ei = elf.get_info(path)
		bits = ei.get("bits")
		for dir in ed.get("runpath", "").split(":"):
			if dir == None or dir == '':
				continue

			match = False
			for expr in self.runpath_re:
				if expr.match(dir):
					match = True
					break

			if match == False:
				list.append(dir)

			if bits == 32:
				for expr in self.runpath_64_re:
					if expr.search(dir):
						engine.warning(
							_("64-bit runpath in 32-bit binary, '%s' includes '%s'") % (path, dir),
							msgid="%s%s.3" % (self.name, "001"))
			else:
				match = False
				for expr in self.runpath_64_re:
					if expr.search(dir):
						match = True
						break
				if match == False:
					engine.warning(
						_("32-bit runpath in 64-bit binary, '%s' includes '%s'") % (path, dir),
						msgid="%s%s.3" % (self.name, "001"))
		if len(list) > 0:
			result = _("bad RUNPATH, '%%s' includes '%s'" %
				   ":".join(list))

		return result
Exemple #14
0
    def __elf_aslr_check(self, path, engine, _pkglint_id):
        """Verify that given executable binary is ASLR tagged and enabled."""
        elfinfo = elf.get_info(path)
        if elfinfo["type"] != "exe":
            return

        # get the ASLR tag string for this binary
        res = subprocess.run(
            ["/usr/bin/elfedit", "-r", "-e", "dyn:sunw_aslr", path],
            capture_output=True)

        # No ASLR tag was found; everything must be tagged
        if res.returncode != 0:
            engine.error(f"'{path}' is not tagged for aslr",
                         msgid=f"{self.name}{_pkglint_id}.5")

        # look for "ENABLE" anywhere in the string;
        # warn about binaries which are not ASLR enabled
        elif b"ENABLE" not in res.stdout:
            engine.warning(f"'{path}' does not have aslr enabled",
                           msgid=f"{self.name}{_pkglint_id}.6")
Exemple #15
0
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)
Exemple #16
0
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 __elf_wrong_location_check(self, path, inspath):
        result = None

        ei = elf.get_info(path)
        bits = ei.get("bits")
        type = ei.get("type")
        elems = os.path.dirname(inspath).split("/")

        path32 = False
        path64 = False

        # Walk through the path elements backward and at the first
        # 32/64 bit specific element, flag it and break.
        for p in elems[::-1]:
            if (p in self.pathlist32):
                path32 = True
                break
            if (p in self.pathlist64):
                path64 = True
                break

        # The Xorg module directory is a hybrid case - everything
        # but the dri subdirectory is 64-bit
        if (os.path.dirname(inspath).startswith("usr/lib/xorg/modules") and
                not os.path.dirname(inspath) == "usr/lib/xorg/modules/dri"):
            path64 = True

        # ignore 64-bit executables in normal (non-32-bit-specific)
        # locations, that's ok now.
        if (type == "exe" and bits == 64 and path32 == False
                and path64 == False):
            return result

        if bits == 32 and path64:
            result = _("32-bit object '%%s' in 64-bit path(%s)" % elems)
        elif bits == 64 and not path64:
            result = _("64-bit object '%s' in 32-bit path")
        return result
Exemple #18
0
    def __elf_location_check(self, path, inspath, engine, _pkglint_id):
        """Make sure that file is placed within correct 32/64 directory."""
        elfinfo = elf.get_info(path)
        bits = elfinfo["bits"]
        elftype = elfinfo["type"]
        elems = os.path.dirname(inspath).split("/")

        path32 = False
        path64 = False

        # Walk through the path elements backward and at the first
        # 32/64 bit specific element, flag it and break.
        for part in elems[::-1]:
            if part in self.pathlist32:
                path32 = True
                break
            if part in self.pathlist64:
                path64 = True
                break

        # The Xorg module directory is a hybrid case - everything
        # but the dri subdirectory is 64-bit
        dirname = os.path.dirname(inspath)
        if dirname.startswith("usr/lib/xorg/modules"
                              ) and dirname != "usr/lib/xorg/modules/dri":
            path64 = True

        # ignore 64-bit executables in normal (non-32-bit-specific)
        # locations, that's ok now.
        if elftype == "exe" and bits == 64 and not path32 and not path64:
            return

        if bits == 32 and path64:
            engine.error(f"32-bit object '{inspath}' in 64-bit path({elems})",
                         msgid=f"{self.name}{_pkglint_id}.2")
        elif bits == 64 and not path64:
            engine.error(f"64-bit object '{inspath}' in 32-bit path",
                         msgid=f"{self.name}{_pkglint_id}.2")
Exemple #19
0
                        fname, data = misc.get_data_digest(action.data(),
                            length=size, return_content=True)

                        action.hash = fname

                        # Extract ELF information
                        # XXX This needs to be modularized.
                        if haveelf and data[:4] == "\x7fELF":
                                elf_name = os.path.join(self.dir, ".temp-%s"
                                    % fname)
                                elf_file = open(elf_name, "wb")
                                elf_file.write(data)
                                elf_file.close()

                                try:
                                        elf_info = elf.get_info(elf_name)
                                except elf.ElfError, e:
                                        raise TransactionContentError(e)

                                try:
                                        elf_hash = elf.get_dynamic(
                                            elf_name)["hash"]
                                        action.attrs["elfhash"] = elf_hash
                                except elf.ElfError:
                                        pass
                                action.attrs["elfbits"] = str(elf_info["bits"])
                                action.attrs["elfarch"] = elf_info["arch"]
                                os.unlink(elf_name)

                        try:
                                dst_path = self.rstore.file(fname)
Exemple #20
0
            fname, data = misc.get_data_digest(action.data(),
                                               length=size,
                                               return_content=True)

            action.hash = fname

            # Extract ELF information
            # XXX This needs to be modularized.
            if haveelf and data[:4] == "\x7fELF":
                elf_name = "%s/.temp" % self.dir
                elf_file = open(elf_name, "wb")
                elf_file.write(data)
                elf_file.close()

                try:
                    elf_info = elf.get_info(elf_name)
                except elf.ElfError, e:
                    raise TransactionContentError(e)

                try:
                    elf_hash = elf.get_dynamic(elf_name)["hash"]
                    action.attrs["elfhash"] = elf_hash
                except elf.ElfError:
                    pass
                action.attrs["elfbits"] = str(elf_info["bits"])
                action.attrs["elfarch"] = elf_info["arch"]
                os.unlink(elf_name)

            #
            # This check prevents entering into the depot store
            # a file which is already there in the store.
Exemple #21
0
    def __elf_runpath_check(self, path, engine, _pkglint_id):
        """Verify that RUNPATH of given binary is correct."""
        runpath_list = []

        dyninfo = elf.get_dynamic(path)
        elfinfo = elf.get_info(path)
        for runpath in dyninfo.get("runpath", "").split(":"):
            if not runpath:
                continue

            match = False
            for expr in self.runpath_re:
                if expr.match(runpath):
                    match = True
                    break

            if not match:
                runpath_list.append(runpath)

            # Make sure RUNPATH matches against a packaged path.
            # Don't check runpaths starting with $ORIGIN, which
            # is specially handled by the linker.
            elif not runpath.startswith("$ORIGIN/"):

                # Strip out leading and trailing '/' in the
                # runpath, since the reference paths don't start
                # with '/' and trailing '/' could cause mismatches.
                # Check first if there is an exact match, then check
                # if any reference path starts with this runpath
                # plus a trailing slash, since it may still be a link
                # to a directory that has no action because it uses
                # the default attributes.
                relative_dir = runpath.strip("/")
                if relative_dir not in self.ref_paths and not any(
                        key.startswith(relative_dir + "/")
                        for key in self.ref_paths):

                    # If still no match, if the runpath contains
                    # an embedded symlink, emit a warning; it may or may
                    # not resolve to a legitimate path.
                    # E.g., for usr/openwin/lib, usr/openwin->X11 and
                    # usr/X11/lib are packaged, but usr/openwin/lib is not.
                    # Otherwise, runpath is bad; add it to list.
                    pdir = os.path.dirname(relative_dir)
                    while pdir != "":
                        if pdir in self.ref_paths and self.ref_paths[pdir][0][
                                1].name == "link":
                            engine.warning(
                                f"runpath '{runpath}' in '{path}' not found in reference "
                                f"paths but contains symlink at '{pdir}'",
                                msgid=f"{self.name}{_pkglint_id}.3")
                            break
                        pdir = os.path.dirname(pdir)
                    else:
                        runpath_list.append(runpath)

            if elfinfo["bits"] == 32:
                for expr in self.runpath_64_re:
                    if expr.search(runpath):
                        engine.warning(
                            f"64-bit runpath in 32-bit binary, '{path}' includes '{runpath}'",
                            msgid=f"{self.name}{_pkglint_id}.3")
            else:
                for expr in self.runpath_64_re:
                    if expr.search(runpath):
                        break
                else:
                    engine.warning(
                        f"32-bit runpath in 64-bit binary, '{path}' includes '{runpath}'",
                        msgid=f"{self.name}{_pkglint_id}.3")

        # handle all incorrect RUNPATHs in a single error
        if runpath_list:
            engine.error(
                f"bad RUNPATH, '{path}' includes '{':'.join(runpath_list)}'",
                msgid=f"{self.name}{_pkglint_id}.3")
Exemple #22
0
    def __get_elf_attrs(self, action, fname, size):
        """Helper function to get the ELF information."""

        # This currently uses the presence of "elfhash" to indicate the
        # need for *any* content hashes to be added. This will work as
        # expected until elfhash is no longer generated by default, and
        # then this logic will need to be updated accordingly.
        need_elf_info = False
        need_elfhash = False

        bufsz = misc.PKG_FILE_BUFSIZ
        if bufsz > size:
            bufsz = size

        f = action.data()
        magic = f.read(4)
        if haveelf and magic == b"\x7fELF":
            need_elf_info = ("elfarch" not in action.attrs
                             or "elfbits" not in action.attrs)
            need_elfhash = "elfhash" not in action.attrs
        if not need_elf_info or not need_elfhash:
            f.close()
            return misc.EmptyDict

        elf_name = os.path.join(self._tmpdir, ".temp-{0}".format(fname))
        with open(elf_name, "wb") as elf_file:
            elf_file.write(magic)
            while True:
                data = f.read(bufsz)
                if not data:
                    break
                elf_file.write(data)
        f.close()

        attrs = {}
        if need_elf_info:
            try:
                elf_info = elf.get_info(elf_name)
            except elf.ElfError as e:
                raise TransactionError(e)
            attrs["elfbits"] = str(elf_info["bits"])
            attrs["elfarch"] = elf_info["arch"]

        # Check which content checksums to compute and add to the action
        get_elfhash = (need_elfhash
                       and "elfhash" in digest.DEFAULT_GELF_HASH_ATTRS)
        get_sha256 = (need_elfhash and not digest.sha512_supported
                      and "pkg.content-hash" in digest.DEFAULT_GELF_HASH_ATTRS)
        get_sha512t_256 = (need_elfhash and digest.sha512_supported
                           and "pkg.content-hash"
                           in digest.DEFAULT_GELF_HASH_ATTRS)

        if get_elfhash or get_sha256 or get_sha512t_256:
            try:
                attrs.update(
                    elf.get_hashes(elf_name,
                                   elfhash=get_elfhash,
                                   sha256=get_sha256,
                                   sha512t_256=get_sha512t_256))
            except elf.ElfError:
                pass

        os.unlink(elf_name)
        return attrs
    def __elf_runpath_check(self, path, engine):
        result = None
        list = []

        ed = elf.get_dynamic(path)
        ei = elf.get_info(path)
        bits = ei.get("bits")
        for dir in ed.get("runpath", "").split(":"):
            if dir == None or dir == '':
                continue

            match = False
            for expr in self.runpath_re:
                if expr.match(dir):
                    match = True
                    break

            if match == False:
                list.append(dir)
            # Make sure RUNPATH matches against a packaged path.
            # Don't check runpaths starting with $ORIGIN, which
            # is specially handled by the linker.

            elif not dir.startswith('$ORIGIN/'):

                # Strip out leading and trailing '/' in the
                # runpath, since the reference paths don't start
                # with '/' and trailing '/' could cause mismatches.
                # Check first if there is an exact match, then check
                # if any reference path starts with this runpath
                # plus a trailing slash, since it may still be a link
                # to a directory that has no action because it uses
                # the default attributes.

                relative_dir = dir.strip('/')
                if not relative_dir in self.ref_paths and \
                    not any(key.startswith(relative_dir + '/')
                        for key in self.ref_paths):

                    # If still no match, if the runpath contains
                    # an embedded symlink, emit a warning; it may or may
                    # not resolve to a legitimate path.
                    # E.g., for usr/openwin/lib, usr/openwin->X11 and
                    # usr/X11/lib are packaged, but usr/openwin/lib is not.
                    # Otherwise, runpath is bad; add it to list.
                    embedded_link = False
                    pdir = os.path.dirname(relative_dir)
                    while pdir != '':
                        if (pdir in self.ref_paths
                                and self.ref_paths[pdir][0][1].name == "link"):
                            embedded_link = True
                            engine.warning(_(
                                "runpath '%s' in '%s' not found in reference paths but contains symlink at '%s'"
                            ) % (dir, path, pdir),
                                           msgid="%s%s.3" % (self.name, "001"))
                            break
                        pdir = os.path.dirname(pdir)
                    if not embedded_link:
                        list.append(dir)

            if bits == 32:
                for expr in self.runpath_64_re:
                    if expr.search(dir):
                        engine.warning(_(
                            "64-bit runpath in 32-bit binary, '%s' includes '%s'"
                        ) % (path, dir),
                                       msgid="%s%s.3" % (self.name, "001"))
            else:
                match = False
                for expr in self.runpath_64_re:
                    if expr.search(dir):
                        match = True
                        break
                if match == False:
                    engine.warning(
                        _("32-bit runpath in 64-bit binary, '%s' includes '%s'"
                          ) % (path, dir),
                        msgid="%s%s.3" % (self.name, "001"))
        if len(list) > 0:
            result = _("bad RUNPATH, '%%s' includes '%s'" % ":".join(list))

        return result
Exemple #24
0
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, {}
Exemple #25
0
        def add_content(self, action):
                """Adds the content of the provided action (if applicable) to
                the Transaction."""

                # Perform additional publication-time validation of actions
                # before further processing is done.
                try:
                        action.validate()
                except actions.ActionError as e:
                        raise TransactionOperationError(e)

                if self.append_trans and action.name != "signature":
                        raise TransactionOperationError(non_sig=True)

                size = int(action.attrs.get("pkg.size", 0))

                if action.has_payload and size <= 0:
                        # XXX hack for empty files
                        action.data = lambda: open(os.devnull, "rb")

                if action.data is not None:
                        # get all hashes for this action
                        hashes, data = misc.get_data_digest(action.data(),
                            length=size, return_content=True,
                            hash_attrs=digest.LEGACY_HASH_ATTRS,
                            hash_algs=digest.HASH_ALGS)

                        # set the hash member for backwards compatibility and
                        # remove it from the dictionary
                        action.hash = hashes.pop("hash", None)
                        action.attrs.update(hashes)

                        # now set the hash value that will be used for storing
                        # the file in the repository.
                        hash_attr, hash_val, hash_func = \
                            digest.get_least_preferred_hash(action)
                        fname = hash_val

                        # Extract ELF information if not already provided.
                        # XXX This needs to be modularized.
                        if haveelf and data[:4] == b"\x7fELF" and (
                            "elfarch" not in action.attrs or
                            "elfbits" not in action.attrs or
                            "elfhash" not in action.attrs):
                                elf_name = os.path.join(self.dir,
                                    ".temp-{0}".format(fname))
                                elf_file = open(elf_name, "wb")
                                elf_file.write(data)
                                elf_file.close()

                                try:
                                        elf_info = elf.get_info(elf_name)
                                except elf.ElfError as e:
                                        raise TransactionContentError(e)

                                try:
                                        # Check which content checksums to
                                        # compute and add to the action
                                        elf1 = "elfhash"

                                        if elf1 in \
                                            digest.LEGACY_CONTENT_HASH_ATTRS:
                                                get_sha1 = True
                                        else:
                                                get_sha1 = False

                                        hashes = elf.get_hashes(elf_name,
                                            elfhash=get_sha1)

                                        if get_sha1:
                                                action.attrs[elf1] = hashes[elf1]

                                except elf.ElfError:
                                        pass
                                action.attrs["elfbits"] = str(elf_info["bits"])
                                action.attrs["elfarch"] = elf_info["arch"]
                                os.unlink(elf_name)

                        try:
                                dst_path = self.rstore.file(fname)
                        except Exception as e:
                                # The specific exception can't be named here due
                                # to the cyclic dependency between this class
                                # and the repository class.
                                if getattr(e, "data", "") != fname:
                                        raise
                                dst_path = None

                        csize, chashes = misc.compute_compressed_attrs(
                            fname, dst_path, data, size, self.dir)
                        for attr in chashes:
                                action.attrs[attr] = chashes[attr]
                        action.attrs["pkg.csize"] = csize

                self.remaining_payload_cnt = \
                    len(action.attrs.get("chain.sizes", "").split())

                # Do some sanity checking on packages marked or being marked
                # obsolete or renamed.
                if action.name == "set" and \
                    action.attrs["name"] == "pkg.obsolete" and \
                    action.attrs["value"] == "true":
                        self.obsolete = True
                        if self.types_found.difference(
                            set(("set", "signature"))):
                                raise TransactionOperationError(_("An obsolete "
                                    "package cannot contain actions other than "
                                    "'set' and 'signature'."))
                elif action.name == "set" and \
                    action.attrs["name"] == "pkg.renamed" and \
                    action.attrs["value"] == "true":
                        self.renamed = True
                        if self.types_found.difference(
                            set(("depend", "set", "signature"))):
                                raise TransactionOperationError(_("A renamed "
                                    "package cannot contain actions other than "
                                    "'set', 'depend', and 'signature'."))

                if not self.has_reqdeps and action.name == "depend" and \
                    action.attrs["type"] == "require":
                        self.has_reqdeps = True

                if self.obsolete and self.renamed:
                        # Reset either obsolete or renamed, depending on which
                        # action this was.
                        if action.attrs["name"] == "pkg.obsolete":
                                self.obsolete = False
                        else:
                                self.renamed = False
                        raise TransactionOperationError(_("A package may not "
                            " be marked for both obsoletion and renaming."))
                elif self.obsolete and action.name not in ("set", "signature"):
                        raise TransactionOperationError(_("A '{type}' action "
                            "cannot be present in an obsolete package: "
                            "{action}").format(
                            type=action.name, action=action))
                elif self.renamed and action.name not in \
                    ("depend", "set", "signature"):
                        raise TransactionOperationError(_("A '{type}' action "
                            "cannot be present in a renamed package: "
                            "{action}").format(
                            type=action.name, action=action))

                # Now that the action is known to be sane, we can add it to the
                # manifest.
                tfpath = os.path.join(self.dir, "manifest")
                tfile = open(tfpath, "a+")
                print(action, file=tfile)
                tfile.close()

                self.types_found.add(action.name)
Exemple #26
0
        def add_content(self, action):
                """Adds the content of the provided action (if applicable) to
                the Transaction."""

                size = int(action.attrs.get("pkg.size", 0))

                if action.name in ("file", "license") and size <= 0:
                        # XXX hack for empty files
                        action.data = lambda: open(os.devnull, "rb")

                if action.data is not None:
                        bufsz = 64 * 1024

                        fname, data = misc.get_data_digest(action.data(),
                            length=size, return_content=True)

                        action.hash = fname

                        # Extract ELF information
                        # XXX This needs to be modularized.
                        if haveelf and data[:4] == "\x7fELF":
                                elf_name = "%s/.temp" % self.dir
                                elf_file = open(elf_name, "wb")
                                elf_file.write(data)
                                elf_file.close()

                                try:
                                        elf_info = elf.get_info(elf_name)
                                except elf.ElfError, e:
                                        raise TransactionContentError(e)

                                try:
                                        elf_hash = elf.get_dynamic(
                                            elf_name)["hash"]
                                        action.attrs["elfhash"] = elf_hash
                                except elf.ElfError:
                                        pass
                                action.attrs["elfbits"] = str(elf_info["bits"])
                                action.attrs["elfarch"] = elf_info["arch"]
                                os.unlink(elf_name)

                        #
                        # This check prevents entering into the depot store
                        # a file which is already there in the store.
                        # This takes CPU load off the depot on large imports
                        # of mostly-the-same stuff.  And in general it saves
                        # disk bandwidth, and on ZFS in particular it saves
                        # us space in differential snapshots.  We also need
                        # to check that the destination is in the same
                        # compression format as the source, as we must have
                        # properly formed files for chash/csize properties
                        # to work right.
                        #
                        fpath = misc.hash_file_name(fname)
                        dst_path = "%s/%s" % (self.cfg.file_root, fpath)
                        fileneeded = True
                        if os.path.exists(dst_path):
                                if PkgGzipFile.test_is_pkggzipfile(dst_path):
                                        fileneeded = False
                                        opath = dst_path

                        if fileneeded:
                                opath = os.path.join(self.dir, fname)
                                ofile = PkgGzipFile(opath, "wb")

                                nbuf = size / bufsz

                                for n in range(0, nbuf):
                                        l = n * bufsz
                                        h = (n + 1) * bufsz
                                        ofile.write(data[l:h])

                                m = nbuf * bufsz
                                ofile.write(data[m:])
                                ofile.close()

                        data = None

                        # Now that the file has been compressed, determine its
                        # size and store that as an attribute in the manifest
                        # for the file.
                        fs = os.stat(opath)
                        action.attrs["pkg.csize"] = str(fs.st_size)

                        # Compute the SHA hash of the compressed file.
                        # Store this as the chash attribute of the file's
                        # action.  In order for this to work correctly, we
                        # have to use the PkgGzipFile class.  It omits
                        # filename and timestamp information from the gzip
                        # header, allowing us to generate deterministic
                        # hashes for different files with identical content.
                        cfile = open(opath, "rb")
                        chash = sha.new()
                        while True:
                                cdata = cfile.read(bufsz)
                                if cdata == "":
                                        break
                                chash.update(cdata)
                        cfile.close()
                        action.attrs["chash"] = chash.hexdigest()
                        cdata = None