lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri, 05 Jun 2020 18:58:52 -0700
From:   Joe Perches <joe@...ches.com>
To:     Andrew Morton <akpm@...ux-foundation.org>
Cc:     Kees Cook <keescook@...omium.org>, linux-kernel@...r.kernel.org
Subject: Re: [PATCH] checkpatch: Add test for possible misuse of
 IS_ENABLED() without CONFIG_

On Fri, 2020-06-05 at 17:32 -0700, Andrew Morton wrote:
> On Fri, 05 Jun 2020 11:24:43 -0700 Joe Perches <joe@...ches.com> wrote:
> 
> > IS_ENABLED is almost always used with CONFIG_<FOO> defines.
> > 
> > Add a test to verify that the #define being tested starts with CONFIG_.
> 
> Yay.
> 
> I wonder if there's a simple way of testing whether the CONFIG_ thing
> can *ever* be enabled.  So detect if someone does
> 
> 	if (IS_ENABLED(CONFIG_BLOCKK))

No, not really. There's no simple way to do that.
It's doable, but it's not at all simple.

I think it would require something similar to the
checkpatch seed_camelcase_includes function to look
for all current config symbols and verify whatever
CONFIG_<DEFINE> against that list.

$ git grep -P -oh "^\s*config\s+\w+" -- '*/Kconfig*' | \
  sed -r -e 's/^\s+//' -e 's/\s+/ /g' | \
  sort | uniq -cym

Right now that takes ~1.5 seconds with my laptop
against an uncached git tree, and ~0.25 seconds cached.

Without a git tree it takes 20+ seconds.

Anyway, maybe this.

It only does the time consuming lookup when
it finds a IS_ENABLED line.

---
 scripts/checkpatch.pl | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 101 insertions(+)

diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 5f00df2c3f59..aabb01cf1e6c 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -47,6 +47,7 @@ my $gitroot = $ENV{'GIT_DIR'};
 $gitroot = ".git" if !defined($gitroot);
 my %debug;
 my %camelcase = ();
+my %Kconfig_syms = ();
 my %use_type = ();
 my @use = ();
 my %ignore_type = ();
@@ -911,6 +912,90 @@ sub is_SPDX_License_valid {
 	return 1;
 }
 
+sub seed_Kconfig_file {
+	my ($file) = @_;
+
+	return if (!(-f $file));
+
+	local $/;
+
+	open(my $Kconfig_file, '<', "$file")
+	    or warn "$P: Can't read '$file' $!\n";
+	my $text = <$Kconfig_file>;
+	close($Kconfig_file);
+
+	my @lines = split('\n', $text);
+
+	foreach my $line (@lines) {
+		next if ($line !~ /^\s*config\s+(\w+)/);
+		$Kconfig_syms{$1} = 1;
+	}
+}
+
+my $Kconfig_symbols_seeded = 0;
+sub seed_Kconfig_symbols {
+	return if ($Kconfig_symbols_seeded);
+
+	my $files;
+	my @Kconfig_files = ();
+	my $Kconfig_syms_cache = "";
+
+	$Kconfig_symbols_seeded = 1;
+
+	if (-e "$gitroot") {
+		my $git_last_include_commit = `${git_command} log --no-merges --pretty=format:"%h%n" -1 -- include`;
+		chomp $git_last_include_commit;
+		$Kconfig_syms_cache = ".checkpatch-Kconfig_syms.git.$git_last_include_commit";
+	} else {
+		my $last_mod_date = 0;
+		$files = `find $root/ -name "Kconfig*"`;
+		@Kconfig_files = split('\n', $files);
+		foreach my $file (@Kconfig_files) {
+			my $date = POSIX::strftime("%Y%m%d%H%M",
+						   localtime((stat $file)[9]));
+			$last_mod_date = $date if ($last_mod_date < $date);
+		}
+		$Kconfig_syms_cache = ".checkpatch-Kconfig_syms.date.$last_mod_date";
+	}
+
+	if ($Kconfig_syms_cache ne "" && -f $Kconfig_syms_cache) {
+		open(my $Kconfig_syms_file, '<', "$Kconfig_syms_cache")
+		    or warn "$P: Can't read '$Kconfig_syms_cache' $!\n";
+		while (<$Kconfig_syms_file>) {
+			chomp;
+			$Kconfig_syms{$_} = 1;
+		}
+		close($Kconfig_syms_file);
+
+		return;
+	}
+
+	if (-e "$gitroot") {
+		my @syms = `${git_command} grep -P -oh '^\\s*config\\s+\\w+' -- '*/Kconfig*'`;
+		s/^\s+// for @syms;
+		s/config\s+// for @syms;
+		s/\n$// for @syms;
+		@syms = sort(uniq(@syms));
+		foreach my $sym (@syms) {
+			$Kconfig_syms{$sym} = 1;
+		}
+	} else {
+		foreach my $file (@Kconfig_files) {
+			seed_Kconfig_file($file);
+		}
+	}
+
+	if ($Kconfig_syms_cache ne "") {
+		unlink glob ".checkpatch-Kconfig_syms.*";
+		open(my $Kconfig_syms_file, '>', "$Kconfig_syms_cache")
+		    or warn "$P: Can't write '$Kconfig_syms_cache' $!\n";
+		foreach (sort { lc($a) cmp lc($b) } keys(%Kconfig_syms)) {
+			print $Kconfig_syms_file ("$_\n");
+		}
+		close($Kconfig_syms_file);
+	}
+}
+
 my $camelcase_seeded = 0;
 sub seed_camelcase_includes {
 	return if ($camelcase_seeded);
@@ -6480,6 +6565,22 @@ sub process {
 			}
 		}
 
+# check for IS_ENABLED() used without CONFIG_<FOO> ($rawline for comment use)
+# or if the CONFIG_<FOO> symbol is not a known Kconfig entry
+		if ($rawline =~ /\bIS_ENABLED\s*\(\s*(\w+)\s*\)/) {
+			my $sym = $1;
+			seed_Kconfig_symbols();
+		        if ($sym !~ /^CONFIG_/) {
+				WARN("IS_ENABLED_CONFIG",
+				     "IS_ENABLED($sym) is normally used as IS_ENABLED(CONFIG_$1)\n" . $herecurr);
+			}
+			if (!exists($Kconfig_syms{$sym})) {
+				WARN("IS_ENABLED_CONFIG",
+				     "'$sym' is not a known Kconfig config entry in the current kernel sources\n" . $herecurr);
+
+			}
+		}
+
 # check for #if defined CONFIG_<FOO> || defined CONFIG_<FOO>_MODULE
 		if ($line =~ /^\+\s*#\s*if\s+defined(?:\s*\(?\s*|\s+)(CONFIG_[A-Z_]+)\s*\)?\s*\|\|\s*defined(?:\s*\(?\s*|\s+)\1_MODULE\s*\)?\s*$/) {
 			my $config = $1;


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