def _install_one_gadget_by_version(cls, name, version, mappings=None, verbose=False): stdout, stderr = verbose_func.verbose_output(verbose) # get complete version, e.g. 18.03.1~ce-0~ubuntu complete_version = cls._get_apt_complete_version(name, version, verbose=verbose) if complete_version: color_print.debug( 'installing {gadget} with {version} version'.format( gadget=name, version=complete_version)) # install with the specified version temp_cmd = copy.copy(cls.cmd_apt_install) temp_cmd.append('{name}={version}'.format( name=name, version=complete_version)) try: subprocess.run(temp_cmd, stderr=stderr, stdout=stdout, check=True) except subprocess.CalledProcessError: return False if mappings: mappings[name] = complete_version return True color_print.warning('no candidate version for %s' % name) return False
def install_by_version(cls, gadgets, context=None, verbose=False): """Install Linux kernel with specified version. Args: gadgets: Kernel gadgets (e.g. kernel). context: Currently not used. verbose: Verbose or not. Returns: Boolean indicating whether kernel is successfully installed or not. """ # refer to # https://blog.csdn.net/u013431916/article/details/82530523 # https://wiki.ubuntu.com/KernelTeam/KernelMaintenance # and # https://en.wikipedia.org/wiki/Linux_kernel#Version_numbering version = gadgets[0]['version'] color_print.debug('switching kernel by version') for repo in config.kernel_apt_repo_entries: cls._add_apt_repository(repo_entry=repo, verbose=verbose) if cls._is_version_available_in_apt(version, verbose=verbose): return cls._install_by_version_with_apt(version, verbose=verbose) else: color_print.warning( 'no apt package for kernel %s' % version) if version.endswith('.0'): version = version.rstrip('.0') + '-' return cls._install_by_version_with_download( version, verbose=verbose)
def _install_by_version_with_download(cls, version, verbose=False): color_print.debug('switching kernel version with downloading packages') stdout, stderr = verbose_func.verbose_output(verbose) try: debs = cls._fetch_package_list_by_version(version, verbose=verbose) if not debs: return # download necessary *.deb and install temp_cmd = copy.copy(cls.cmd_dpkg_install) version_suffix = None for deb in debs: cls.download_file(deb, config.kernel_packages_dir) filename = deb.split('/')[-1] temp_cmd.append( '{prefix}/{filename}'.format(prefix=config.kernel_packages_dir, filename=filename)) if 'linux-image-' in filename: # get full version for further modification in grub try: version_suffix = re.search( r'linux-image-[a-z]*-?([\d].*?)_', filename).group(1) except AttributeError: # failed to derive complete kernel version pass color_print.debug('installing kernel packages') # installation of kernel may return nonzero, currently ignore them subprocess.run(temp_cmd, stdout=stdout, stderr=stderr, check=False) if version_suffix: color_print.debug('kernel version: %s' % version_suffix) cls._modify_grub(version=version_suffix) else: color_print.warning('failed to derive complete kernel version') color_print.warning('please update grub manually') return True except subprocess.CalledProcessError: return False
def remove(args): """Remove an installed cloud native gadget. Args: args.gadget: Name of the specified cloud native gadget. args.verbose: Verbose or not. Returns: None. """ if args.gadget == 'docker': DockerInstaller.uninstall(verbose=args.verbose) color_print.debug( '{gadget} successfully removed'.format(gadget=args.gadget)) if args.gadget == 'k8s': KubernetesInstaller.uninstall(verbose=args.verbose) color_print.debug( '{gadget} successfully removed'.format(gadget=args.gadget)) if args.gadget == 'kata': if KataContainersInstaller.uninstall(verbose=args.verbose): color_print.debug( '{gadget} successfully removed'.format(gadget=args.gadget)) else: color_print.error( 'failed to remove {gadget}'.format(gadget=args.gadget)) if args.gadget == 'kernel': color_print.warning( 'removal of {gadget} is unsupported'.format(gadget=args.gadget))
def remove(args): """Remove an installed cloud native vulnerability. Remove the vulnerable cloud native gadget with the cloud native vulnerability specified by args.cnv. Args: args.cnv: Name of the specified cloud native vulnerability. args.verbose: Verbose or not. Returns: None. """ vulns = vuln_loader.load_vulns_by_dir(config.vuln_cn_dir_wildcard) vuln = filters.filter_vuln_by_name(vulns=vulns, name=args.cnv) if not vuln: color_print.error_and_exit( 'no cloud native vulnerability named {cnv}'.format(cnv=args.cnv)) if vuln['class'] == 'config' or vuln['class'] == 'mount' or vuln[ 'class'] == 'no-vuln': vulns = vuln_loader.load_vulns_by_dir(config.vuln_cn_dir_wildcard) vuln = filters.filter_vuln_by_name(vulns=vulns, name=args.cnv) if not vuln: color_print.error_and_exit( 'no vulnerability named {cnv}'.format(cnv=args.cnv)) internal_cmds.delete_vuln_resources_in_k8s(vuln, verbose=args.verbose) return color_print.debug( '{vuln} is going to be removed'.format(vuln=vuln['name'])) if vuln['class'].startswith('docker'): DockerInstaller.uninstall(verbose=args.verbose) color_print.debug('{v} successfully removed'.format(v=vuln['name'])) if vuln['class'] == 'kubernetes': KubernetesInstaller.uninstall(verbose=args.verbose) color_print.debug('{v} successfully removed'.format(v=vuln['name'])) if vuln['class'] == 'kata-containers': if KataContainersInstaller.uninstall(verbose=args.verbose): color_print.debug( '{v} successfully removed'.format(v=vuln['name'])) else: color_print.error('failed to remove {v}'.format(v=vuln['name'])) if vuln['class'] == 'kernel': color_print.warning( 'removal of vulnerabilities in class {vuln_class} is unsupported'. format(vuln_class=vuln['class'])) return
def _fetch_package_list_by_version(cls, version, verbose=False): color_print.debug('retrieving package list for kernel %s' % version) try: f = open(config.kernel_packages_list, 'r') except FileNotFoundError: color_print.warning('%s does not exist.' % config.kernel_packages_list) package_list_downloader.download_package_list() f = open(config.kernel_packages_list, 'r') try: packages = yaml.load(f, Loader=yaml.SafeLoader) for key in packages.keys(): if version in key: color_print.debug('kernel package list found:') color_print.debug(json.dumps(packages[key])) return packages[key] except yaml.scanner.ScannerError: return None color_print.error('kernel package list not found') return None
def load_vuln(filename): """Load information about one vulnerability from one file. Args: filename: File storing information of specific vulnerability. Returns: If loading succeeds, return information dict about the vulnerability, else, return None. """ try: with open(filename, 'r') as f: # for SafeLoader, see # https://github.com/yaml/pyyaml/wiki/PyYAML-yaml.load(input)-Deprecation vuln = yaml.load(f, Loader=yaml.SafeLoader) vuln['path'] = re.sub('[^/]+.yaml$', '', filename) return vuln except FileNotFoundError: color_print.warning( '{filename} does not exist, skipped.'.format(filename=filename)) return None
def install_by_version(cls, gadgets, context=None, verbose=False): """Install Docker with specified version. Args: gadgets: Docker gadgets (e.g. docker-ce). context: Currently not used. verbose: Verbose or not. Returns: Boolean indicating whether Docker is successfully installed or not. """ if not cls._pre_install(verbose=verbose): color_print.error('failed to install prerequisites') return False for gadget in gadgets: if not cls._install_one_gadget_by_version( gadget['name'], gadget['version'], verbose=verbose): color_print.warning( 'docker seems to be installed, but some errors happened during installation') # sometimes docker is installed but error occurs during installation # so currently we just return true for it return True return True
def load_vuln(filename): """Load information about one vulnerability from one file. Args: filename: File storing information of specific vulnerability. Returns: If loading succeeds, return information dict about the vulnerability, else, return None. """ try: with open(filename, 'r') as f: # for SafeLoader, see # https://github.com/yaml/pyyaml/wiki/PyYAML-yaml.load(input)-Deprecation vuln = yaml.load(f, Loader=yaml.SafeLoader) # e.g. path: vulns_app/thinkphp/5.0.23-rce/ vuln['path'] = filename[:len(filename) - len(config.vuln_app_desc_file)] return vuln except FileNotFoundError: color_print.warning( '{filename} does not exist, skipped.'.format(filename=filename)) return None
def kata_specified_installed(temp_gadget, kata_runtime_type, verbose=False): """Check whether kata-containers with specified version has been installed. Args: temp_gadget: Kata-containers gadgets (e.g. kata-containers). kata_runtime_type: Runtime of Kata (e.g. qemu/clh/...). verbose: Returns: If kata-containers with specified version has been installed, return True, else False. """ try: _, stderr = verbose_func.verbose_output(verbose) temp_cmd = '{base_dir}/bin/kata-runtime --version'.format( base_dir=config.kata_tar_decompress_dest).split() res = subprocess.run( temp_cmd, stdout=subprocess.PIPE, stderr=stderr, check=True) version_string = res.stdout.decode('utf-8').split('\n')[0] server_version = re.search( r'.*([\d]+\.[\d]+\.[\d]+)', version_string).group(1) if server_version == temp_gadget[0]['version']: # check whether kata runtime type is also correct try: link_target = os.readlink( '{kata_config_dir}/configuration.toml'.format(kata_config_dir=config.kata_config_dir)) actual_runtime_type = link_target.split('.')[0].split('-')[-1] if actual_runtime_type != kata_runtime_type: color_print.warning( 'your expected kata runtime type is {expected}, while current type is {actual}'.format( expected=kata_runtime_type, actual=actual_runtime_type)) color_print.warning( 'you can configure runtime type manually') except (FileNotFoundError, OSError): color_print.warning( 'configuration.toml does not exist or is not an effective symbol link to real configurations') color_print.warning( 'please check configurations in {kata_config_dir} manually'.format( kata_config_dir=config.kata_config_dir)) return True return False except (IndexError, AttributeError, FileNotFoundError, subprocess.CalledProcessError): return False