From patchwork Thu Nov 9 05:09:33 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tobin Harding X-Patchwork-Id: 10050121 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 7307B602D7 for ; Thu, 9 Nov 2017 05:11:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 610712AA63 for ; Thu, 9 Nov 2017 05:11:07 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 556112AAF1; Thu, 9 Nov 2017 05:11:07 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id 9D6592AAEF for ; Thu, 9 Nov 2017 05:11:05 +0000 (UTC) Received: (qmail 3363 invoked by uid 550); 9 Nov 2017 05:10:26 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 3183 invoked from network); 9 Nov 2017 05:10:24 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tobin.cc; h=cc :date:from:in-reply-to:message-id:references:subject:to :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; bh=lkWkBM2uwp/oEqpL2 SGAYOpllDY46GU2lwPSux6yiCo=; b=DPjORHXU84oMhRjvwYg+l/Ss3Y03Iq1hp 2CZC71Ltgv5RzFn6yIt85F7MIPvwkhWNM/1qutvqvhi5+gAx5xcQk4Dj542hR6F2 zvb/1eyPwh/NTAYunwEshNFJdFhzBAYkKxHHdSMUZCBz+EhkIb2trY6vhiGvFmkQ +odSlXzv+GVQyC3hkXeKpEWgxLazduSWDoMcFYynT+p5TxmcwYHaXFVyPckPqSfg oH+xcRytGuYLsr3tO+DIHZ64K8HoBxcjZxj444tpILhIsyJHUJZ7cLj6fDPWb3ck tc0eWXhYygPYtt3CedGIxCdB/jiTvGs8LLHSPy2l1tCNt5H4vjLng== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:date:from:in-reply-to:message-id :references:subject:to:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; bh=lkWkBM2uwp/oEqpL2SGAYOpllDY46GU2lwPSux6yiCo=; b=EvPodfUO Zidfj7K8UGJbeVTmhqWOsTQLuCm5zT4lSB0hpCtIGxyxI/D0ill8yLaJgkeKauQK eD2Lc6kD7U3Wrj3mgmY1rhWFQjqzBUZBzjJBzOIYQRRpMEqC2AbzPpmCo5U5QX57 Z3s22FiOMvgecVqrCRWwYMWY+wvIE1o63I4+i+Axi0OoNu+ua2oHZf6uCLAZFqbr lUAXLw9Ar638iQcblFH+fw3+Eidnnh3xSEprUGKUklGqHlJhRb/Y1o3yFg2wT/mW 0kg4o8aAmuEHhnlPBThDwGK5mbdb0Y1KGI3Pw6+2Fr8jO1v3POa3L4f2uxnP/SQk Hu6iJ/T0ZMy4Kg== X-ME-Sender: From: "Tobin C. Harding" To: Linus Torvalds Cc: "Tobin C. Harding" , "Jason A. Donenfeld" , Theodore Ts'o , Kees Cook , Paolo Bonzini , Tycho Andersen , "Roberts, William C" , Tejun Heo , Jordan Glover , Greg KH , Petr Mladek , Joe Perches , Ian Campbell , Sergey Senozhatsky , Catalin Marinas , Will Deacon , Steven Rostedt , Chris Fries , Dave Weinstein , Daniel Micay , Djalal Harouni , "Paul E. McKenney" , Andy Lutomirski , Peter Zijlstra , Michael Ellerman , David Miller , Network Development , linux-kernel@vger.kernel.org, kernel-hardening@lists.openwall.com Date: Thu, 9 Nov 2017 16:09:33 +1100 Message-Id: <1510204175-10138-7-git-send-email-me@tobin.cc> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1510204175-10138-1-git-send-email-me@tobin.cc> References: <1510204175-10138-1-git-send-email-me@tobin.cc> Subject: [kernel-hardening] [PATCH v2 6/8] scripts/leaking_addresses: add summary reporting X-Virus-Scanned: ClamAV using ClamSMTP Currently script just dumps all results found. Potentially, this risks losing single results among multiple duplicate results. We need some way of restricting duplicates to assist users of the script. It would also be nice if we got a report instead of raw results. Duplicates can be defined in various ways, instead of trying to find a single perfect solution we can present the user with various options to display the output. Doing so will typically lead to users wanting to view the output multiple times. Currently we scan the kernel each time, this is slow and unnecessary. We can expedite the process by writing the results to file for subsequent viewing. Add command line options to enable summary reporting, including options to write to and read from file. Signed-off-by: Tobin C. Harding --- scripts/leaking_addresses.pl | 191 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 188 insertions(+), 3 deletions(-) diff --git a/scripts/leaking_addresses.pl b/scripts/leaking_addresses.pl index 0aac03a020a8..4610ad3c80c2 100755 --- a/scripts/leaking_addresses.pl +++ b/scripts/leaking_addresses.pl @@ -31,6 +31,13 @@ my @DIRS = ('/proc', '/sys'); # Command line options. my $help = 0; my $debug = 0; +my $raw = 0; +my $output_raw = ""; # Write raw results to file. +my $input_raw = ""; # Read raw results from file instead of scanning. + +my $suppress_dmesg = 0; # Don't show dmesg in output. +my $squash_by_path = 0; # Summary report grouped by absolute path. +my $squash_by_filename = 0; # Summary report grouped by filename. # Do not parse these files (absolute path). my @skip_parse_files_abs = ('/proc/kmsg', @@ -73,13 +80,31 @@ sub help my ($exitcode) = @_; print << "EOM"; + Usage: $P [OPTIONS] Version: $V Options: - -d, --debug Display debugging output. - -h, --help, --version Display this help and exit. + -o, --output-raw= Save results for future processing. + -i, --input-raw= Read results from file instead of scanning. + --raw Show raw results (default). + --suppress-dmesg Do not show dmesg results. + --squash-by-path Show one result per unique path. + --squash-by-filename Show one result per unique filename. + -d, --debug Display debugging output. + -h, --help, --version Display this help and exit. + +Examples: + + # Scan kernel and dump raw results. + $0 + + # Scan kernel and save results to file. + $0 --output-raw scan.out + + # View summary report. + $0 --input-raw scan.out --squash-by-filename Scans the running (64 bit) kernel for potential leaking addresses. @@ -90,11 +115,33 @@ EOM GetOptions( 'd|debug' => \$debug, 'h|help' => \$help, - 'version' => \$help + 'version' => \$help, + 'o|output-raw=s' => \$output_raw, + 'i|input-raw=s' => \$input_raw, + 'suppress-dmesg' => \$suppress_dmesg, + 'squash-by-path' => \$squash_by_path, + 'squash-by-filename' => \$squash_by_filename, + 'raw' => \$raw, ) or help(1); help(0) if ($help); +if ($input_raw) { + format_output($input_raw); + exit(0); +} + +if (!$input_raw and ($squash_by_path or $squash_by_filename)) { + printf "\nSummary reporting only available with --input-raw=\n"; + printf "(First run scan with --output-raw=.)\n"; + exit(128); +} + +if ($output_raw) { + open my $fh, '>', $output_raw or die "$0: $output_raw: $!\n"; + select $fh; +} + parse_dmesg(); walk(@DIRS); @@ -239,3 +286,141 @@ sub walk } } } + +sub format_output +{ + my ($file) = @_; + + # Default is to show raw results. + if ($raw or (!$squash_by_path and !$squash_by_filename)) { + dump_raw_output($file); + return; + } + + my ($total, $dmesg, $paths, $files) = parse_raw_file($file); + + printf "\nTotal number of results from scan (incl dmesg): %d\n", $total; + + if (!$suppress_dmesg) { + print_dmesg($dmesg); + } + + if ($squash_by_filename) { + squash_by($files, 'filename'); + } + + if ($squash_by_path) { + squash_by($paths, 'path'); + } +} + +sub dump_raw_output +{ + my ($file) = @_; + + open (my $fh, '<', $file) or die "$0: $file: $!\n"; + while (<$fh>) { + if ($suppress_dmesg) { + if ("dmesg:" eq substr($_, 0, 6)) { + next; + } + } + print $_; + } + close $fh; +} + +sub parse_raw_file +{ + my ($file) = @_; + + my $total = 0; # Total number of lines parsed. + my @dmesg; # dmesg output. + my %files; # Unique filenames containing leaks. + my %paths; # Unique paths containing leaks. + + open (my $fh, '<', $file) or die "$0: $file: $!\n"; + while (my $line = <$fh>) { + $total++; + + if ("dmesg:" eq substr($line, 0, 6)) { + push @dmesg, $line; + next; + } + + cache_path(\%paths, $line); + cache_filename(\%files, $line); + } + + return $total, \@dmesg, \%paths, \%files; +} + +sub print_dmesg +{ + my ($dmesg) = @_; + + print "\ndmesg output:\n"; + + if (@$dmesg == 0) { + print "\n"; + return; + } + + foreach(@$dmesg) { + my $index = index($_, ': '); + $index += 2; # skid ': ' + print substr($_, $index); + } +} + +sub squash_by +{ + my ($ref, $desc) = @_; + + print "\nResults squashed by $desc (excl dmesg). "; + print "Displaying [ <$desc>], \n"; + + if (keys %$ref == 0) { + print "\n"; + return; + } + + foreach(keys %$ref) { + my $lines = $ref->{$_}; + my $length = @$lines; + printf "[%d %s] %s", $length, $_, @$lines[0]; + } +} + +sub cache_path +{ + my ($paths, $line) = @_; + + my $index = index($line, ': '); + my $path = substr($line, 0, $index); + + $index += 2; # skip ': ' + add_to_cache($paths, $path, substr($line, $index)); +} + +sub cache_filename +{ + my ($files, $line) = @_; + + my $index = index($line, ': '); + my $path = substr($line, 0, $index); + my $filename = basename($path); + + $index += 2; # skip ': ' + add_to_cache($files, $filename, substr($line, $index)); +} + +sub add_to_cache +{ + my ($cache, $key, $value) = @_; + + if (!$cache->{$key}) { + $cache->{$key} = (); + } + push @{$cache->{$key}}, $value; +}