From 478c95410e4b1c9862e501474faa3cf582768af6 Mon Sep 17 00:00:00 2001 From: Bjoern Tropf Date: Mon, 8 Jun 2009 00:03:46 +0200 Subject: Add cve/vulnerability class, change lots of code --- TODO | 2 +- collector.py | 9 ++-- kernel-check.py | 53 +++++++++++---------- kernellib.py | 143 +++++++++++++++++++++++++++++++++----------------------- 4 files changed, 117 insertions(+), 90 deletions(-) diff --git a/TODO b/TODO index 0ff31d5..36b8884 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,7 @@ Todo ==== - Fix all TODO markers -- Create a vulnerability class +- Find a solution for Clean code ========== diff --git a/collector.py b/collector.py index 5951e95..cd214ef 100755 --- a/collector.py +++ b/collector.py @@ -101,15 +101,16 @@ def main(argv): print('Creating the xml files...') for item in buglist: lib.receive_bugzilla_bug(folder['bug'], item) - bug_dict = lib.parse_bugzilla_dict(folder['bug'], item) - lib.write_cve_file(folder['out'], item, bug_dict, nvd_dict) + vul = lib.parse_bugzilla_dict(folder['bug'], item) + vul = lib.search_nvd_dict(nvd_dict, vul) + lib.write_cve_file(folder['out'], vul) time.sleep(DELAY) def usage(): 'Prints the usage screen' - print 'Usage: ' + sys.argv[0][:-3] + ' [OPTION]...' + print 'Usage: %s [OPTION]...' % sys.argv[0][:-3] print 'Kernel security information\r\n' print ' -d, --delay [ticks] add delay to xml file creation' print ' -f, --force force update of xml files' @@ -117,7 +118,7 @@ def usage(): print ' -t, --tree [dir] set the portage path' print ' -s, --skip skip update of earlier xml files' print ' -v, --verbose display debugging information' - print '\r\nVersion: 0.3' + print '\r\nVersion: %s' % lib.VERSION print 'Copyright (C) 2009 Bjoern Tropf ' print 'Copyright (C) 2009 Robert Buchholz ' sys.exit() diff --git a/kernel-check.py b/kernel-check.py index c8f2019..1bce717 100755 --- a/kernel-check.py +++ b/kernel-check.py @@ -25,13 +25,6 @@ import kernellib as lib def main(argv): 'Main function' - KERNEL = lib.extract_version(os.uname()[2]) - - ARCH = os.uname()[4] - BEST = lib.best_version(KERNEL['source']) - CVE = [345, 284, 274, 0, 4] #TODO: Implement + use dict! - GENPATCH = lib.get_genpatch(lib.read_genpatch_file('out'), KERNEL) - info = portage.output.EOutput().einfo warn = portage.output.EOutput().ewarn error = portage.output.EOutput().eerror @@ -54,42 +47,46 @@ def main(argv): return # TODO: show_bugid(arg) elif opt in ('-v', '--verbose'): - lib.verbose = True + lib.VERBOSE = True print '>>> Gathering system information' - if KERNEL: - info('Kernel version: ' + color('GOOD', KERNEL['version'] + '-' + KERNEL['revision'])) - info('Kernel sources: ' + color('GOOD', KERNEL['source'])) + kernel = lib.extract_version(os.uname()[2]) + if kernel: + info('Kernel version: ' + color('GOOD', kernel['version'] + '-' + kernel['revision'])) + info('Kernel sources: ' + color('GOOD', kernel['source'])) else: error('No kernel information found!') sys.exit() - if GENPATCH: - info('Integrated genpatch: ' + color('GOOD', GENPATCH['version'] + ' ' + GENPATCH['want'])) + genpatch = lib.get_genpatch(lib.read_genpatch_file('out'), kernel) + if genpatch: + info('Integrated genpatch: ' + color('GOOD', genpatch['version'] + ' ' + genpatch['want'])) else: warn('No genpatch information found!') - if ARCH: - info('System architecture: ' + color('GOOD', ARCH)) + arch = os.uname()[4] + if arch: + info('System architecture: ' + color('GOOD', arch)) else: error('No system architecture found!') sys.exit() print '\n>>> Reading kernel vulnerabilities' - if CVE: - info(color('GOOD', str(CVE[0])) + ' files read') - info(color('GOOD', str(CVE[1])) + ' match this system') - info(color('GOOD', str(CVE[2])) + ' haven been fixed') + cve = [345, 284, 274, 0, 4] #TODO: Implement + use dict! + if cve: + info(color('GOOD', str(cve[0])) + ' files read') + info(color('GOOD', str(cve[1])) + ' match this system') + info(color('GOOD', str(cve[2])) + ' haven been fixed') - if CVE[3]: - warn(str(CVE[3]) + ' could be fixed by upgrading') + if cve[3]: + warn(str(cve[3]) + ' could be fixed by upgrading') else: info('No vulnerability could be fixed by upgrading') - if CVE[4]: - warn(str(CVE[4]) + ' have not been fixed yet') + if cve[4]: + warn(str(cve[4]) + ' have not been fixed yet') else: info('No vulnerability have not been fixed yet') @@ -97,7 +94,9 @@ def main(argv): error('No vulnerability files found!') sys.exit() - if not CVE[3]: + + if not cve[3]: + best = lib.best_version(kernel['source']) info('') info('These could be fixed by upgrading:') info('') @@ -108,7 +107,7 @@ def main(argv): info('$ ' + sys.argv[0] + ' -i [id]') info('') info('Upgrading to the latest version') - info('[' + color('GOOD', BEST) + ']') + info('[' + color('GOOD', best) + ']') info('is recommended!') else: info('') @@ -118,14 +117,14 @@ def main(argv): def usage(): 'Prints the usage screen' - print 'Usage: ' + sys.argv[0][:-3] + ' [OPTION]...' + print 'Usage: %s [OPTION]...' % sys.argv[0][:-3] print 'Kernel security information\r\n' print ' -h, --help display help information' print ' -n, --nocolor disable colors' print ' -r, --report [file] create a security report' print ' -s, --show [bugid] display information about a bug' print ' -v, --verbose display debugging information' - print '\r\nVersion: 0.3' + print '\r\nVersion: %s' % lib.VERSION print 'Copyright (C) 2009 Bjoern Tropf ' print 'Copyright (C) 2009 Robert Buchholz ' sys.exit() diff --git a/kernellib.py b/kernellib.py index 317142b..be95a70 100755 --- a/kernellib.py +++ b/kernellib.py @@ -57,6 +57,7 @@ GENERAL_KERNEL_TYPES = ['aa', 'acpi', 'ac', 'alpha', 'arm', 'as', 'cell', 'ck', GENTOO_KERNEL_TYPES = ['cell', 'mips', 'tuxonice', 'mm', 'usermode', 'gentoo', 'vanilla', 'git', 'openvz', 'vserver', 'hardened', 'sh', 'xbox', 'sparc', 'xen'] +VERSION = '0.4' VERBOSE = False FORCE = False @@ -244,29 +245,55 @@ def parse_bugzilla_list(filename): return buglist +#TODO: Short Code, use Vulnerability directly instead of dic def parse_bugzilla_dict(directory, bugid): - 'Returns a dictionary containing information about a kernel vulnerability' + 'Returns a vulnerability containing information about a kernel vulnerability' #FIXME: Sounds strange bugfilename = os.path.join(directory, bugid) root = et.parse(open(bugfilename, 'r')).getroot()[0] - elements = ['bug_id', 'creation_ts', 'reporter', 'status_whiteboard', 'short_desc', 'rep_platform'] + elem = ['bug_id', 'reporter', 'creation_ts', 'rep_platform', 'status_whiteboard', 'short_desc'] dic = dict() - for i in elements: - if i == 'short_desc': - cves = extract_cves(root.find(i).text) + for item in elem: + if item == 'short_desc': + cves = extract_cves(root.find(item).text) if len(cves) > 0: dic['cves'] = cves else: error('Invalid cve for bugid [%s]' % root.find('bug_id').text) - error('-> ' + root.find(i).text) + error('-> ' + root.find(item).text) try: - dic[i] = root.find(i).text + dic[item] = root.find(item).text except AttributeError: - dic[i] = None + dic[item] = None - return dic + interval = from_whiteboard(dic['status_whiteboard']) + vul = Vulnerability(dic['cves'], dic[elem[0]], dic[elem[1]], dic[elem[2]], dic[elem[3]], interval) + + return vul + + +def search_nvd_dict(dic, vul): #TODO: Rename + #TODO: Description + + cves = list() + + for item in vul.cvelist: + cve = Cve(item, + dic[item]['published'], + dic[item]['desc'], + dic[item]['severity'], + dic[item]['CVSS_vector'], + dic[item]['CVSS_score'], + dic[item]['refs']) + #TODO: bugref.set('url', 'https://bugs.gentoo.org/show_bug.cgi?id=' + bug_dict['bug_id']) + #TODO: bugref.text = 'Gentoo bug #%s' % (bug_dict['bug_id'],) + + cves.append(cve) + vul.cves = cves + + return vul def parse_nvd_dict(directory): @@ -299,7 +326,7 @@ def parse_nvd_dict(directory): reftree.tag = reftree.tag.replace(namespace, '') for elem in reftree.findall('.//*'): elem.tag = elem.tag.replace(namespace, '') - dic['refs'] = reftree + dic['refs'] = reftree #TODO: Rework! Use dict instead desc = tree.find(''.join(namespace + tag + '/' for tag in ('desc', 'descript'))) if desc != None: @@ -348,73 +375,44 @@ def read_cve_file(): return -#TODO: Deprecated, create a vulnerability class -def write_cve_file(directory, bugid, bug_dict, nvd_dict): +def write_cve_file(directory, vul): 'Write a bug file containing all important information for kernel-check' - filename = os.path.join(directory, bugid + '.xml') + filename = os.path.join(directory, vul.bugid + '.xml') - bug_order = ['id', 'reporter', 'reported', 'arch', 'affected'] - cve_order = ['id', 'published', 'desc', 'severity', 'vector', 'score', 'refs'] + bug_order = ['bugid', 'reporter', 'reported', 'arch', 'affected'] #FIXME + cve_order = ['published', 'desc', 'severity', 'vector', 'score', 'refs'] #FIXME root = et.Element('vulnerability') - - try: - cves = bug_dict['cves'] - - xml_bug_dict = { - 'arch' : bug_dict['rep_platform'], - 'id' : bug_dict['bug_id'], - 'reporter' : bug_dict['reporter'], - 'reported' : bug_dict['creation_ts'] - } - - except KeyError: - return - bugroot = et.SubElement(root, 'bug') for element in bug_order: if element == 'affected': affectedroot = et.SubElement(bugroot, 'affected') - intervals = from_whiteboard(bug_dict['status_whiteboard']) - if intervals: - for item in intervals: + if vul.interval: + for item in vul.interval: item.to_xml(affectedroot) else: - error('Whiteboard for bugid [%s]' % bug_dict['bug_id']) - error('-> %s' % bug_dict['status_whiteboard']) + error('Whiteboard for bugid [%s]' % vul.bugid) + error('-> %s' % vul.interval) else: node = et.SubElement(bugroot, element) - node.text = xml_bug_dict[element] - - for enum, cve in enumerate(cves): - try: - xml_cve_dic = { - 'desc' : nvd_dict[cve]['desc'], - 'id' : cve, - 'published' : nvd_dict[cve]['published'], - 'severity' : nvd_dict[cve]['severity'], - 'score' : nvd_dict[cve]['CVSS_score'], - 'refs' : nvd_dict[cve]['refs'], - 'vector' : nvd_dict[cve]['CVSS_vector'] - } - - except KeyError: - break + node.text = getattr(vul, element) + for cve in vul.cves: cveroot = et.SubElement(root, 'cve') for element in cve_order: if element == 'refs': - reftree = xml_cve_dic[element] - cveroot.append(xml_cve_dic[element]) - bugref = et.SubElement(reftree, 'ref') - bugref.set('url', 'https://bugs.gentoo.org/show_bug.cgi?id=' + bug_dict['bug_id']) - bugref.text = 'Gentoo bug #%s' % (bug_dict['bug_id'],) + reftree = cve.refs + cveroot.append(cve.refs) + bugref = et.SubElement(reftree, 'ref') #FIXME: Add this information earlier + bugref.set('url', 'https://bugs.gentoo.org/show_bug.cgi?id=%s' % vul.bugid) + bugref.set('source', 'GENTOO') + bugref.text = 'Gentoo bug #%s' % vul.bugid else: node = et.SubElement(cveroot, element) - node.text = xml_cve_dic[element] + node.text = getattr(cve, element) write_xml(root, filename) @@ -430,7 +428,36 @@ def write_xml(root, filename): doc.write(xmlout, encoding='utf-8') -class IntervalEntry: +class Vulnerability: + #TODO: Description + + def __init__(self, cvelist, bugid, reporter, reported, arch, interval, cves = None): + #TODO: Description + + self.cvelist = cvelist + self.bugid = bugid + self.reporter = reporter + self.reported = reported + self.arch = arch + self.interval = interval + self.cves = cves + + +class Cve: + #TODO: Description + + def __init__(self, cve, published, desc, severity, vector, score, refs): + #TODO: Description + self.cve = cve + self.published = published + self.desc = desc + self.severity = severity + self.vector = vector + self.score = score + self.refs = refs + + +class Interval: 'Defines an interval for kernel ebuilds' def __init__(self, name, lower, upper, lower_inclusive, upper_inclusive, expand): @@ -591,7 +618,7 @@ def from_whiteboard(whiteboard): if version and not REGEX['wb_version'].match(version): return False - affected.append(IntervalEntry(name, wb['lower'], wb['upper'], wb['lower_inc'], wb['upper_inc'], wb['expand'])) + affected.append(Interval(name, wb['lower'], wb['upper'], wb['lower_inc'], wb['upper_inc'], wb['expand'])) whiteboard = match.group(7) return affected -- cgit v1.2.3-65-gdbad