Commit 67bbd2f0 authored by Kees Cook's avatar Kees Cook
Browse files

leaking_addresses: Provide mechanism to scan binary files



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: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: default avatarTycho Andersen <tandersen@netflix.com>
Link: https://lore.kernel.org/r/20240222220053.1475824-4-keescook@chromium.org


Signed-off-by: default avatarKees Cook <keescook@chromium.org>
parent 3e389d45
Loading
Loading
Loading
Loading
+53 −0
Original line number Diff line number Diff line
@@ -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;
	}