From c26be832b8724928ada8a9be04d86f89559f23e6 Mon Sep 17 00:00:00 2001 From: Bjoern Tropf Date: Mon, 14 Dec 2009 12:01:59 +0100 Subject: Implement -k/--kernel $(uname -r) Fix several bugs Change licence date Cleanup --- TODO | 7 ++- bin/kernel-check | 2 +- pym/kernelcheck/kernelcheck.py | 133 ++++++++++++++++++--------------------- pym/kernelcheck/lib/kernellib.py | 30 ++++----- setup.py | 2 +- tools/cron.py | 22 +++---- tools/findcommit.sh | 4 +- 7 files changed, 92 insertions(+), 108 deletions(-) diff --git a/TODO b/TODO index 23973d6..15a81b0 100644 --- a/TODO +++ b/TODO @@ -1,10 +1,10 @@ - Implement Report - Implement the testsuite -- Implement kernel testing framework +- Implement a kernel testing framework - Find a way to import '-' or '_' modules - Handle "best kernel not found" - Add further error handling -- Implement hardend/xen interval +- Implement hardend and xen - Add parameters to cron.py - Rework interval class - Split up cves.refs @@ -18,3 +18,6 @@ - Port cron.py to python3 - Move genpatch to kernel class - Fix userland arch <> kernel arch +- Implement Verbose +- Fix GENERIC-MAP-NOMATCH output + diff --git a/bin/kernel-check b/bin/kernel-check index cf8d8d0..f05027e 100644 --- a/bin/kernel-check +++ b/bin/kernel-check @@ -1,6 +1,6 @@ #!/usr/bin/env python # kernel-check -- Gentoo Kernel Security -# Copyright 2009-2009 Gentoo Foundation +# Copyright 2009-2010 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 import sys diff --git a/pym/kernelcheck/kernelcheck.py b/pym/kernelcheck/kernelcheck.py index e7a7ded..bacbdbc 100755 --- a/pym/kernelcheck/kernelcheck.py +++ b/pym/kernelcheck/kernelcheck.py @@ -1,89 +1,84 @@ #!/usr/bin/env python # kernel-check -- Gentoo Kernel Security -# Copyright 2009-2009 Gentoo Foundation +# Copyright 2009-2010 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -from portage.output import blue, bold, colorize, EOutput, darkgreen, teal #TODO +from portage.output import blue, bold, colorize, EOutput, darkgreen, teal try: from _emerge.userquery import userquery - from _emerge.stdout_spinner import stdout_spinner + from _emerge.stdout_spinner import stdout_spinner as spinner except ImportError: from _emerge import userquery - from _emerge import stdout_spinner + from _emerge import stdout_spinner as spinner import getopt +import os import portage import sys import textwrap -import os - import lib.kernellib as lib -info = EOutput().einfo #FIXME -warn = EOutput().ewarn -error = EOutput().eerror -spin = stdout_spinner() def main(argv): 'Main function' + for arg in argv: + if lib.REGEX['argument'].match(arg): + print_bug(arg) + return + try: - opts, args = getopt.gnu_getopt(argv, 'dhnr:sv', - ['debug', 'help', 'nocolor', 'report=', 'sync', 'verbose']) - except getopt.GetoptError: - usage() + opts, args = getopt.gnu_getopt(argv, 'dhk:nr:sv', + ['debug', 'help', 'kernel=', 'nocolor', 'report=', 'sync', 'verbose']) + except getopt.GetoptError, e: + EOutput().eerror('Invalid argument: %s' % e) #TODO invalid bugid, cve return + kernel = None + arg_kernel = None for opt, arg in opts: if opt in ('-d', '--debug'): lib.DEBUG = True elif opt in ('-h', '--help'): usage() return + elif opt in ('-k', '--kernel'): + arg_kernel = arg + kernel = lib.extract_version(arg) elif opt in ('-n', '--nocolor'): portage.output.nocolor() elif opt in ('-r', '--report'): - error('--report not yet implemented') + EOutput().eerror('--report not yet implemented') return elif opt in ('-s', '--sync'): os.system('%s%s' % ('rsync -avz rsync://rbu.sh/gentoo-kernel ', '/usr/portage/metadata/kernel')) return elif opt in ('-v', '--verbose'): - lib.VERBOSE = True - - for arg in argv: - if lib.REGEX['argument'].match(arg): - if 'cve' in arg.lower(): - vul = lib.find_cve(arg, lib.DIR['out']) - if not vul: - print_bug(arg) #FIXME - else: - print_bug(vul.bugid) - else: - print_bug(arg) - return - - information = dict() - - print('') - print(darkgreen('These are the specifications of your kernel:')) - print('') + pass #TODO Implement uname = os.uname() - if uname[0] != 'Linux': - error('This tool currently only works for Linux kernels.') - error('Apparantly you are using "%s".' % uname[0]) #TODO + if uname[0].lower() != 'linux': + EOutput().eerror('This tool only works for linux kernels.') + EOutput().eerror('Apparently you are using "%s".' % uname[0]) return - kernel = lib.extract_version(uname[2]) - if kernel is None: - error('No kernel information found!') - return + if arg_kernel is not None: + if kernel is None: + EOutput().eerror('The kernel you specified could not be found.') + EOutput().eerror('Your specification is "%s".' % arg_kernel) + return + else: + kernel = lib.extract_version(uname[2]) + if kernel is None: + EOutput().eerror('Your kernel could not be identified.') + return + + print(darkgreen('\nThese are the specifications of your kernel:')) arch = portage.settings['ARCH'] - if not arch: + if arch: kernel.arch = '?' else: kernel.arch = arch @@ -101,41 +96,35 @@ def main(argv): repr(kernel.genpatch)) if kernel.genpatch else ''), 'Architecture' : kernel.arch } - print_items(information, 'Information') - print('') + print_items(information, 'Information') print_items(lib.gather_configuration(), 'Configuration') - print('') - print('Determining vulnerabilities... '), + print('\nDetermining vulnerabilities... '), - evaluation = lib.eval_cve_files(lib.DIR['out'], kernel, spin) + evaluation = lib.eval_cve_files(lib.KERNELDIR, kernel, spinner()) if not evaluation: - error('No kernel vulnerability files found!') #TODO + print("\b\b done!\n") + EOutput().eerror('No kernel vulnerability files found!') return - kernel_updates = lib.eval_kernel_updates(kernel, evaluation, spin) - - print("\b\b done!") + kernel_updates = lib.eval_kernel_updates(kernel, evaluation, spinner()) - print('') + print("\b\b done!\n") if len(evaluation.affected) is not 0: print_summary(evaluation.affected, kernel_updates) - print('Total: %s vulnerabilities (%s), Average CVSS score: %.1f' % ( + print('\nTotal: %s vulnerabilities (%s), Average CVSS score: %.1f' % ( len(evaluation.affected), repr(evaluation), evaluation.avg_cvss)) if kernel_updates: print('Kernel updates:') - for key in kernel_updates.keys(): + for key in sorted(kernel_updates.keys()): print(' %s %s' % (teal('[%s]' % kernel_updates[key]), key)) - print('') - prompt = "Would you like to upgrade your kernel?" + prompt = "\nWould you like to upgrade your kernel?" if userquery(prompt, None) == 'No': - print('') - print('Quitting.') - print('') + print('\nQuitting.\n') else: print('Not implemented yet...') @@ -152,7 +141,8 @@ def print_items(category, header): if portage.output.get_term_size()[1] < screenwidth: screenwidth = portage.output.get_term_size()[1] - info(bold('%s:' % header)) + print('') + EOutput().einfo(bold('%s:' % header)) for item in category.keys(): for i, string in enumerate(textwrap.wrap('%s' % category[item], (screenwidth - 23))): @@ -176,8 +166,8 @@ def print_summary(vullist, kernel_updates): if 'AV:A' in cve.vector or 'AV:N' in cve.vector: cvetype += colorize('BAD', 'network') - if ('C:P' in cve.vector or 'C:C' in cve.vector) \ - and ('I:P' in cve.vector or 'I:C' in cve.vector) \ + if ('C:P' in cve.vector or 'C:C' in cve.vector) \ + and ('I:P' in cve.vector or 'I:C' in cve.vector) \ and ('A:P' in cve.vector or 'A:C' in cve.vector): cvetype += '%s%s' % (' ', blue('-complete')) else: @@ -196,9 +186,7 @@ def print_summary(vullist, kernel_updates): print('[%s %26s] %s %s TYPE="%s" %s') % (darkgreen('bugid'), colorize('GOOD', item.bugid), darkgreen(cve.cve), - blue('[%s]' % cve.score), cvetype, index) - - print('') + blue('[%4s]' % cve.score), cvetype, index) def print_bug(bugid): @@ -208,10 +196,10 @@ def print_bug(bugid): print_cve(bugid.upper()) return - vul = lib.read_cve_file(lib.DIR['out'], bugid) + vul = lib.read_cve_file(lib.KERNELDIR, bugid) if vul is None: - error('Could not find bugid: %s' % bugid) + EOutput().eerror('Could not find bugid: %s' % bugid) return buginformation = { @@ -222,7 +210,6 @@ def print_bug(bugid): 'Architecture' : vul.arch.capitalize() } - print('') print_items(buginformation, 'Bugid %s' % bugid) for cve in vul.cves: @@ -233,9 +220,9 @@ def print_cve(cveid): 'Prints information about a cve' cve = lib.Cve(cveid) - vul = lib.find_cve(cveid, lib.DIR['out']) #FIXME + vul = lib.find_cve(cveid, lib.KERNELDIR) if vul is None: - error('Could not find cve: %s' % cveid) + EOutput().eerror('Could not find cve: %s' % cveid) return else: for item in vul.cves: @@ -251,15 +238,14 @@ def print_cve(cveid): } #TODO print cve.refs - print('') print_items(cveinformation, cve.cve) def print_information(): 'Prints an information message' - info('To print more information about a vulnerability try:') - info(' $ %s [BUGID|CVE]' % sys.argv[0]) + EOutput().einfo('To print more information about a vulnerability try:') + EOutput().einfo(' $ %s [BUGID|CVE]' % sys.argv[0]) def usage(): @@ -269,6 +255,7 @@ def usage(): print('Gentoo Kernel Security %s\n' % lib.VERSION) print(' -d, --debug display debugging information') print(' -h, --help display help information') + print(' -k, --kernel specify a kernel') print(' -n, --nocolor disable colors') print(' -r, --report [file] create a security report') print(' -s, --sync receive the latest vulnerabilities') diff --git a/pym/kernelcheck/lib/kernellib.py b/pym/kernelcheck/lib/kernellib.py index c95252e..f9ec9c5 100644 --- a/pym/kernelcheck/lib/kernellib.py +++ b/pym/kernelcheck/lib/kernellib.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # kernel-check -- Gentoo Kernel Security -# Copyright 2009-2009 Gentoo Foundation +# Copyright 2009-2010 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 import inspect @@ -44,14 +44,8 @@ KERNEL_TYPES = [ VERSION = '0.3.15' DEBUG = False -FILEPATH = os.path.dirname(os.path.realpath(__file__)) PORTDIR = portage.settings['PORTDIR'] -DIR = { - 'tmp' : os.path.join(FILEPATH, 'tmp'), - 'out' : os.path.join(PORTDIR, 'metadata', 'kernel'), - 'bug' : os.path.join(FILEPATH, 'tmp', 'bug'), - 'nvd' : os.path.join(FILEPATH, 'tmp', 'nvd') -} +KERNELDIR = os.path.join(PORTDIR, 'metadata', 'kernel') def BUG_ON(msg, e): if DEBUG: @@ -317,10 +311,10 @@ def is_in_interval(interval, kernel, bugid=None): version = kernel.version.replace('-', '.') elif interval.name == 'hardened': - version = kernel.version #TODO is this correct? + version = kernel.version #TODO implement elif interval.name == 'xen': - version = kernel.version #TODO is this correct? + version = kernel.version #TODO implement elif interval.name == 'vserver': return False @@ -426,7 +420,7 @@ def find_cve(cve, directory): return None -def eval_cve_files(directory, kernel, spin=None): +def eval_cve_files(directory, kernel, spinner=None): 'Returns a vulnerabilty evaluation' files = parse_cve_files(directory) @@ -439,8 +433,8 @@ def eval_cve_files(directory, kernel, spin=None): evaluation = Evaluation() for item in files: - if spin: - spin.update() + if spinner: + spinner.update() evaluation.read += 1 if item.arch not in ARCHES: @@ -515,7 +509,7 @@ def is_affected(interval_list, kernel, item): kernel_affected = True else: kernel_affected = False - #TODO Implement else for hardend/xen/expand + #TODO Implement else for hardend and xen return kernel_affected @@ -650,19 +644,19 @@ def all_version(source): return versions -def eval_kernel_updates(kernel, kernel_eval, spin): +def eval_kernel_updates(kernel, kernel_eval, spinner): "" index = 0 kernel_dict = dict() for compare in all_version(kernel.source): - if compare.version > kernel.version or \ - (compare.version == kernel.version and \ + if compare.version > kernel.version or \ + (compare.version == kernel.version and \ compare.revision > kernel.revision): compare.arch = kernel.arch compare.genpatch = get_genpatch(PORTDIR, compare) - compare_eval = eval_cve_files(DIR['out'], compare, spin) + compare_eval = eval_cve_files(DIR['out'], compare, spinner) comparison = compare_evaluation(kernel_eval, compare_eval) for item in comparison.fixed: diff --git a/setup.py b/setup.py index 67c1e6c..6a14c92 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # kernel-check -- Gentoo Kernel Security -# Copyright 2009-2009 Gentoo Foundation +# Copyright 2009-2010 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 from distutils.core import setup diff --git a/tools/cron.py b/tools/cron.py index 770e9aa..85228e4 100755 --- a/tools/cron.py +++ b/tools/cron.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # kernel-check -- Gentoo Kernel Security -# Copyright 2009-2009 Gentoo Foundation +# Copyright 2009-2010 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 from contextlib import closing @@ -41,9 +41,9 @@ CONST = { PENDING = { 'published' : '0000-00-00', - 'desc' : 'This PENDING identifier specifies all vulnerabilities ' \ + 'desc' : 'This PENDING identifier specifies all vulnerabilities ' \ 'which are not approved yet. PENDING is used by products, ' \ - 'databases, and services to specify when a particular ' \ + 'databases, and services to specify when a particular ' \ 'vulnerability element has been proposed as CVE entry.', 'severity' : 'Low', 'vector' : '()', @@ -54,10 +54,10 @@ PENDING = { NOMATCH = { 'cve' : 'GENERIC-MAP-NOMATCH', 'published' : '0000-00-00', - 'desc' : 'This GENERIC identifier is not specific to any ' \ - 'vulnerability. GENERIC-MAP-NOMATCH is used by products, ' \ - 'databases, and services to specify when a particular ' \ - 'vulnerability element does not map to a corresponding ' \ + 'desc' : 'This GENERIC identifier is not specific to any ' \ + 'vulnerability. GENERIC-MAP-NOMATCH is used by products, ' \ + 'databases, and services to specify when a particular ' \ + 'vulnerability element does not map to a corresponding ' \ 'CVE entry.', 'severity' : 'Low', 'vector' : '()', @@ -80,10 +80,10 @@ REGEX = { 'grp_all' : re.compile(r'(?<=\()[ (]*CVE-(\d{4})([-,(){}|, \d]+)(?=\))'), 'grp_split' : re.compile(r'(?<=\D)(\d{4})(?=\D|$)'), 'm_nomatch' : re.compile(r'.*GENERIC-MAP-NOMATCH.*'), - 'wb_match' : re.compile(r'\s*\[\s*([^ +<=>]+)\s*([<=>]{1,2})' \ - r'\s*([^ <=>\]]+)\s*(?:([<=>]{1,2})' \ + 'wb_match' : re.compile(r'\s*\[\s*([^ +<=>]+)\s*([<=>]{1,2})' \ + r'\s*([^ <=>\]]+)\s*(?:([<=>]{1,2})' \ r'\s*([^ \]]+))?\s*\]\s*(.*)'), - 'wb_vers' : re.compile(r'^(?:\d{1,2}\.){0,3}\d{1,2}' \ + 'wb_vers' : re.compile(r'^(?:\d{1,2}\.){0,3}\d{1,2}' \ r'(?:[-_](?:r|rc)?\d{1,2})*$') } @@ -137,7 +137,7 @@ def main(argv): logging.info('Receiving the kernel vulnerability list from bugzilla') - url = [CONST['bzurl'], 'buglist.cgi?query_format=advanced' \ + url = [CONST['bzurl'], 'buglist.cgi?query_format=advanced' \ '&component=Kernel'] for item in CONST['state']: diff --git a/tools/findcommit.sh b/tools/findcommit.sh index 770078b..be1814f 100755 --- a/tools/findcommit.sh +++ b/tools/findcommit.sh @@ -1,6 +1,6 @@ #!/bin/sh -# kernel-check -- Kernel security information -# Copyright 2009-2009 Gentoo Foundation +# kernel-check -- Gentoo Kernel Security +# Copyright 2009-2010 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 TEXT=".*$@.*" -- cgit v1.2.3-65-gdbad