scripts: leaking_addresses.pl: add support for 32-bit kernel addresses
PATCH 1/1 scripts: leaking_addresses.pl: add support for 32-bit kernel addresses
The current leaking_addresses.pl script only supports showing "leaked" 64-bit kernel virtual addresses. This patch adds support for showing "leaked" 32-bit kernel virtual addresses.
The way it currently works- once it detects we're running on an i'x'86 platform (where x=3|4|5|6), it takes this arch into account for checking: the essential rationale:
virt-addr >= PAGE_OFFSET => it's a kernel virtual address.
Note-
1. It's a work in progress; some pending TODOs:
- support for ARM-32
- programatically query and set the PAGE_OFFSET based on arch (it's currently hard-coded)
2. Minor edit:
the '--raw', '--suppress-dmesg', '--squash-by-path' and '--squash-by-filename' option switches are only meaningful
when the '----input-raw=' option is used. So, indent the 'Help' screen lines to reflect the fact.
Feedback welcome..
---
scripts/leaking_addresses.pl +37 -7
@@ -12,7 +12,10 @@ # # You may like to set kptr_restrict=2 before running script # (see Documentation/sysctl/kernel.txt). - +# +# 32-bit kernel address support : Kaiwan N Billimoria +# <[email protected]> +# use warnings; use strict; use POSIX;
@@ -35,7 +38,7 @@ 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'); +my @SUPPORTED_ARCHITECTURES = ('x86_64', 'ppc64', 'i[3456]86'); # Command line options. my $help = 0;
@@ -48,6 +51,9 @@ 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 $bit_size = 64; # Check 64-bit kernel addresses by default +my $PAGE_OFFSET_32BIT = 0xc0000000; + # Do not parse these files (absolute path). my @skip_parse_files_abs = ('/proc/kmsg', '/proc/kcore',
@@ -97,10 +103,10 @@ Options: -o, --output-raw=<file> Save results for future processing. -i, --input-raw=<file> Read results from file instead of scanning. - --raw Show raw results (default). - --suppress-dmesg Do not show dmesg results. - --squash-by-path Show one result per unique path. - --squash-by-filename Show one result per unique filename. + --raw Show raw results (default). + --suppress-dmesg Do not show dmesg results. + --squash-by-path Show one result per unique path. + --squash-by-filename Show one result per unique filename. -d, --debug Display debugging output. -h, --help, --version Display this help and exit.
@@ -177,7 +183,7 @@ sub dprint sub is_supported_architecture { - return (is_x86_64() or is_ppc64()); + return (is_x86_64() or is_ppc64() or is_ix86_32()); } sub is_x86_64
@@ -185,6 +191,7 @@ sub is_x86_64 my $archname = $Config{archname}; if ($archname =~ m/x86_64/) { + $bit_size=64; return 1; } return 0;
@@ -195,6 +202,19 @@ sub is_ppc64 my $archname = $Config{archname}; if ($archname =~ m/powerpc/ and $archname =~ m/64/) { + $bit_size=64; + return 1; + } + return 0; +} + +# 32-bit x86: is_i'x'86_32() ; where x is [3 or 4 or 5 or 6] +sub is_ix86_32 +{ + my $archname = $Config{archname}; + + if ($archname =~ m/i[3456]86-linux/) { + $bit_size=32; return 1; } return 0;
@@ -215,6 +235,15 @@ sub is_false_positive $match =~ '\bf{10}601000\b') { return 1; } + } elsif ($bit_size == 32) { + my $addr32 = eval hex($match); + if ($addr32 < $PAGE_OFFSET_32BIT ) { + return 1; + } + if ($match =~ '\b(0x)?(f|F){8}\b') { + return 1; + } } return 0;
@@ -243,6 +272,8 @@ sub may_leak_address $address_re = '\b(0x)?ffff[[:xdigit:]]{12}\b'; } elsif (is_ppc64()) { $address_re = '\b(0x)?[89abcdef]00[[:xdigit:]]{13}\b'; + } elsif (is_ix86_32()) { + $address_re = '\b(0x)?[[:xdigit:]]{8}\b'; } while (/($address_re)/g) {
You don't typically need [xxx v1] for version 1, the v1 is implicit.
Please use the git brief description prefix that is already in use i.e
leaking_addresses: add support for 32-bit kernel addresses
Quoted 3 lines · On Tue, Nov 21, 2017 at 01:28:14PM +0530, [email protected] wrote:
The current leaking_addresses.pl script only supports showing "leaked" 64-bit kernel virtual addresses. This patch adds support for showing "leaked" 32-bit kernel virtual addresses.
Thanks for the patch. I like your ideas. Here are a few nitpicks to help us get your work merged.
Quoted 7 lines
The way it currently works- once it detects we're running on an i'x'86 platform (where x=3|4|5|6), it takes this arch into account for checking: the essential rationale:
virt-addr >=PAGE_OFFSET=> it's a kernel virtual address.Note-
1. It's a work in progress; some pending TODOs:
We don't have 'work in progress' in the kernel, everything is a work in progress. We just have RFC or PATCH.
Quoted 1 line
- support for ARM-32
Sure, we can do this later.
Quoted 2 lines
- programatically query and set the
PAGE_OFFSETbased on arch (it's currently hard-coded)
Let's do this straight away, it will be much nicer.
Quoted 5 lines
2. Minor edit:
the '--raw', '--suppress-dmesg', '--squash-by-path' and '--squash-by-filename' option switches are only meaningful
when the '----input-raw=' option is used. So, indent the 'Help' screen lines to reflect the fact.
This is a different change to the architecture stuff so should be in a separate patch. You could do both as a series if you like. Off the top of my head I have never seen options output like this, but if you have, I'm willing to accept your view. You are correct that the options mentioned are only use in conjuncture with '--input-raw' so some way of showing this would be nice.
Quoted 1 line
Feedback welcome..
Here it comes ;)
Quoted 7 lines
Signed-off-by Kaiwan N Billimoria <[email protected]>---
scripts/leaking_addresses.pl +0
-0
scripts/leaking_addresses.pl line 17
Quoted 7 lines
scripts/leaking_addresses.pl +3
-1@@ -12,7 +12,10 @@ # # You may like to set kptr_restrict=2 before running script # (see Documentation/sysctl/kernel.txt). - +# +# 32-bit kernel address support : Kaiwan N Billimoria +# <[email protected]>
Cool. Can you put this up the top near the other copyright information please.
Perhaps
# (c) 2017 Kaiwan N Billimoria <[email protected]> (ix86 support)
Quoted 13 lines
scripts/leaking_addresses.pl +1
-1use warnings; use strict; use POSIX;@@ -35,7 +38,7 @@ 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'); +my @SUPPORTED_ARCHITECTURES = ('x86_64', 'ppc64', 'i[3456]86'); # Command line options. my $help = 0;
scripts/leaking_addresses.pl my $suppress_dmesg = 0; # Don't show dmesg in output. · line 54
Quoted 4 lines
scripts/leaking_addresses.pl +1
-0@@ -48,6 +51,9 @@ 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 $bit_size = 64; # Check 64-bit kernel addresses by default
This global is unnecessary. You already have is_ix86_32() so you can just use that.
scripts/leaking_addresses.pl my $suppress_dmesg = 0; # Don't show dmesg in output. · line 55
Quoted 1 line
scripts/leaking_addresses.pl +1
-0+my $PAGE_OFFSET_32BIT = 0xc0000000;
As commented above, can we do this programmatically like previously discussed?
Quoted 7 lines
scripts/leaking_addresses.pl +0
-0# Do not parse these files (absolute path). my @skip_parse_files_abs = ('/proc/kmsg', '/proc/kcore',@@ -97,10 +103,10 @@ Options: -o, --output-raw=<file> Save results for future processing. -i, --input-raw=<file> Read results from file instead of scanning.
scripts/leaking_addresses.pl Options: · line 111
Quoted 10 lines
scripts/leaking_addresses.pl +4
-4- --raw Show raw results (default). - --suppress-dmesg Do not show dmesg results. - --squash-by-path Show one result per unique path. - --squash-by-filename Show one result per unique filename. + --raw Show raw results (default). + --suppress-dmesg Do not show dmesg results. + --squash-by-path Show one result per unique path. + --squash-by-filename Show one result per unique filename. -d, --debug Display debugging output. -h, --help, --version Display this help and exit.
Commented on above.
Quoted 10 lines
scripts/leaking_addresses.pl +1
-1@@ -177,7 +183,7 @@ sub dprint sub is_supported_architecture { - return (is_x86_64() or is_ppc64()); + return (is_x86_64() or is_ppc64() or is_ix86_32()); } sub is_x86_64
scripts/leaking_addresses.pl sub is_x86_64 · line 194
Quoted 4 lines
scripts/leaking_addresses.pl +1
-0@@ -185,6 +191,7 @@ sub is_x86_64 my $archname = $Config{archname}; if ($archname =~ m/x86_64/) { + $bit_size=64;
Setting a global opaquely within an is_a_ function (or subroutine) violates the principle of least surprise. No one would expect an is_a function to do this. Either way, as commented above, we don't need this global anyways.
scripts/leaking_addresses.pl sub is_ppc64 · line 205
Quoted 8 lines
scripts/leaking_addresses.pl +1
-0return 1; } return 0;@@ -195,6 +202,19 @@ sub is_ppc64 my $archname = $Config{archname}; if ($archname =~ m/powerpc/ and $archname =~ m/64/) { + $bit_size=64;
As above.
scripts/leaking_addresses.pl sub is_ppc64 · line 211
Quoted 6 lines
scripts/leaking_addresses.pl +6
-0+ return 1; + } + return 0; +} + +# 32-bit x86: is_i'x'86_32() ; where x is [3 or 4 or 5 or 6]
Perhaps
# true for Intel x86 32 bit architectures, x386 and above.
scripts/leaking_addresses.pl sub is_ppc64 · line 217
Quoted 6 lines
scripts/leaking_addresses.pl +6
-0+sub is_ix86_32 +{ + my $archname = $Config{archname}; + + if ($archname =~ m/i[3456]86-linux/) { + $bit_size=32;
Please use kernel coding style
$bit_size = 32;
scripts/leaking_addresses.pl sub is_false_positive · line 238
Quoted 8 lines
scripts/leaking_addresses.pl +1
-0return 1; } return 0;@@ -215,6 +235,15 @@ sub is_false_positive $match =~ '\bf{10}601000\b') { return 1; } + } elsif ($bit_size == 32) {
} elsif (is_ix86_32())
Bonus points, you uncovered a bug in the current script if (is_x86_64) was missing the parenthesis!
# leaking_addresses.pl: Scan 64 bit kernel for potential leaking addresses. @@ -209,7 +211,7 @@ sub is_false_positive
return 1;
}- if (is_x86_64) {
+ if (is_x86_64()) {
Thanks. I'm guessing this is what led you to using the global :) Have patched dev branch (branch name: leaks).
scripts/leaking_addresses.pl sub is_false_positive · line 242
Quoted 4 lines
scripts/leaking_addresses.pl +4
-0+ my $addr32 = eval hex($match); + if ($addr32 < $PAGE_OFFSET_32BIT ) { + return 1; + }
Nice.
scripts/leaking_addresses.pl sub is_false_positive · line 245
Quoted 3 lines
scripts/leaking_addresses.pl +3
-0+ if ($match =~ '\b(0x)?(f|F){8}\b') { + return 1; + }
So, may_leak_address() and is_false_positive() are tightly coupled and not really that nice. Once we add 32 bit support it gets worse. Going forwards, we can either add your 32 bit work then refactor both functions or you can refactor them as you add the 32 bit stuff. I'm open to either. Some things to note
- The mask stuff (all 1's) should have an all 0's regex also.
- The mask stuff should probably be closer to the mask stuff for 64 bit. It's not immediately apparent a clean way to do this though.
- It's not immediately apparent if an address less that PAGE_OFFSET is a false positive or should be caught in leaks_address().
- Do we need 32 bit equivalents for
if ($line =~ '\bKEY=[[:xdigit:]]{14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b' or
$line =~ '\b[[:xdigit:]]{14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b') {Even though this is a false positive it needs to be where it is (note the 'tightly coupled' statement above).
scripts/leaking_addresses.pl sub may_leak_address · line 279
Quoted 12 lines
scripts/leaking_addresses.pl +2
-0} return 0;@@ -243,6 +272,8 @@ sub may_leak_address $address_re = '\b(0x)?ffff[[:xdigit:]]{12}\b'; } elsif (is_ppc64()) { $address_re = '\b(0x)?[89abcdef]00[[:xdigit:]]{13}\b'; + } elsif (is_ix86_32()) { + $address_re = '\b(0x)?[[:xdigit:]]{8}\b'; } while (/($address_re)/g) {
Your patch did not apply, the problem looks to be in the code section above. You can see that there is no removed line. For next spin please check your patch applies on top of the 'leaks' branch (which now includes the fix for the bug you found).
I have one more comment that should have been at the top but I did not want to confuse things. Typically, the git brief description should be limited to 50 characters. If you do decide to split this patch into two and use the prefix suggested you may like to change the git brief description but don't feel you have to. If you do decide to do this, your next patch set will be a version 1 again. I may be wrong but I never increment a patch version if the subject line changes (excluding contents of [] ).
I'm relatively new here so please feel free to ignore anything I've said. I have commented in the effort to help you learn as I am doing so also.
I'll look forward to v2. Please ask if anything I've said is unclear.
thanks,
Tobin.
Thanks Tobin, for your detailed comments.
Quoted 5 lines · Tobin C. Harding
You don't typically need [xxx v1] for version 1, the v1 is implicit.
Please use the git brief description prefix that is already in use i.e
leaking_addresses: add support for 32-bit kernel addresses
Ok..
Quoted 4 lines · On Tue, Nov 21, 2017 at 01:28:14PM +0530, [email protected] wrote:
Quoted 1 line
- support for ARM-32
Sure, we can do this later.
Righto
Quoted 5 lines
Quoted 3 lines
- programatically query and set the
PAGE_OFFSETbased on arch (it's currently hard-coded)Let's do this straight away, it will be much nicer.
Yes, will work on it..
Quoted 6 lines
Quoted 5 lines
2. Minor edit:
the '--raw', '--suppress-dmesg', '--squash-by-path' and '--squash-by-filename' option switches are only meaningful
when the '----input-raw=' option is used. So, indent the 'Help' screen lines to reflect the fact.
Quoted 6 lines
This is a different change to the architecture stuff so should be in a separate patch. You could do both as a series if you like. Off the top of my head I have never seen options output like this, but if you have, I'm willing to accept your view. You are correct that the options mentioned are only use in conjuncture with '--input-raw' so some way of showing this would be nice.
I realize this; so, yeah, will make the next one a series and put this in the 2nd..
Quoted 11 lines
Quoted 2 lines
+my $bit_size = 64; # Check 64-bit kernel addresses by default
This global is unnecessary. You already have
is_ix86_32()so you can just use that.From your later comments, I think you see that using this global is necessary.
Please use kernel coding style
$bit_size = 32;
Ok..
Quoted 2 lines
Bonus points, you uncovered a bug in the current script
if (is_x86_64)was missing the parenthesis!
Yeah :-)
Quoted 10 lines
scripts/leaking_addresses.pl sub is_false_positive · line 245
Quoted 4 lines
scripts/leaking_addresses.pl +3
-0+ if ($match =~ '\b(0x)?(f|F){8}\b') { + return 1; + }So,
may_leak_address()andis_false_positive()are tightly coupled and not really that nice. Once we add 32 bit support it gets worse. Going forwards, we can either add your 32 bit work then refactor both functions or you can refactor them as you add the 32 bit stuff. I'm open to either.
Yes I agree. Having said that, I'll leave it on the back burner for now..
Quoted 3 lines
Some things to note
- The mask stuff (all 1's) should have an all 0's regex also.
Well, once we determine the address is >= PAGE_OFFSET, it's automatically apparent that it's not 0, yes?
Quoted 4 lines
- The mask stuff should probably be closer to the mask stuff for 64 bit. It's not immediately apparent a clean way to do this though.
- It's not immediately apparent if an address less thatPAGE_OFFSETis a false positive or should be caught inleaks_address().
Hmm only thing I can think of offhand- on many ARM-32's, the kernel module space is belowPAGE_OFFSET; we'd have to take that into consideration of course. Anything else < PAGE_OFFSET and a kernel address? Anyone?
Quoted 5 lines
- Do we need 32 bit equivalents for
if ($line =~ '\bKEY=[[:xdigit:]]{14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b' or $line =~ '\b[[:xdigit:]]{14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b') {
Ok am unclear on what exactly the above achieves.. could you pl throw some light on it, thanks..
Quoted 5 lines
Your patch did not apply, the problem looks to be in the code section above. You can see that there is no removed line. For next spin please check your patch applies on top of the 'leaks' branch (which now includes the fix for the bug you found).
Yes, sorry about that; will do..
Quoted 8 lines
I have one more comment that should have been at the top but I did not want to confuse things. Typically, the git brief description should be limited to 50 characters. If you do decide to split this patch into two and use the prefix suggested you may like to change the git brief description but don't feel you have to. If you do decide to do this, your next patch set will be a version 1 again. I may be wrong but I never increment a patch version if the subject line changes (excluding contents of [] ).
Right. I plan to send the next one as a 2 patch series; will keep the git prefix you suggest
(and as Sub changes, will not label the version).
Quoted 3 lines
thanks,
Tobin.
Thanks,
Kaiwan.