From patchwork Tue Dec 15 17:19:57 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Whitcroft X-Patchwork-Id: 41205 X-Patchwork-Delegate: apw@canonical.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from chlorine.canonical.com (chlorine.canonical.com [91.189.94.204]) by ozlabs.org (Postfix) with ESMTP id 87504B6F10 for ; Wed, 16 Dec 2009 04:20:17 +1100 (EST) Received: from localhost ([127.0.0.1] helo=chlorine.canonical.com) by chlorine.canonical.com with esmtp (Exim 4.69) (envelope-from ) id 1NKb4F-0003Ab-Ac; Tue, 15 Dec 2009 17:20:11 +0000 Received: from adelie.canonical.com ([91.189.90.139]) by chlorine.canonical.com with esmtp (Exim 4.69) (envelope-from ) id 1NKb4B-00039e-8Q for kernel-team@lists.ubuntu.com; Tue, 15 Dec 2009 17:20:07 +0000 Received: from hutte.canonical.com ([91.189.90.181]) by adelie.canonical.com with esmtp (Exim 4.69 #1 (Debian)) id 1NKb48-0006Gs-1H for ; Tue, 15 Dec 2009 17:20:04 +0000 Received: from 79-66-207-78.dynamic.dsl.as9105.com ([79.66.207.78] helo=localhost.localdomain) by hutte.canonical.com with esmtpsa (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1NKb47-0001WO-PS for kernel-team@lists.ubuntu.com; Tue, 15 Dec 2009 17:20:04 +0000 From: Andy Whitcroft To: kernel-team@lists.ubuntu.com Subject: [PATCH 1/6] UBUNTU: config-check -- add a configuration enforcer Date: Tue, 15 Dec 2009 17:19:57 +0000 Message-Id: <1260897602-20420-2-git-send-email-apw@canonical.com> X-Mailer: git-send-email 1.6.3.3 In-Reply-To: <1260897602-20420-1-git-send-email-apw@canonical.com> References: <1260897602-20420-1-git-send-email-apw@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.9 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: kernel-team-bounces@lists.ubuntu.com Errors-To: kernel-team-bounces@lists.ubuntu.com Add a new configuration option value checker and enforcer. This allow us to specify the values we expect various configuration options to have and to do that depending on the architecture and flavour of the build. This is applied both as an early build check and at updateconfigs time. Signed-off-by: Andy Whitcroft --- debian.master/config/enforce | 25 ++++ debian.master/rules.d/2-binary-arch.mk | 2 +- debian.master/rules.d/4-checks.mk | 8 ++ debian.master/scripts/config-check | 187 +++++++++++++++++++++++++++++++ debian.master/scripts/misc/kernelconfig | 25 ++++- 5 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 debian.master/config/enforce create mode 100755 debian.master/scripts/config-check diff --git a/debian.master/config/enforce b/debian.master/config/enforce new file mode 100644 index 0000000..605ab65 --- /dev/null +++ b/debian.master/config/enforce @@ -0,0 +1,25 @@ +# +# SECURITY items +# +# Ensure this option is enabled. +value CONFIG_COMPAT_BRK n +value CONFIG_DEVKMEM n +value CONFIG_LSM_MMAP_MIN_ADDR 0 +value CONFIG_SECCOMP y +value CONFIG_SECURITY y +value CONFIG_SECURITY_FILE_CAPABILITIES y +value CONFIG_SECURITY_SMACK y +value CONFIG_SYN_COOKIES y +# For architectures which support this option ensure it is enabled. +!exists CONFIG_CC_STACKPROTECTOR | value CONFIG_CC_STACKPROTECTOR y +!exists CONFIG_DEBUG_RODATA | value CONFIG_DEBUG_RODATA y +!exists CONFIG_STRICT_DEVMEM | value CONFIG_STRICT_DEVMEM y +# For architectures which support this option ensure it is disabled. +!exists CONFIG_COMPAT_VDSO | value CONFIG_COMPAT_VDSO n +# Default to 32768 for armel, 65536 for everything else. +(( arch armel | arch sparc ) & value CONFIG_DEFAULT_MMAP_MIN_ADDR 32768 ) | \ + ( value CONFIG_DEFAULT_MMAP_MIN_ADDR 65536) + +# CONFIG_USB_DEVICE_FS breaks udev USB firmware loading and is deprecated +# ensure it is disabled. +value CONFIG_USB_DEVICEFS n diff --git a/debian.master/rules.d/2-binary-arch.mk b/debian.master/rules.d/2-binary-arch.mk index e6bba87..d909d89 100644 --- a/debian.master/rules.d/2-binary-arch.mk +++ b/debian.master/rules.d/2-binary-arch.mk @@ -3,7 +3,7 @@ # Prepare the out-of-tree build directory -prepare-%: $(stampdir)/stamp-prepare-% +prepare-%: $(stampdir)/stamp-prepare-% prepare-checks-% @# Empty for make to be happy $(stampdir)/stamp-prepare-%: target_flavour = $* $(stampdir)/stamp-prepare-%: $(commonconfdir)/config.common.$(family) $(archconfdir)/config.common.$(arch) $(archconfdir)/config.flavour.% diff --git a/debian.master/rules.d/4-checks.mk b/debian.master/rules.d/4-checks.mk index 778984c..093639e 100644 --- a/debian.master/rules.d/4-checks.mk +++ b/debian.master/rules.d/4-checks.mk @@ -24,3 +24,11 @@ module-check-%: $(abidir)/%.modules checks-%: abi-check-% module-check-% @# Will be calling more stuff later + +# Check the config against the known options list. +config-prepare-check-%: $(stampdir)/stamp-prepare-% + @perl -f $(DEBIAN)/scripts/config-check \ + $(builddir)/build-$*/.config "$(arch)" "$*" "$(commonconfdir)" "$(skipconfig)" + +prepare-checks-%: config-prepare-check-% + @# Will be calling more stuff later diff --git a/debian.master/scripts/config-check b/debian.master/scripts/config-check new file mode 100755 index 0000000..48409f7 --- /dev/null +++ b/debian.master/scripts/config-check @@ -0,0 +1,187 @@ +#!/usr/bin/perl +# +# check-config -- check the current config for issues +# +use strict; + +my $P = 'check-config'; + +if ($#ARGV != 4) { + die "Usage: $P \n"; +} + +my ($config, $arch, $flavour, $commonconfig, $warn_only) = @ARGV; + +my $checks = "$commonconfig/enforce"; +my %values = (); + +# If we are in overridden then still perform the checks and emit the messages +# but do not return failure. Those items marked FATAL will alway trigger +# failure. +my $fail_exit = 1; +$fail_exit = 0 if ($warn_only eq 'true' || $warn_only eq '1'); +my $exit_val = 0; + +# Predicate execution engine. +sub pred_first { + my ($rest) = @_; + my $depth = 0; + my $off; + my $char; + my $pred; + + for ($off = 0; $off <= length($rest); $off++) { + $char = substr($rest, $off, 1); + if ($char eq '(') { + $depth++; + } elsif ($char eq ')') { + $depth--; + } elsif ($depth == 0 && $char eq '&') { + last; + } elsif ($depth == 0 && $char eq '|') { + last; + } + } + if ($depth > 0) { + die "$P: $rest: missing close parenthesis ')'\n"; + } elsif ($depth < 0) { + die "$P: $rest: missing open parenthesis '('\n"; + } + + ($pred, $rest) = (substr($rest, 0, $off), substr($rest, $off + 1)); + + $pred =~ s/^\s*//; + $pred =~ s/\s*$//; + + #print "pred<$pred> rest<$rest> char<$char>\n"; + ($pred, $rest, $char); +} + +sub pred_do { + my ($pred) = @_; + my (@a) = split(' ', $pred); + + if ($a[0] eq 'arch') { + die "$P: $pred: malformed -- $pred \n" if ($#a != 1); + #print " *** ARCH<$arch ?? $a[1]>\n"; + return ($arch eq $a[1]) + } elsif ($a[0] eq 'flavour') { + die "$P: $pred: malformed -- $pred \n" if ($#a != 1); + #print " *** FLAVOUR<$flavour ?? $a[1]>\n"; + return ($flavour eq $a[1]) + } elsif ($a[0] eq 'value') { + die "$P: $pred: malformed -- $pred \n" if ($#a != 2); + #print " *** CHECK<$a[1] $a[2] ?? " . $values{$a[1]} . ">\n"; + return ($values{$a[1]} eq $a[2]); + } elsif ($a[0] eq 'exists') { + die "$P: $pred: malformed -- $pred \n" if ($#a != 1); + return (defined $values{$a[1]}); + } else { + die "$P: $pred: unknown predicate\n"; + } + return 1; +} +sub pred_exec { + my ($rest) = @_; + my $pred; + my $res; + my $sep; + + #print "pred_exec<$rest>\n"; + + ($pred, $rest, $sep) = pred_first($rest); + + # Leading ! implies inversion. + if ($pred =~ /^\s*!\s*(.*)$/) { + #print " invert<$1>\n"; + $res = !pred_exec($1); + + # Recurse left for complex expressions. + } elsif ($pred =~ /^\s*\((.*)\)\s*$/) { + #print " left<$1>\n"; + $res = pred_exec($1); + + # Check for common syntax issues. + } elsif ($pred eq '') { + if ($sep eq '&' || $sep eq '|') { + die "$P: $pred$rest: malformed binary operator\n"; + } else { + die "$P: $pred$rest: syntax error\n"; + } + + # A predicate, execute it. + } else { + #print " DO<$pred> sep<$sep>\n"; + $res = pred_do($pred); + } + + #print " pre-return res<$res> sep<$sep>\n"; + if ($sep eq '') { + # + + # Recurse right for binary operators -- note these are lazy. + } elsif ($sep eq '&' || $sep eq '|') { + #print " right<$rest> ? sep<$sep> res<$res>\n"; + if ($rest =~ /^\s*($|\||\&)/) { + die "$P: $pred$rest: malformed binary operator\n"; + } + if (($res && $sep eq '&') || (!$res && $sep eq '|')) { + #print " right<$rest>\n"; + $res = pred_exec($rest); + } + + } else { + die "$P: $pred$rest: malformed predicate\n"; + } + #print " return res<$res> sep<$sep>\n"; + return $res; +} + +# Load up the current configuration values -- FATAL if this fails +print "$P: $config: loading config\n"; +open(CONFIG, "<$config") || die "$P: $config: open failed -- $! -- aborting\n"; +while () { + # Pull out values. + /^#*\s*(CONFIG_\w+)[\s=](.*)$/ or next; + if ($2 eq 'is not set') { + $values{$1} = 'n'; + } else { + $values{$1} = $2; + } +} +close(CONFIG); + +# FATAL: Check if we have an enforcement list. +my $pass = 0; +my $total = 0; +my $line = ''; +print "$P: $checks: loading checks\n"; +open(CHECKS, "<$checks") || die "$P: $checks: open failed -- $! -- aborting\n"; +while () { + /^#/ && next; + chomp; + + $line .= $_; + if ($line =~ /\\$/) { + chop($line); + $line .= " "; + next; + } + $line =~ /^\s*$/ && next; + + #print "CHECK: <$line>\n"; + $total++; + my $result = pred_exec($line); + if (!$result) { + print "$P: FAIL: $line\n"; + $exit_val = $fail_exit; + } else { + $pass++; + } + + $line = ''; +} +close(CHECKS); + +print "$P: $pass/$total checks passed -- exit $exit_val\n"; +exit $exit_val; diff --git a/debian.master/scripts/misc/kernelconfig b/debian.master/scripts/misc/kernelconfig index 4bf7c1d..c01624e 100755 --- a/debian.master/scripts/misc/kernelconfig +++ b/debian.master/scripts/misc/kernelconfig @@ -116,7 +116,6 @@ for arch in $archs; do done rm -f $common_conf -rm -rf build # Now run splitconfig.pl on all the config.common. copied to # $tmpdir @@ -130,3 +129,27 @@ rm -rf build >$arch/config.common.$arch done ) + +echo "" +echo "Running config-check for all configurations ..." +echo "" +fail=0 +for arch in $archs; do + archconfdir=$confdir/$arch + flavourconfigs=$(cd $archconfdir && ls config.flavour.*) + for config in $flavourconfigs; do + if [ -f $archconfdir/$config ]; then + fullconf="$tmpdir/$arch-$config-full" + "$bindir/../config-check" "$fullconf" "$arch" "$config" "$confdir" "0" || let "fail=$fail+1" + fi + done +done + +if [ "$fail" != 0 ]; then + echo "" + echo "*** ERROR: $fail config-check failures detected" + echo "" +fi + +rm -rf build +