コード例 #1
0
    def __init__(self, app_dir, app_dir_files):
        super().__init__(app_dir, app_dir_files)

        self.priority = 100
        self.patch_elf = PatchElf()
        self.patch_elf.logger.level = logging.WARNING
        self.system_interpreter = None
コード例 #2
0
    def get_dependants_of(self, lib_name):
        dependants = set()
        for root, dirs, files in os.walk(self.app_dir):
            if 'opt/libc' in root:
                continue

            for file in files:
                abs_path = os.path.join(root, file)
                try:
                    if is_elf(abs_path):
                        patch_elf = PatchElf()
                        patch_elf.log_stdout = False
                        patch_elf.log_stderr = False
                        patch_elf.log_command = False

                        needs = patch_elf.get_needed(abs_path)
                        if lib_name in needs:
                            dependants.add(
                                os.path.relpath(abs_path, self.app_dir))

                except FileNotFoundError:
                    pass
                except PatchElfError:
                    pass

        return dependants
コード例 #3
0
    def get_bundle_needed_libs(self):
        libs_needed = set()
        bundle_libs = set()
        for root, dirs, files in os.walk(self.app_dir):
            if 'opt/libc' in root:
                continue

            for file in files:
                bundle_libs.add(file)
                abs_path = os.path.join(root, file)
                try:
                    if is_elf(abs_path):
                        patch_elf = PatchElf()
                        patch_elf.log_stdout = False
                        patch_elf.log_stderr = False
                        patch_elf.log_command = False

                        libs_needed.update(patch_elf.get_needed(abs_path))
                except FileNotFoundError:
                    pass
                except PatchElfError:
                    pass

        bundle_needed = libs_needed - bundle_libs
        return bundle_needed
コード例 #4
0
 def _set_interpreter(self, file, interpreter):
     try:
         patchelf_command = PatchElf()
         patchelf_command.log_stderr = False
         bin_interpreter = patchelf_command.get_interpreter(file)
         if bin_interpreter:
             self.system_interpreter = bin_interpreter
             logging.info('Setting interpreter to: %s' % os.path.relpath(file, self.app_dir))
             patchelf_command.set_interpreter(file, interpreter)
     except PatchElfError:
         pass
コード例 #5
0
    def _set_interpreter(self, file, uuid):
        try:
            patchelf_command = PatchElf()
            patchelf_command.log_stderr = False
            real_interpreter = patchelf_command.get_interpreter(file)
            if real_interpreter.startswith('/tmp/appimage-'):
                # skip, the binary has been patched already
                return

            apprun_interpreter = self._gen_interpreter_link_path(
                real_interpreter, uuid)
            if real_interpreter and real_interpreter != apprun_interpreter:
                self.interpreters[real_interpreter] = apprun_interpreter
                logging.info('Replacing PT_INTERP on: %s' %
                             os.path.relpath(file, self.app_dir))
                logging.info('\t"%s"  => "%s"' %
                             (real_interpreter, apprun_interpreter))
                patchelf_command.set_interpreter(file, apprun_interpreter)
        except PatchElfError:
            pass
コード例 #6
0
class DynamicLoader(BaseHelper):
    def __init__(self, app_dir, app_dir_files):
        super().__init__(app_dir, app_dir_files)

        self.priority = 100
        self.patch_elf = PatchElf()
        self.patch_elf.logger.level = logging.WARNING

    def get_binary_path(self) -> str:
        linker_dir = os.path.join(self.app_dir, 'lib')
        logging.debug("Looking linker binary at: %s\n" % linker_dir)

        binary_path = self._find_binary_by_name(linker_dir)
        binary_path = self._resolve_symlink(binary_path)
        binary_path = self._make_path_relative_to_app_dir(binary_path)

        return binary_path

    def configure(self, app_run):
        linker_path = self.get_binary_path()
        app_run.env['LINKER_PATH'] = '$APPDIR/%s' % linker_path
        self._set_elf_run_paths(app_run.env['APPIMAGE_UUID'])

    def _make_path_relative_to_app_dir(self, binary_path):
        binary_path = os.path.abspath(binary_path)
        abs_app_dir_path = os.path.abspath(self.app_dir) + '/'
        binary_path = binary_path.replace(abs_app_dir_path, '')

        return binary_path

    def _resolve_symlink(self, binary_path):
        if os.path.islink((binary_path)):
            link_target = os.readlink(binary_path)

            if link_target.startswith('/'):
                binary_path = os.path.join(self.app_dir, link_target)
            else:
                dir = os.path.dirname(binary_path)
                binary_path = os.path.join(dir, link_target)

        return binary_path

    def _find_binary_by_name(self, linker_dir) -> str:
        for file in self.app_dir_files:
            if self._is_linker_file(file):
                return file
        raise DynamicLoaderError('Unable to find \'ld.so\' in the AppDir')

    @staticmethod
    def _is_linker_file(file):
        return fnmatch.fnmatch(file, '*/lib/*/ld-*.so*') or fnmatch.fnmatch(
            file, '*/lib64/ld-*.so*')

    def _set_elf_run_paths(self, appimage_uuid):
        for file in self.app_dir_files:
            if not self._is_linker_file(file) and not os.path.islink(file):
                self._patch_elf(file, appimage_uuid)

    def _list_libs(self):
        library_files = []
        for full_path in self.app_dir_files:
            if self._is_shared_lib(full_path):
                library_files.append(full_path)

        return library_files

    def _patch_elf(self, file, appimage_uuid):
        run_path = None
        interpreter_path = None
        try:
            self.patch_elf.log_stderr = False
            needed_libs = self.patch_elf.get_needed(file)
            if needed_libs:
                link_dirs = self._find_elf_link_dirs(needed_libs)
                logging.info("Setting RUN_PATHS to: %s" %
                             os.path.relpath(file, self.app_dir))
                run_path = self._create_elf_run_path_list(file, link_dirs)

        except PatchElfError:
            pass

        try:
            self.patch_elf.log_stderr = False
            interpreter = self.patch_elf.get_interpreter(file)
            if interpreter:
                interpreter_path = '/tmp/appimage_%s.ld.so' % appimage_uuid
                # https://docs.oracle.com/cd/E19957-01/806-0641/chapter6-71736/index.html
                logging.info("Setting PT_INTERP to: %s" %
                             os.path.relpath(file, self.app_dir))

        except PatchElfError:
            pass

        try:
            if run_path or interpreter_path:
                self.patch_elf.log_stderr = True
                self.patch_elf.set(file,
                                   run_path=run_path,
                                   interpreter=interpreter_path)
        except PatchElfError:
            pass

    @staticmethod
    def _create_elf_run_path_list(file, link_dirs):
        run_path = set()
        for dir_path in link_dirs:
            rel_path = os.path.relpath(dir_path, os.path.dirname(file))
            if rel_path == '.':
                rel_path = ''

            run_path_entry = '$ORIGIN/%s' % rel_path

            logging.debug("\t%s" % run_path_entry)
            run_path.add(run_path_entry)

        return run_path

    def _find_elf_link_dirs(self, needed):
        lib_dirs = set()
        for entry in needed:
            path = self._get_relative_parent_dir_of(entry)
            if path:
                abs_path = os.path.join(self.app_dir, path)
                lib_dirs.add(abs_path)
        return lib_dirs

    @staticmethod
    def _is_shared_lib(path):
        file_name = os.path.basename(path)
        return file_name.endswith('.so') or '.so.' in file_name