Esempio n. 1
0
    def send_files(self, incremental_patches_list):
        """
        Send config and patch files

        :return: void
        """
        f_action = FileAction(self.config_fullpath)
        temporary_config = tempfile.NamedTemporaryFile(delete=False)
        # check the configuration file
        # TODO: make it more compact
        if re.findall("[.]gz\Z", self.config_fullpath):
            log.notice('gz extension')
            # uncompress the gzip config file
            # return configuration temporary folder
            temporary_config = f_action.decompress_gz(temporary_config)
        else:
            # read already uncompressed configuration
            with open(self.config_fullpath, 'rb') as in_file:
                config = in_file.read()
                # Store uncompressed temporary file
            temporary_config.write(config)
        # Get kernel version from the configuration file header
        # self.kernel_version = f_action.config_kernel_version(temporary_config)
        self.rest_manager.set_kernel_version(self.kernel_version)
        log.notice('debug: kernel version = ' +
                   self.rest_manager.get_kernel_version())

        send_api = '/elivepatch/api/v1.0/get_files'

        # send uncompressed config and patch files fullpath
        self.rest_manager.send_files(temporary_config,
                                     self.main_patch_fullpath,
                                     incremental_patches_list, send_api)
Esempio n. 2
0
 def version(self):
     """
     Function for as the server version and print on screen
     """
     url = self.server_url + '/elivepatch/api/v1.0/agent'
     r = requests.get(url)
     log.notice(r.json())
Esempio n. 3
0
 def load(self, patch_fulldir, livepatch_fulldir):
     """
     kpatch load live patch into the client machine working kernel
     :param patch_fulldir: String patch full directory
     :param livepatch_fulldir: String live patch full directory
     """
     try:
         _command(['sudo', 'kpatch', 'load', livepatch_fulldir])
         log.notice('patch_fulldir:' + str(patch_fulldir) + ' livepatch_fulldir: '+ str(livepatch_fulldir))
         self._save(patch_fulldir, livepatch_fulldir)
     except:
         log.notice('failed to load the livepatch')
Esempio n. 4
0
 def __init__(self, restserver_url, kernel_version, session_uuid=None):
     self.config_fullpath = ''
     self.main_patch_fullpath = ''
     self.restserver_url = restserver_url
     self.kernel_version = kernel_version
     if session_uuid:
         self.session_uuid = session_uuid
     else:
         self.session_uuid = id_generate_uuid()
     log.notice('This session uuid: ' + str(self.session_uuid))
     self.rest_manager = restful.ManaGer(self.restserver_url,
                                         self.kernel_version,
                                         self.session_uuid)
Esempio n. 5
0
 def decompress_gz(self, temporary):
     """
     Uncompress gzipped configuration
     :return: Uncompressed configuration file path
     """
     path_gz_file = self.full_path
     log.notice('path_gz_file: ' + path_gz_file +
                ' temporary_path_uncompressed_file: ' + temporary.name)
     if os.path.isfile(path_gz_file):
         with gzip.open(path_gz_file, 'rb') as in_file:
             uncompressed_output = in_file.read()
         # Store uncompressed file
         temporary.write(uncompressed_output)
     return temporary
Esempio n. 6
0
    def get_livepatch(self, patch_folder):
        """
        Save the patch in the incremental patches folder and install the livepatch
        :param patch_folder: Main patch that will be saved in the incremental patches folder.
        """
        patch_manager = patch.ManaGer()
        url = self.server_url + '/elivepatch/api/v1.0/send_livepatch'
        payload = {'KernelVersion': self.kernel_version, 'UUID': self.uuid}
        try:
            r = requests.get(url, json=payload)
            if r.status_code == requests.codes.ok:  # livepatch returned ok
                try:
                    b = BytesIO(r.content)
                    with open('myfile.ko', 'wb') as out:
                        out.write(r.content)
                    r.close()
                    log.notice(b)
                except:
                    log.notice('livepatch not found')
                    r.close()
        except:
            self._catching_exceptions_exit(self.get_livepatch)

        with tempfile.TemporaryDirectory() as elivepatch_uuid_dir:
            livepatch_fulldir = os.path.join(elivepatch_uuid_dir,
                                             'livepatch.ko')
            if os.path.exists('myfile.ko'):
                if not os.path.exists(elivepatch_uuid_dir):
                    os.makedirs(elivepatch_uuid_dir)
                shutil.copy("myfile.ko", livepatch_fulldir)
                log.notice('livepatch saved in ' + elivepatch_uuid_dir +
                           '/ folder')
                patch_manager.load(patch_folder, livepatch_fulldir)
            else:
                log.notice('livepatch not received')
