History

Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net

Simple cases of overlapping changes in the packet scheduler. Must easier to resolve this time. Which probably means that I screwed it up somehow.

David S. Miller committed 9 years ago

Commit 4dc67582 parents 19aeeb9 3fefc31148 files · +1125 −436Browse files

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

Unified · Split

scripts/leaking_addresses.pl+305−0
@@ -0,0 +1,305 @@
1+#!/usr/bin/env perl
2+#
3+# (c) 2017 Tobin C. Harding <me@tobin.cc>
4+# Licensed under the terms of the GNU GPL License version 2
5+#
6+# leaking_addresses.pl: Scan 64 bit kernel for potential leaking addresses.
7+# - Scans dmesg output.
8+# - Walks directory tree and parses each file (for each directory in @DIRS).
9+#
10+# You can configure the behaviour of the script;
11+#
12+# - By adding paths, for directories you do not want to walk;
13+# absolute paths: @skip_walk_dirs_abs
14+# directory names: @skip_walk_dirs_any
15+#
16+# - By adding paths, for files you do not want to parse;
17+# absolute paths: @skip_parse_files_abs
18+# file names: @skip_parse_files_any
19+#
20+# The use of @skip_xxx_xxx_any causes files to be skipped where ever they occur.
21+# For example adding 'fd' to @skip_walk_dirs_any causes the fd/ directory to be
22+# skipped for all PID sub-directories of /proc
23+#
24+# The same thing can be achieved by passing command line options to --dont-walk
25+# and --dont-parse. If absolute paths are supplied to these options they are
26+# appended to the @skip_xxx_xxx_abs arrays. If file names are supplied to these
27+# options, they are appended to the @skip_xxx_xxx_any arrays.
28+#
29+# Use --debug to output path before parsing, this is useful to find files that
30+# cause the script to choke.
31+#
32+# You may like to set kptr_restrict=2 before running script
33+# (see Documentation/sysctl/kernel.txt).
34+
35+use warnings;
36+use strict;
37+use POSIX;
38+use File::Basename;
39+use File::Spec;
40+use Cwd 'abs_path';
41+use Term::ANSIColor qw(:constants);
42+use Getopt::Long qw(:config no_auto_abbrev);
43+
44+my $P = $0;
45+my $V = '0.01';
46+
47+# Directories to scan.
48+my @DIRS = ('/proc', '/sys');
49+
50+# Command line options.
51+my $help = 0;
52+my $debug = 0;
53+my @dont_walk = ();
54+my @dont_parse = ();
55+
56+# Do not parse these files (absolute path).
57+my @skip_parse_files_abs = ('/proc/kmsg',
58+ '/proc/kcore',
59+ '/proc/fs/ext4/sdb1/mb_groups',
60+ '/proc/1/fd/3',
61+ '/sys/kernel/debug/tracing/trace_pipe',
62+ '/sys/kernel/security/apparmor/revision');
63+
64+# Do not parse thes files under any subdirectory.
65+my @skip_parse_files_any = ('0',
66+ '1',
67+ '2',
68+ 'pagemap',
69+ 'events',
70+ 'access',
71+ 'registers',
72+ 'snapshot_raw',
73+ 'trace_pipe_raw',
74+ 'ptmx',
75+ 'trace_pipe');
76+
77+# Do not walk these directories (absolute path).
78+my @skip_walk_dirs_abs = ();
79+
80+# Do not walk these directories under any subdirectory.
81+my @skip_walk_dirs_any = ('self',
82+ 'thread-self',
83+ 'cwd',
84+ 'fd',
85+ 'stderr',
86+ 'stdin',
87+ 'stdout');
88+
89+sub help
90+{
91+ my ($exitcode) = @_;
92+
93+ print << "EOM";
94+Usage: $P [OPTIONS]
95+Version: $V
96+
97+Options:
98+
99+ --dont-walk=<dir> Don't walk tree starting at <dir>.
100+ --dont-parse=<file> Don't parse <file>.
101+ -d, --debug Display debugging output.
102+ -h, --help, --version Display this help and exit.
103+
104+If an absolute path is passed to --dont_XXX then this path is skipped. If a
105+single filename is passed then this file/directory will be skipped when
106+appearing under any subdirectory.
107+
108+Example:
109+
110+ # Just scan dmesg output.
111+ scripts/leaking_addresses.pl --dont_walk_abs /proc --dont_walk_abs /sys
112+
113+Scans the running (64 bit) kernel for potential leaking addresses.
114+
115+EOM
116+ exit($exitcode);
117+}
118+
119+GetOptions(
120+ 'dont-walk=s' => \@dont_walk,
121+ 'dont-parse=s' => \@dont_parse,
122+ 'd|debug' => \$debug,
123+ 'h|help' => \$help,
124+ 'version' => \$help
125+) or help(1);
126+
127+help(0) if ($help);
128+
129+push_to_global();
130+
131+parse_dmesg();
132+walk(@DIRS);
133+
134+exit 0;
135+
136+sub debug_arrays
137+{
138+ print 'dirs_any: ' . join(", ", @skip_walk_dirs_any) . "\n";
139+ print 'dirs_abs: ' . join(", ", @skip_walk_dirs_abs) . "\n";
140+ print 'parse_any: ' . join(", ", @skip_parse_files_any) . "\n";
141+ print 'parse_abs: ' . join(", ", @skip_parse_files_abs) . "\n";
142+}
143+
144+sub dprint
145+{
146+ printf(STDERR @_) if $debug;
147+}
148+
149+sub push_in_abs_any
150+{
151+ my ($in, $abs, $any) = @_;
152+
153+ foreach my $path (@$in) {
154+ if (File::Spec->file_name_is_absolute($path)) {
155+ push @$abs, $path;
156+ } elsif (index($path,'/') == -1) {
157+ push @$any, $path;
158+ } else {
159+ print 'path error: ' . $path;
160+ }
161+ }
162+}
163+
164+# Push command line options to global arrays.
165+sub push_to_global
166+{
167+ push_in_abs_any(\@dont_walk, \@skip_walk_dirs_abs, \@skip_walk_dirs_any);
168+ push_in_abs_any(\@dont_parse, \@skip_parse_files_abs, \@skip_parse_files_any);
169+}
170+
171+sub is_false_positive
172+{
173+ my ($match) = @_;
174+
175+ if ($match =~ '\b(0x)?(f|F){16}\b' or
176+ $match =~ '\b(0x)?0{16}\b') {
177+ return 1;
178+ }
179+
180+ # vsyscall memory region, we should probably check against a range here.
181+ if ($match =~ '\bf{10}600000\b' or
182+ $match =~ '\bf{10}601000\b') {
183+ return 1;
184+ }
185+
186+ return 0;
187+}
188+
189+# True if argument potentially contains a kernel address.
190+sub may_leak_address
191+{
192+ my ($line) = @_;
193+ my $address = '\b(0x)?ffff[[:xdigit:]]{12}\b';
194+
195+ # Signal masks.
196+ if ($line =~ '^SigBlk:' or
197+ $line =~ '^SigCgt:') {
198+ return 0;
199+ }
200+
201+ if ($line =~ '\bKEY=[[:xdigit:]]{14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b' or
202+ $line =~ '\b[[:xdigit:]]{14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b') {
203+ return 0;
204+ }
205+
206+ while (/($address)/g) {
207+ if (!is_false_positive($1)) {
208+ return 1;
209+ }
210+ }
211+
212+ return 0;
213+}
214+
215+sub parse_dmesg
216+{
217+ open my $cmd, '-|', 'dmesg';
218+ while (<$cmd>) {
219+ if (may_leak_address($_)) {
220+ print 'dmesg: ' . $_;
221+ }
222+ }
223+ close $cmd;
224+}
225+
226+# True if we should skip this path.
227+sub skip
228+{
229+ my ($path, $paths_abs, $paths_any) = @_;
230+
231+ foreach (@$paths_abs) {
232+ return 1 if (/^$path$/);
233+ }
234+
235+ my($filename, $dirs, $suffix) = fileparse($path);
236+ foreach (@$paths_any) {
237+ return 1 if (/^$filename$/);
238+ }
239+
240+ return 0;
241+}
242+
243+sub skip_parse
244+{
245+ my ($path) = @_;
246+ return skip($path, \@skip_parse_files_abs, \@skip_parse_files_any);
247+}
248+
249+sub parse_file
250+{
251+ my ($file) = @_;
252+
253+ if (! -R $file) {
254+ return;
255+ }
256+
257+ if (skip_parse($file)) {
258+ dprint "skipping file: $file\n";
259+ return;
260+ }
261+ dprint "parsing: $file\n";
262+
263+ open my $fh, "<", $file or return;
264+ while ( <$fh> ) {
265+ if (may_leak_address($_)) {
266+ print $file . ': ' . $_;
267+ }
268+ }
269+ close $fh;
270+}
271+
272+
273+# True if we should skip walking this directory.
274+sub skip_walk
275+{
276+ my ($path) = @_;
277+ return skip($path, \@skip_walk_dirs_abs, \@skip_walk_dirs_any)
278+}
279+
280+# Recursively walk directory tree.
281+sub walk
282+{
283+ my @dirs = @_;
284+ my %seen;
285+
286+ while (my $pwd = shift @dirs) {
287+ next if (skip_walk($pwd));
288+ next if (!opendir(DIR, $pwd));
289+ my @files = readdir(DIR);
290+ closedir(DIR);
291+
292+ foreach my $file (@files) {
293+ next if ($file eq '.' or $file eq '..');
294+
295+ my $path = "$pwd/$file";
296+ next if (-l $path);
297+
298+ if (-d $path) {
299+ push @dirs, $path;
300+ } else {
301+ parse_file($path);
302+ }
303+ }
304+ }
305+}