History

leaking_addresses: add summary reporting options

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.

Tobin C. Harding committed 9 years ago

Commit d09bd8d1 parent 1c1e3be1 file · +188 −3Browse files

Showing the changes to scripts (1 of 1 file). Show all

Unified · Split

scripts/leaking_addresses.pl+188−3
@@ -31,6 +31,13 @@ my @DIRS = ('/proc', '/sys'); · 30 unmodified lines
3131 # Command line options.
3232 my $help = 0;
3333 my $debug = 0;
34+my $raw = 0;
35+my $output_raw = ""; # Write raw results to file.
36+my $input_raw = ""; # Read raw results from file instead of scanning.
37+
38+my $suppress_dmesg = 0; # Don't show dmesg in output.
39+my $squash_by_path = 0; # Summary report grouped by absolute path.
40+my $squash_by_filename = 0; # Summary report grouped by filename.
3441
3542 # Do not parse these files (absolute path).
3643 my @skip_parse_files_abs = ('/proc/kmsg',
@@ -73,13 +80,31 @@ sub help · 36 unmodified lines
7380 my ($exitcode) = @_;
7481
7582 print << "EOM";
83+
7684 Usage: $P [OPTIONS]
7785 Version: $V
7886
7987 Options:
8088
81− -d, --debug Display debugging output.
82− -h, --help, --version Display this help and exit.
89+ -o, --output-raw=<file> Save results for future processing.
90+ -i, --input-raw=<file> Read results from file instead of scanning.
91+ --raw Show raw results (default).
92+ --suppress-dmesg Do not show dmesg results.
93+ --squash-by-path Show one result per unique path.
94+ --squash-by-filename Show one result per unique filename.
95+ -d, --debug Display debugging output.
96+ -h, --help, --version Display this help and exit.
97+
98+Examples:
99+
100+ # Scan kernel and dump raw results.
101+ $0
102+
103+ # Scan kernel and save results to file.
104+ $0 --output-raw scan.out
105+
106+ # View summary report.
107+ $0 --input-raw scan.out --squash-by-filename
83108
84109 Scans the running (64 bit) kernel for potential leaking addresses.
85110
@@ -90,11 +115,33 @@ EOM · 4 unmodified lines
90115 GetOptions(
91116 'd|debug' => \$debug,
92117 'h|help' => \$help,
93− 'version' => \$help
118+ 'version' => \$help,
119+ 'o|output-raw=s' => \$output_raw,
120+ 'i|input-raw=s' => \$input_raw,
121+ 'suppress-dmesg' => \$suppress_dmesg,
122+ 'squash-by-path' => \$squash_by_path,
123+ 'squash-by-filename' => \$squash_by_filename,
124+ 'raw' => \$raw,
94125 ) or help(1);
95126
96127 help(0) if ($help);
97128
129+if ($input_raw) {
130+ format_output($input_raw);
131+ exit(0);
132+}
133+
134+if (!$input_raw and ($squash_by_path or $squash_by_filename)) {
135+ printf "\nSummary reporting only available with --input-raw=<file>\n";
136+ printf "(First run scan with --output-raw=<file>.)\n";
137+ exit(128);
138+}
139+
140+if ($output_raw) {
141+ open my $fh, '>', $output_raw or die "$0: $output_raw: $!\n";
142+ select $fh;
143+}
144+
98145 parse_dmesg();
99146 walk(@DIRS);
100147
@@ -239,3 +286,141 @@ sub walk · 138 unmodified lines
239286 }
240287 }
241288 }
289+
290+sub format_output
291+{
292+ my ($file) = @_;
293+
294+ # Default is to show raw results.
295+ if ($raw or (!$squash_by_path and !$squash_by_filename)) {
296+ dump_raw_output($file);
297+ return;
298+ }
299+
300+ my ($total, $dmesg, $paths, $files) = parse_raw_file($file);
301+
302+ printf "\nTotal number of results from scan (incl dmesg): %d\n", $total;
303+
304+ if (!$suppress_dmesg) {
305+ print_dmesg($dmesg);
306+ }
307+
308+ if ($squash_by_filename) {
309+ squash_by($files, 'filename');
310+ }
311+
312+ if ($squash_by_path) {
313+ squash_by($paths, 'path');
314+ }
315+}
316+
317+sub dump_raw_output
318+{
319+ my ($file) = @_;
320+
321+ open (my $fh, '<', $file) or die "$0: $file: $!\n";
322+ while (<$fh>) {
323+ if ($suppress_dmesg) {
324+ if ("dmesg:" eq substr($_, 0, 6)) {
325+ next;
326+ }
327+ }
328+ print $_;
329+ }
330+ close $fh;
331+}
332+
333+sub parse_raw_file
334+{
335+ my ($file) = @_;
336+
337+ my $total = 0; # Total number of lines parsed.
338+ my @dmesg; # dmesg output.
339+ my %files; # Unique filenames containing leaks.
340+ my %paths; # Unique paths containing leaks.
341+
342+ open (my $fh, '<', $file) or die "$0: $file: $!\n";
343+ while (my $line = <$fh>) {
344+ $total++;
345+
346+ if ("dmesg:" eq substr($line, 0, 6)) {
347+ push @dmesg, $line;
348+ next;
349+ }
350+
351+ cache_path(\%paths, $line);
352+ cache_filename(\%files, $line);
353+ }
354+
355+ return $total, \@dmesg, \%paths, \%files;
356+}
357+
358+sub print_dmesg
359+{
360+ my ($dmesg) = @_;
361+
362+ print "\ndmesg output:\n";
363+
364+ if (@$dmesg == 0) {
365+ print "<no results>\n";
366+ return;
367+ }
368+
369+ foreach(@$dmesg) {
370+ my $index = index($_, ': ');
371+ $index += 2; # skid ': '
372+ print substr($_, $index);
373+ }
374+}
375+
376+sub squash_by
377+{
378+ my ($ref, $desc) = @_;
379+
380+ print "\nResults squashed by $desc (excl dmesg). ";
381+ print "Displaying [<number of results> <$desc>], <example result>\n";
382+
383+ if (keys %$ref == 0) {
384+ print "<no results>\n";
385+ return;
386+ }
387+
388+ foreach(keys %$ref) {
389+ my $lines = $ref->{$_};
390+ my $length = @$lines;
391+ printf "[%d %s] %s", $length, $_, @$lines[0];
392+ }
393+}
394+
395+sub cache_path
396+{
397+ my ($paths, $line) = @_;
398+
399+ my $index = index($line, ': ');
400+ my $path = substr($line, 0, $index);
401+
402+ $index += 2; # skip ': '
403+ add_to_cache($paths, $path, substr($line, $index));
404+}
405+
406+sub cache_filename
407+{
408+ my ($files, $line) = @_;
409+
410+ my $index = index($line, ': ');
411+ my $path = substr($line, 0, $index);
412+ my $filename = basename($path);
413+
414+ $index += 2; # skip ': '
415+ add_to_cache($files, $filename, substr($line, $index));
416+}
417+
418+sub add_to_cache
419+{
420+ my ($cache, $key, $value) = @_;
421+
422+ if (!$cache->{$key}) {
423+ $cache->{$key} = ();
424+ }
425+ push @{$cache->{$key}}, $value;
426+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t