Esempio n. 7
0
    def list(self, kernel_version):
        """
        Listing incremental patches
        :param kernel_version: String  with kernel version
        :return: list of incremental patch
        """
        kernel_sources = 'gentoo-sources'
        patch_filename = []
        previous_patches = []
        # search eapply_user patches
        # local basedir=${PORTAGE_CONFIGROOT%/}/etc/portage/patches
        try:
            portage_configroot = os.environ['PORTAGE_CONFIGROOT']
        except:
            portage_configroot = os.path.join('/etc', 'portage', 'patches')
        kernel_patch_basedir_PN = os.path.join(portage_configroot, 'sys-kernel',
                                            kernel_sources)
        kernel_patch_basedir_P = os.path.join(portage_configroot, 'sys-kernel',
                                            kernel_sources + '-' + kernel_version)
        basedir = [kernel_patch_basedir_PN, kernel_patch_basedir_P]
        for path in basedir:
            for (dirpath, dirnames, filenames) in os.walk(path):
                if filenames and not dirnames:
                    for filename in filenames:
                        if filename.endswith('.patch'):
                            log.notice('dirpath: '+str(dirpath),'filename: '+str(filename))
                            incremental_patch_fullpath = os.path.join(dirpath, filename)
                            log.notice(incremental_patch_fullpath)
                            patch_filename.append(incremental_patch_fullpath)
        # os.walk() walks in random order, perform a lexical sort
        patch_filename.sort()

        # search previous livepatch patch folder
        for (dirpath, dirnames, filenames) in os.walk(self.tmp_patch_folder):
            if filenames and not dirnames:
                for filename in filenames:
                    if filename.endswith('.patch'):
                        log.notice(str('dirpath: '+str(dirpath) + 'filename: '+str(filename)))
                        incremental_patch_fullpath = os.path.join(dirpath, filename)
                        log.notice(incremental_patch_fullpath)
                        previous_patches.append(incremental_patch_fullpath)
        # os.walk() walks in random order, perform a lexical sort
        previous_patches = sorted(previous_patches, key=lambda elive: int(elive.replace('/elivepatch.patch','').split('_')[1]))

        # Append the previous patches to the eapply_user patches list
        patch_filename.extend(previous_patches)

        log.notice('List of current patches:')
        return patch_filename
Esempio n. 8
0
    def cve_git_id(self, kernel_version):
        major_version, minor_version, revision_version = kernel_version.split(
            '.')
        print(major_version, minor_version, revision_version)
        security_file = open(
            self.repo_dir + str(major_version) + "." + str(minor_version) +
            "/" + str(major_version) + "." + str(minor_version) +
            "_security.txt", "r")
        security_versions = []
        for line in security_file:
            if "CVEs fixed in" in line:
                security_versions_tmp = line.strip().split(' ')[3][:-1]
                # if there is not revision, set revision as 0
                sv_split_tmp = security_versions_tmp.split('.')
                if len(sv_split_tmp) == 2:
                    security_versions.append(0)
                else:
                    security_versions.append(
                        security_versions_tmp.split('.')[2])
        security_file.close()

        log.notice('[debug] security versions: ' + str(security_versions))

        cve_2d_list = []
        for version in security_versions:
            if int(version) > int(revision_version):
                cve_2d_list.append(
                    self.cve_id(major_version, minor_version, version))

        cve_outfile_list = []
        patch_index = 0
        if not os.path.exists(self.cve_patches_dir):
            os.mkdir(self.cve_patches_dir)
        for cve_list in cve_2d_list:
            # Remove duplicated cve_id from the cve list for not add the same patch
            cve_list = [
                ii for n, ii in enumerate(cve_list) if ii not in cve_list[:n]
            ]
            for cve_id in cve_list:
                cve_outfile = self.download_cve_patch(
                    cve_id,
                    str(patch_index).zfill(5))
                cve_outfile_list.append([cve_outfile[0], cve_outfile[1].name])
                patch_index += 1
        return cve_outfile_list
