new file mode 100644
@@ -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
@@ -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.%
@@ -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
new file mode 100755
@@ -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 <config> <arch> <flavour> <commonconfig> <warn-only>\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 <arch>\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 <flavour>\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 <name> <val>\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 <name>\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 (<CONFIG>) {
+ # 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 (<CHECKS>) {
+ /^#/ && 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;
@@ -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.<arch> 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
+
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 <apw@canonical.com> --- 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