# (c) 2017 Tobin C. Harding <me@tobin.cc>
# Licensed under the terms of the GNU GPL License version 2
#
-# leaking_addresses.pl: Scan 64 bit kernel for potential leaking addresses.
+# leaking_addresses.pl: Scan the kernel for potential leaking addresses.
# - Scans dmesg output.
# - Walks directory tree and parses each file (for each directory in @DIRS).
#
# Timer for parsing each file, in seconds.
my $TIMEOUT = 10;
-# Script can only grep for kernel addresses on the following architectures. If
-# your architecture is not listed here and has a grep'able kernel address please
-# consider submitting a patch.
-my @SUPPORTED_ARCHITECTURES = ('x86_64', 'ppc64');
+# Kernel addresses vary by architecture. We can only auto-detect the following
+# architectures (using `uname -m`). (flag --32-bit overrides auto-detection.)
+my @SUPPORTED_ARCHITECTURES = ('x86_64', 'ppc64', 'x86');
# Command line options.
my $help = 0;
my $squash_by_path = 0; # Summary report grouped by absolute path.
my $squash_by_filename = 0; # Summary report grouped by filename.
my $kernel_config_file = ""; # Kernel configuration file.
+my $opt_32bit = 0; # Scan 32-bit kernel.
+my $page_offset_32bit = 0; # Page offset for 32-bit kernel.
# Do not parse these files (absolute path).
my @skip_parse_files_abs = ('/proc/kmsg',
--squash-by-path Show one result per unique path.
--squash-by-filename Show one result per unique filename.
--kernel-config-file=<file> Kernel configuration file (e.g /boot/config)
+ --32-bit Scan 32-bit kernel.
+ --page-offset-32-bit=o Page offset (for 32-bit kernel 0xABCD1234).
-d, --debug Display debugging output.
-h, --help, --version Display this help and exit.
-Scans the running (64 bit) kernel for potential leaking addresses.
+Scans the running kernel for potential leaking addresses.
EOM
exit($exitcode);
'squash-by-filename' => \$squash_by_filename,
'raw' => \$raw,
'kernel-config-file=s' => \$kernel_config_file,
+ '32-bit' => \$opt_32bit,
+ 'page-offset-32-bit=o' => \$page_offset_32bit,
) or help(1);
help(0) if ($help);
exit(128);
}
-if (!is_supported_architecture()) {
+if (!(is_supported_architecture() or $opt_32bit or $page_offset_32bit)) {
printf "\nScript does not support your architecture, sorry.\n";
printf "\nCurrently we support: \n\n";
foreach(@SUPPORTED_ARCHITECTURES) {
}
printf("\n");
+ printf("If you are running a 32-bit architecture you may use:\n");
+ printf("\n\t--32-bit or --page-offset-32-bit=<page offset>\n\n");
+
my $archname = `uname -m`;
printf("Machine hardware name (`uname -m`): %s\n", $archname);
sub is_supported_architecture
{
- return (is_x86_64() or is_ppc64());
+ return (is_x86_64() or is_ppc64() or is_ix86_32());
+}
+
+sub is_32bit
+{
+ # Allow --32-bit or --page-offset-32-bit to override
+ if ($opt_32bit or $page_offset_32bit) {
+ return 1;
+ }
+
+ return is_ix86_32();
+}
+
+sub is_ix86_32
+{
+ my $arch = `uname -m`;
+
+ chomp $arch;
+ if ($arch =~ m/i[3456]86/) {
+ return 1;
+ }
+ return 0;
}
sub is_arch
{
my ($match) = @_;
+ if (is_32bit()) {
+ return is_false_positive_32bit($match);
+ }
+
+ # 64 bit false positives.
+
if ($match =~ '\b(0x)?(f|F){16}\b' or
$match =~ '\b(0x)?0{16}\b') {
return 1;
return 0;
}
+sub is_false_positive_32bit
+{
+ my ($match) = @_;
+ state $page_offset = get_page_offset();
+
+ if ($match =~ '\b(0x)?(f|F){8}\b') {
+ return 1;
+ }
+
+ if (hex($match) < $page_offset) {
+ return 1;
+ }
+
+ return 0;
+}
+
+# returns integer value
+sub get_page_offset
+{
+ my $page_offset;
+ my $default_offset = 0xc0000000;
+
+ # Allow --page-offset-32bit to override.
+ if ($page_offset_32bit != 0) {
+ return $page_offset_32bit;
+ }
+
+ $page_offset = get_kernel_config_option('CONFIG_PAGE_OFFSET');
+ if (!$page_offset) {
+ return $default_offset;
+ }
+ return $page_offset;
+}
+
sub is_in_vsyscall_memory_region
{
my ($match) = @_;
sub get_address_re
{
- if (is_x86_64()) {
- return get_x86_64_re();
- } elsif (is_ppc64()) {
+ if (is_ppc64()) {
return '\b(0x)?[89abcdef]00[[:xdigit:]]{13}\b';
+ } elsif (is_32bit()) {
+ return '\b(0x)?[[:xdigit:]]{8}\b';
}
+
+ return get_x86_64_re();
}
sub get_x86_64_re