Introduce --kallsyms argument for scanning binary files for known symbol
addresses. This would have found the exposure in /sys/kernel/notes:

$ scripts/leaking_addresses.pl --kallsyms=<(sudo cat /proc/kallsyms)
/sys/kernel/notes: hypercall_page @ 156
/sys/kernel/notes: xen_hypercall_set_trap_table @ 156
/sys/kernel/notes: startup_xen @ 132

Acked-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>
Signed-off-by: Kees Cook <keesc...@chromium.org>
---
Cc: "Tobin C. Harding" <m...@tobin.cc>
Cc: Tycho Andersen <tycho@tycho.pizza>
Cc: Guixiong Wei <guixiong...@gmail.com>
Cc: linux-hardening@vger.kernel.org
---
 scripts/leaking_addresses.pl | 53 ++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/scripts/leaking_addresses.pl b/scripts/leaking_addresses.pl
index 73cfcc5c8854..8e992b18bcd9 100755
--- a/scripts/leaking_addresses.pl
+++ b/scripts/leaking_addresses.pl
@@ -52,10 +52,13 @@ 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.
+my $kallsyms_file = "";                # Kernel symbols file.
 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.
 
+my @kallsyms = ();
+
 # Skip these absolute paths.
 my @skip_abs = (
        '/proc/kmsg',
@@ -96,6 +99,8 @@ Options:
              --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)
+       --kallsyms=<file>               Read kernel symbol addresses from file 
(for
+                                               scanning binary files).
        --32-bit                        Scan 32-bit kernel.
        --page-offset-32-bit=o          Page offset (for 32-bit kernel 
0xABCD1234).
        -d, --debug                     Display debugging output.
@@ -116,6 +121,7 @@ GetOptions(
        'squash-by-path'        => \$squash_by_path,
        'squash-by-filename'    => \$squash_by_filename,
        'raw'                   => \$raw,
+       'kallsyms=s'            => \$kallsyms_file,
        'kernel-config-file=s'  => \$kernel_config_file,
        '32-bit'                => \$opt_32bit,
        'page-offset-32-bit=o'  => \$page_offset_32bit,
@@ -156,6 +162,25 @@ if ($output_raw) {
        select $fh;
 }
 
+if ($kallsyms_file) {
+       open my $fh, '<', $kallsyms_file or die "$0: $kallsyms_file: $!\n";
+       while (<$fh>) {
+               chomp;
+               my @entry = split / /, $_;
+               my $addr_text = $entry[0];
+               if ($addr_text !~ /^0/) {
+                       # TODO: Why is hex() so impossibly slow?
+                       my $addr = hex($addr_text);
+                       my $symbol = $entry[2];
+                       # Only keep kernel text addresses.
+                       my $long = pack("J", $addr);
+                       my $entry = [$long, $symbol];
+                       push @kallsyms, $entry;
+               }
+       }
+       close $fh;
+}
+
 parse_dmesg();
 walk(@DIRS);
 
@@ -447,6 +472,25 @@ sub timed_parse_file
        }
 }
 
+sub parse_binary
+{
+       my ($file) = @_;
+
+       open my $fh, "<:raw", $file or return;
+       local $/ = undef;
+       my $bytes = <$fh>;
+       close $fh;
+
+       foreach my $entry (@kallsyms) {
+               my $addr = $entry->[0];
+               my $symbol = $entry->[1];
+               my $offset = index($bytes, $addr);
+               if ($offset != -1) {
+                       printf("$file: $symbol @ $offset\n");
+               }
+       }
+}
+
 sub parse_file
 {
        my ($file) = @_;
@@ -456,6 +500,15 @@ sub parse_file
        }
 
        if (! -T $file) {
+               if ($file =~ m|^/sys/kernel/btf/| or
+                   $file =~ m|^/sys/devices/pci| or
+                   $file =~ m|^/sys/firmware/efi/efivars/| or
+                   $file =~ m|^/proc/bus/pci/|) {
+                       return;
+               }
+               if (scalar @kallsyms > 0) {
+                       parse_binary($file);
+               }
                return;
        }
 
-- 
2.34.1


Reply via email to