diff options
-rw-r--r-- | elivepatch_client/client/checkers.py | 37 | ||||
-rw-r--r-- | elivepatch_client/client/cli.py | 16 | ||||
-rw-r--r-- | elivepatch_client/client/security.py | 95 |
3 files changed, 109 insertions, 39 deletions
diff --git a/elivepatch_client/client/checkers.py b/elivepatch_client/client/checkers.py index 79f45fa..ed8bf97 100644 --- a/elivepatch_client/client/checkers.py +++ b/elivepatch_client/client/checkers.py @@ -11,7 +11,6 @@ import tempfile import os import os.path import re -from git import Repo from elivepatch_client.client import restful @@ -81,23 +80,6 @@ class Kernel(object): self.rest_manager.get_livepatch(self.main_patch_fullpath) -class CVE(object): - """ - Check the kernel against a CVE repository - """ - def __init__(self): - self.git_url = "https://github.com/nluedtke/linux_kernel_cves" - self.repo_dir = "/tmp/kernel_cve/" - pass - - def download(self): - Repo.clone_from(self.git_url, self.repo_dir) - - def set_repo(self, git_url, repo_dir): - self.git_url = git_url - self.repo_dir = repo_dir - - class FileAction(object): """ Work with files @@ -120,22 +102,3 @@ class FileAction(object): # Store uncompressed file temporary.write(uncompressed_output) return temporary - - def config_kernel_version(self, uncompressed_config_file): - """ - Find the kernel version from where the configuration as been generated - :param uncompressed_config_file: - :return: kernel version - """ - uncompressed_config_file.seek(0) - with uncompressed_config_file as f: - i = 0 - while i < 2: - f.readline() - if i == 1: - kernel_line = str(f.readline()) - i += 1 - kernel_version_raw = str(kernel_line.split(' ')[2]) - kernel_version = kernel_version_raw.split(('-'))[0] - return kernel_version - diff --git a/elivepatch_client/client/cli.py b/elivepatch_client/client/cli.py index 181b1e0..2f45f67 100644 --- a/elivepatch_client/client/cli.py +++ b/elivepatch_client/client/cli.py @@ -5,12 +5,13 @@ # Distributed under the terms of the GNU General Public License v2 or later import sys +import os from elivepatch_client.client.checkers import Kernel from elivepatch_client.client import restful from elivepatch_client.client.version import VERSION from elivepatch_client.client import patch - +from elivepatch_client.client import security if sys.hexversion >= 0x30200f0: ALL_KEYWORD = b'ALL' @@ -30,7 +31,18 @@ class Main(object): def dispatch(self, config): print(str(config)) if config.cve: - print('Kernel security CVE check is not implemented yet') + patch_manager = patch.ManaGer() + applied_patches_list = patch_manager.list(config.kernel_version) + print(applied_patches_list) + cve_repository = security.CVE() + if not os.path.isdir("/tmp/kernel_cve"): + print("Downloading the CVE repository...") + cve_repository.download() + else: + print("CVE repository already present.") + print("updating...") + # TODO: update repository + cve_repository.cve_git_id() elif config.patch: patch_manager = patch.ManaGer() applied_patches_list = patch_manager.list(config.kernel_version) diff --git a/elivepatch_client/client/security.py b/elivepatch_client/client/security.py new file mode 100644 index 0000000..c322b0a --- /dev/null +++ b/elivepatch_client/client/security.py @@ -0,0 +1,95 @@ +from git import Repo +import os +import urllib.request as request +import shutil + + +class CVE(object): + """ + Check the kernel against a CVE repository + """ + def __init__(self): + self.git_url = "https://github.com/nluedtke/linux_kernel_cves" + self.repo_dir = "/tmp/kernel_cve/" + self.cve_patches_dir = "/tmp/patches_cve/" + pass + + def download(self): + Repo.clone_from(self.git_url, self.repo_dir) + + def set_repo(self, git_url, repo_dir): + self.git_url = git_url + self.repo_dir = repo_dir + + def cve_git_id(self): + major_version, minor_version, revision_version = _current_kernel_version() + major_version, minor_version, revision_version = 4,9,25 + security_file = open("/tmp/kernel_cve/"+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 + if len(security_versions_tmp) == 3: + security_versions.append(0) + else: + security_versions.append(security_versions_tmp.split('.')[2]) + security_file.close() + + print('[debug] security versions: ' + str(security_versions)) + + cve_2d_list = [] + for version in security_versions: + if int(version) > revision_version: + cve_2d_list.append(self.cve_id(major_version, minor_version, version)) + + 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: + print(cve_list) + print([ii for n,ii in enumerate(cve_list) if ii not in cve_list[:n]]) + for cve_id in cve_list: + self.download_cve_patch(cve_id, str(patch_index)) + patch_index +=1 + + def download_cve_patch(self, cve_id, patch_index): + file_name= self.cve_patches_dir + patch_index + '.patch' + + # Download the file from `url` and save it locally under `file_name`: + with request.urlopen('https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/patch/?id=' + cve_id) as response, \ + open(file_name, 'wb') as out_file: + shutil.copyfileobj(response, out_file) + + def cve_id(self, major_version, minor_version, revision_version): + security_file = open("/tmp/kernel_cve/"+str(major_version)+"."+str(minor_version)+ + "/"+str(major_version)+"."+str(minor_version)+"_security.txt", "r") + + git_security_id = [] + # return cve for a kernel version + for excluded_line in security_file: + if ("CVEs fixed in "+str(major_version)+ + "."+str(minor_version)+ + "."+str(revision_version)+ + ":") in excluded_line: + for included_line in security_file: + if not "\n" is included_line: + git_security_id.append(included_line.strip().split(' ')[1]) + else: + # debug + # print('got cve for '+str(major_version)+ + # "."+str(minor_version)+ + # "."+str(revision_version)) + break + security_file.close() + return git_security_id + + +def _current_kernel_version(): + kernel_version = os.uname()[2] + major_version = int(kernel_version.split('.')[0]) + minor_version = int(kernel_version.split('.')[1]) + revision_version = int((kernel_version.split('.')[2]).split('-')[0]) + return major_version, minor_version, revision_version + |