Esempio n. 9
0
 def send_files(self, temporary_config, new_patch_fullpath,
                incremental_patches, api):
     """
     Function for send files and build live patch (server side)
     :param temporary_config: configuration file full path
     :param new_patch_fullpath: main patch full path
     :param incremental_patches: List with incremental patches paths
     :param api: RESTFul server path
     :return: json with response
     """
     url = self.server_url + api
     # we are sending the file and the UUID
     # The server is dividing user by UUID
     # UUID is generated with python UUID
     # TODO: add the UUID in the json location instead of headers
     response_dict = None
     headers = {'KernelVersion': self.kernel_version, 'UUID': self.uuid}
     # Static patch and config filename
     files = []
     counter = 0
     log.notice('incremental_patches: ' + str(incremental_patches))
     for incremental_patch_fullpath in incremental_patches:
         if incremental_patch_fullpath.endswith('.patch'):
             # TODO: we need to close what we open
             read_incremental_patch = open(incremental_patch_fullpath, 'rb')
             files.append(
                 ('patch', (str(counter).zfill(5) + '.patch',
                            read_incremental_patch, 'multipart/form-data', {
                                'Expires': '0'
                            })))
             counter += 1
     files.append(
         ('main_patch', ('main.patch', open(new_patch_fullpath,
                                            'rb'), 'multipart/form-data', {
                                                'Expires': '0'
                                            })))
     files.append(('config', ('config', open(temporary_config.name,
                                             'rb'), 'multipart/form-data', {
                                                 'Expires': '0'
                                             })))
     log.notice(str(files))
     try:
         response = requests.post(url, files=files, headers=headers)
         log.notice('send file: ' + str(response.json()))
         response_dict = response.json()
     except requests.exceptions.ConnectionError as e:
         log.notice('connection error: %s' % e)
         temporary_config.close()
     except:
         self._catching_exceptions_exit(self.send_files)
     temporary_config.close()
     return response_dict
Esempio n. 10
0
def _command(bashCommand, kernel_source_dir=None, env=None):
    """
    Popen override function

    :param bashCommand: List of command arguments to execute
    :param kernel_source_dir: the source directory of the kernel
    :return: void
    """
    # Inherit the parent environment and update the private copy
    if env:
        process_env = os.environ.copy()
        process_env.update(env)
        env = process_env

    if kernel_source_dir:
        log.notice(bashCommand)
        process = subprocess.Popen(bashCommand, stdout=subprocess.PIPE,  cwd=kernel_source_dir, env=env)
        output, error = process.communicate()
        log.notice(output)
    else:
        log.notice(bashCommand)
        process = subprocess.Popen(bashCommand, stdout=subprocess.PIPE, env=env)
        output, error = process.communicate()
        log.notice(output)
Esempio n. 11
0
    def dispatch(self, config):
        log.debug(str(config))
        if config.cve:
            patch_manager = patch.ManaGer()
            applied_patches_list = patch_manager.list(config.kernel_version)
            log.notice(applied_patches_list)
            cve_repository = security.CVE()
            if not os.path.isdir("/tmp/kernel_cve"):
                log.notice("Downloading the CVE repository...")
                cve_repository.git_download()
            else:
                log.notice("CVE repository already present.")
                log.notice("updating...")
                cve_repository.git_update()
            if config.clear:
                if os.path.isfile('cve_ids'):
                    os.remove('cve_ids')
            cve_patch_list = cve_repository.cve_git_id(config.kernel_version)
            new_cve_patch_list = cve_patch_list
            cve_previous_patch_list = []
            # checking if we have a previous cve_ids list
            if os.path.isfile('cve_ids'):
                cve_db = shelve.open('cve_ids')
                for i in (list(cve_db.keys())):
                    cve_previous_patch_list.append([i, cve_db[i]])
                cve_db.close()
                new_cve_patch_list = []
                # checking if there is any new cve patch in the repository
                for cve_patch_id in cve_patch_list:
                    if cve_patch_id not in cve_previous_patch_list:
                        new_cve_patch_list.append(cve_patch_id)
            # converting new cve to live patch
            for cve_id, cve_patch in new_cve_patch_list:
                with shelve.open('cve_ids') as cve_db:
                    cve_db[cve_id] = cve_patch

            log.notice('merging cve patches...')
            with tempfile.NamedTemporaryFile(dir='/tmp/', delete=False) as portage_tmpdir:
                log.notice('portage_tmpdir: '+portage_tmpdir.name)
                for cve_id, cve_file in cve_patch_list:
                    with open(cve_file,'rb+') as infile:
                        portage_tmpdir.write(infile.read())
                livepatch(config.url, config.kernel_version, config.config, portage_tmpdir.name, applied_patches_list)

            log.notice(new_cve_patch_list)
        elif config.patch:
            patch_manager = patch.ManaGer()
            applied_patches_list = patch_manager.list(config.kernel_version)
            log.notice(str(applied_patches_list))
            livepatch(config.url, config.kernel_version, config.config, config.patch, applied_patches_list)

        elif config.version:
            log.notice('elivepatch version: '+str(VERSION))
        else:
            print('--help for help\n\
you need at list --patch or --cve')