cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

streamline_config.pl (16820B)


      1#!/usr/bin/env perl
      2# SPDX-License-Identifier: GPL-2.0
      3#
      4# Copyright 2005-2009 - Steven Rostedt
      5#
      6#  It's simple enough to figure out how this works.
      7#  If not, then you can ask me at stripconfig@goodmis.org
      8#
      9# What it does?
     10#
     11#   If you have installed a Linux kernel from a distribution
     12#   that turns on way too many modules than you need, and
     13#   you only want the modules you use, then this program
     14#   is perfect for you.
     15#
     16#   It gives you the ability to turn off all the modules that are
     17#   not loaded on your system.
     18#
     19# Howto:
     20#
     21#  1. Boot up the kernel that you want to stream line the config on.
     22#  2. Change directory to the directory holding the source of the
     23#       kernel that you just booted.
     24#  3. Copy the configuration file to this directory as .config
     25#  4. Have all your devices that you need modules for connected and
     26#      operational (make sure that their corresponding modules are loaded)
     27#  5. Run this script redirecting the output to some other file
     28#       like config_strip.
     29#  6. Back up your old config (if you want too).
     30#  7. copy the config_strip file to .config
     31#  8. Run "make oldconfig"
     32#
     33#  Now your kernel is ready to be built with only the modules that
     34#  are loaded.
     35#
     36# Here's what I did with my Debian distribution.
     37#
     38#    cd /usr/src/linux-2.6.10
     39#    cp /boot/config-2.6.10-1-686-smp .config
     40#    ~/bin/streamline_config > config_strip
     41#    mv .config config_sav
     42#    mv config_strip .config
     43#    make oldconfig
     44#
     45use warnings;
     46use strict;
     47use Getopt::Long;
     48
     49# set the environment variable LOCALMODCONFIG_DEBUG to get
     50# debug output.
     51my $debugprint = 0;
     52$debugprint = 1 if (defined($ENV{LOCALMODCONFIG_DEBUG}));
     53
     54sub dprint {
     55    return if (!$debugprint);
     56    print STDERR @_;
     57}
     58
     59my $uname = `uname -r`;
     60chomp $uname;
     61
     62my @searchconfigs = (
     63	{
     64	    "file" => ".config",
     65	    "exec" => "cat",
     66	},
     67	{
     68	    "file" => "/proc/config.gz",
     69	    "exec" => "zcat",
     70	},
     71	{
     72	    "file" => "/boot/config-$uname",
     73	    "exec" => "cat",
     74	},
     75	{
     76	    "file" => "/boot/vmlinuz-$uname",
     77	    "exec" => "scripts/extract-ikconfig",
     78	    "test" => "scripts/extract-ikconfig",
     79	},
     80	{
     81	    "file" => "vmlinux",
     82	    "exec" => "scripts/extract-ikconfig",
     83	    "test" => "scripts/extract-ikconfig",
     84	},
     85	{
     86	    "file" => "/lib/modules/$uname/kernel/kernel/configs.ko",
     87	    "exec" => "scripts/extract-ikconfig",
     88	    "test" => "scripts/extract-ikconfig",
     89	},
     90	{
     91	    "file" => "kernel/configs.ko",
     92	    "exec" => "scripts/extract-ikconfig",
     93	    "test" => "scripts/extract-ikconfig",
     94	},
     95	{
     96	    "file" => "kernel/configs.o",
     97	    "exec" => "scripts/extract-ikconfig",
     98	    "test" => "scripts/extract-ikconfig",
     99	},
    100);
    101
    102sub read_config {
    103    foreach my $conf (@searchconfigs) {
    104	my $file = $conf->{"file"};
    105
    106	next if ( ! -f "$file");
    107
    108	if (defined($conf->{"test"})) {
    109	    `$conf->{"test"} $conf->{"file"} 2>/dev/null`;
    110	    next if ($?);
    111	}
    112
    113	my $exec = $conf->{"exec"};
    114
    115	print STDERR "using config: '$file'\n";
    116
    117	open(my $infile, '-|', "$exec $file") || die "Failed to run $exec $file";
    118	my @x = <$infile>;
    119	close $infile;
    120	return @x;
    121    }
    122    die "No config file found";
    123}
    124
    125my @config_file = read_config;
    126
    127# Parse options
    128my $localmodconfig = 0;
    129my $localyesconfig = 0;
    130
    131GetOptions("localmodconfig" => \$localmodconfig,
    132	   "localyesconfig" => \$localyesconfig);
    133
    134# Get the build source and top level Kconfig file (passed in)
    135my $ksource = ($ARGV[0] ? $ARGV[0] : '.');
    136my $kconfig = $ARGV[1];
    137my $lsmod_file = $ENV{'LSMOD'};
    138
    139my @makefiles = `find $ksource -name Makefile -or -name Kbuild 2>/dev/null`;
    140chomp @makefiles;
    141
    142my %depends;
    143my %selects;
    144my %prompts;
    145my %objects;
    146my %config2kfile;
    147my $var;
    148my $iflevel = 0;
    149my @ifdeps;
    150
    151# prevent recursion
    152my %read_kconfigs;
    153
    154sub read_kconfig {
    155    my ($kconfig) = @_;
    156
    157    my $state = "NONE";
    158    my $config;
    159
    160    my $cont = 0;
    161    my $line;
    162
    163    my $source = "$ksource/$kconfig";
    164    my $last_source = "";
    165
    166    # Check for any environment variables used
    167    while ($source =~ /\$\((\w+)\)/ && $last_source ne $source) {
    168	my $env = $1;
    169	$last_source = $source;
    170	$source =~ s/\$\($env\)/$ENV{$env}/;
    171    }
    172
    173    open(my $kinfile, '<', $source) || die "Can't open $source";
    174    while (<$kinfile>) {
    175	chomp;
    176
    177	# Make sure that lines ending with \ continue
    178	if ($cont) {
    179	    $_ = $line . " " . $_;
    180	}
    181
    182	if (s/\\$//) {
    183	    $cont = 1;
    184	    $line = $_;
    185	    next;
    186	}
    187
    188	$cont = 0;
    189
    190	# collect any Kconfig sources
    191	if (/^source\s+"?([^"]+)/) {
    192	    my $kconfig = $1;
    193	    # prevent reading twice.
    194	    if (!defined($read_kconfigs{$kconfig})) {
    195		$read_kconfigs{$kconfig} = 1;
    196		read_kconfig($kconfig);
    197	    }
    198	    next;
    199	}
    200
    201	# configs found
    202	if (/^\s*(menu)?config\s+(\S+)\s*$/) {
    203	    $state = "NEW";
    204	    $config = $2;
    205	    $config2kfile{"CONFIG_$config"} = $kconfig;
    206
    207	    # Add depends for 'if' nesting
    208	    for (my $i = 0; $i < $iflevel; $i++) {
    209		if ($i) {
    210		    $depends{$config} .= " " . $ifdeps[$i];
    211		} else {
    212		    $depends{$config} = $ifdeps[$i];
    213		}
    214		$state = "DEP";
    215	    }
    216
    217	# collect the depends for the config
    218	} elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) {
    219	    $state = "DEP";
    220	    $depends{$config} = $1;
    221	} elsif ($state eq "DEP" && /^\s*depends\s+on\s+(.*)$/) {
    222	    $depends{$config} .= " " . $1;
    223	} elsif ($state eq "DEP" && /^\s*def(_(bool|tristate)|ault)\s+(\S.*)$/) {
    224	    my $dep = $3;
    225	    if ($dep !~ /^\s*(y|m|n)\s*$/) {
    226		$dep =~ s/.*\sif\s+//;
    227		$depends{$config} .= " " . $dep;
    228		dprint "Added default depends $dep to $config\n";
    229	    }
    230
    231	# Get the configs that select this config
    232	} elsif ($state ne "NONE" && /^\s*select\s+(\S+)/) {
    233	    my $conf = $1;
    234	    if (defined($selects{$conf})) {
    235		$selects{$conf} .= " " . $config;
    236	    } else {
    237		$selects{$conf} = $config;
    238	    }
    239
    240	# configs without prompts must be selected
    241	} elsif ($state ne "NONE" && /^\s*(tristate\s+\S|prompt\b)/) {
    242	    # note if the config has a prompt
    243	    $prompts{$config} = 1;
    244
    245	# Check for if statements
    246	} elsif (/^if\s+(.*\S)\s*$/) {
    247	    my $deps = $1;
    248	    # remove beginning and ending non text
    249	    $deps =~ s/^[^a-zA-Z0-9_]*//;
    250	    $deps =~ s/[^a-zA-Z0-9_]*$//;
    251
    252	    my @deps = split /[^a-zA-Z0-9_]+/, $deps;
    253
    254	    $ifdeps[$iflevel++] = join ':', @deps;
    255
    256	} elsif (/^endif/) {
    257
    258	    $iflevel-- if ($iflevel);
    259
    260	# stop on "help" and keywords that end a menu entry
    261	} elsif (/^\s*(---)?help(---)?\s*$/ || /^(comment|choice|menu)\b/) {
    262	    $state = "NONE";
    263	}
    264    }
    265    close($kinfile);
    266}
    267
    268if ($kconfig) {
    269    read_kconfig($kconfig);
    270}
    271
    272# Makefiles can use variables to define their dependencies
    273sub convert_vars {
    274    my ($line, %vars) = @_;
    275
    276    my $process = "";
    277
    278    while ($line =~ s/^(.*?)(\$\((.*?)\))//) {
    279	my $start = $1;
    280	my $variable = $2;
    281	my $var = $3;
    282
    283	if (defined($vars{$var})) {
    284	    $process .= $start . $vars{$var};
    285	} else {
    286	    $process .= $start . $variable;
    287	}
    288    }
    289
    290    $process .= $line;
    291
    292    return $process;
    293}
    294
    295# Read all Makefiles to map the configs to the objects
    296foreach my $makefile (@makefiles) {
    297
    298    my $line = "";
    299    my %make_vars;
    300
    301    open(my $infile, '<', $makefile) || die "Can't open $makefile";
    302    while (<$infile>) {
    303	# if this line ends with a backslash, continue
    304	chomp;
    305	if (/^(.*)\\$/) {
    306	    $line .= $1;
    307	    next;
    308	}
    309
    310	$line .= $_;
    311	$_ = $line;
    312	$line = "";
    313
    314	my $objs;
    315
    316	# Convert variables in a line (could define configs)
    317	$_ = convert_vars($_, %make_vars);
    318
    319	# collect objects after obj-$(CONFIG_FOO_BAR)
    320	if (/obj-\$\((CONFIG_[^\)]*)\)\s*[+:]?=\s*(.*)/) {
    321	    $var = $1;
    322	    $objs = $2;
    323
    324	# check if variables are set
    325	} elsif (/^\s*(\S+)\s*[:]?=\s*(.*\S)/) {
    326	    $make_vars{$1} = $2;
    327	}
    328	if (defined($objs)) {
    329	    foreach my $obj (split /\s+/,$objs) {
    330		$obj =~ s/-/_/g;
    331		if ($obj =~ /(.*)\.o$/) {
    332		    # Objects may be enabled by more than one config.
    333		    # Store configs in an array.
    334		    my @arr;
    335
    336		    if (defined($objects{$1})) {
    337			@arr = @{$objects{$1}};
    338		    }
    339
    340		    $arr[$#arr+1] = $var;
    341
    342		    # The objects have a hash mapping to a reference
    343		    # of an array of configs.
    344		    $objects{$1} = \@arr;
    345		}
    346	    }
    347	}
    348    }
    349    close($infile);
    350}
    351
    352my %modules;
    353my $linfile;
    354
    355if (defined($lsmod_file)) {
    356    if ( ! -f $lsmod_file) {
    357	if ( -f $ENV{'objtree'}."/".$lsmod_file) {
    358	    $lsmod_file = $ENV{'objtree'}."/".$lsmod_file;
    359	} else {
    360		die "$lsmod_file not found";
    361	}
    362    }
    363
    364    my $otype = ( -x $lsmod_file) ? '-|' : '<';
    365    open($linfile, $otype, $lsmod_file);
    366
    367} else {
    368
    369    # see what modules are loaded on this system
    370    my $lsmod;
    371
    372    foreach my $dir ( ("/sbin", "/bin", "/usr/sbin", "/usr/bin") ) {
    373	if ( -x "$dir/lsmod" ) {
    374	    $lsmod = "$dir/lsmod";
    375	    last;
    376	}
    377    }
    378    if (!defined($lsmod)) {
    379	# try just the path
    380	$lsmod = "lsmod";
    381    }
    382
    383    open($linfile, '-|', $lsmod) || die "Can not call lsmod with $lsmod";
    384}
    385
    386while (<$linfile>) {
    387	next if (/^Module/);  # Skip the first line.
    388	if (/^(\S+)/) {
    389		$modules{$1} = 1;
    390	}
    391}
    392close ($linfile);
    393
    394# add to the configs hash all configs that are needed to enable
    395# a loaded module. This is a direct obj-${CONFIG_FOO} += bar.o
    396# where we know we need bar.o so we add FOO to the list.
    397my %configs;
    398foreach my $module (keys(%modules)) {
    399    if (defined($objects{$module})) {
    400	my @arr = @{$objects{$module}};
    401	foreach my $conf (@arr) {
    402	    $configs{$conf} = $module;
    403	    dprint "$conf added by direct ($module)\n";
    404	    if ($debugprint) {
    405		my $c=$conf;
    406		$c =~ s/^CONFIG_//;
    407		if (defined($depends{$c})) {
    408		    dprint " deps = $depends{$c}\n";
    409		} else {
    410		    dprint " no deps\n";
    411		}
    412	    }
    413	}
    414    } else {
    415	# Most likely, someone has a custom (binary?) module loaded.
    416	print STDERR "$module config not found!!\n";
    417    }
    418}
    419
    420# Read the current config, and see what is enabled. We want to
    421# ignore configs that we would not enable anyway.
    422
    423my %orig_configs;
    424my $valid = "A-Za-z_0-9";
    425
    426foreach my $line (@config_file) {
    427    $_ = $line;
    428
    429    if (/(CONFIG_[$valid]*)=(m|y)/) {
    430	$orig_configs{$1} = $2;
    431    }
    432}
    433
    434my $repeat = 1;
    435
    436my $depconfig;
    437
    438#
    439# Note, we do not care about operands (like: &&, ||, !) we want to add any
    440# config that is in the depend list of another config. This script does
    441# not enable configs that are not already enabled. If we come across a
    442# config A that depends on !B, we can still add B to the list of depends
    443# to keep on. If A was on in the original config, B would not have been
    444# and B would not be turned on by this script.
    445#
    446sub parse_config_depends
    447{
    448    my ($p) = @_;
    449
    450    while ($p =~ /[$valid]/) {
    451
    452	if ($p =~ /^[^$valid]*([$valid]+)/) {
    453	    my $conf = "CONFIG_" . $1;
    454
    455	    $p =~ s/^[^$valid]*[$valid]+//;
    456
    457	    # We only need to process if the depend config is a module
    458	    if (!defined($orig_configs{$conf}) || $orig_configs{$conf} eq "y") {
    459		next;
    460	    }
    461
    462	    if (!defined($configs{$conf})) {
    463		# We must make sure that this config has its
    464		# dependencies met.
    465		$repeat = 1; # do again
    466		dprint "$conf selected by depend $depconfig\n";
    467		$configs{$conf} = 1;
    468	    }
    469	} else {
    470	    die "this should never happen";
    471	}
    472    }
    473}
    474
    475# Select is treated a bit differently than depends. We call this
    476# when a config has no prompt and requires another config to be
    477# selected. We use to just select all configs that selected this
    478# config, but found that that can balloon into enabling hundreds
    479# of configs that we do not care about.
    480#
    481# The idea is we look at all the configs that select it. If one
    482# is already in our list of configs to enable, then there's nothing
    483# else to do. If there isn't, we pick the first config that was
    484# enabled in the original config and use that.
    485sub parse_config_selects
    486{
    487    my ($config, $p) = @_;
    488
    489    my $next_config;
    490
    491    while ($p =~ /[$valid]/) {
    492
    493	if ($p =~ /^[^$valid]*([$valid]+)/) {
    494	    my $conf = "CONFIG_" . $1;
    495
    496	    $p =~ s/^[^$valid]*[$valid]+//;
    497
    498	    # Make sure that this config exists in the current .config file
    499	    if (!defined($orig_configs{$conf})) {
    500		dprint "$conf not set for $config select\n";
    501		next;
    502	    }
    503
    504	    # Check if something other than a module selects this config
    505	    if (defined($orig_configs{$conf}) && $orig_configs{$conf} ne "m") {
    506		dprint "$conf (non module) selects config, we are good\n";
    507		# we are good with this
    508		return;
    509	    }
    510	    if (defined($configs{$conf})) {
    511		dprint "$conf selects $config so we are good\n";
    512		# A set config selects this config, we are good
    513		return;
    514	    }
    515	    # Set this config to be selected
    516	    if (!defined($next_config)) {
    517		$next_config = $conf;
    518	    }
    519	} else {
    520	    die "this should never happen";
    521	}
    522    }
    523
    524    # If no possible config selected this, then something happened.
    525    if (!defined($next_config)) {
    526	print STDERR "WARNING: $config is required, but nothing in the\n";
    527	print STDERR "  current config selects it.\n";
    528	return;
    529    }
    530
    531    # If we are here, then we found no config that is set and
    532    # selects this config. Repeat.
    533    $repeat = 1;
    534    # Make this config need to be selected
    535    $configs{$next_config} = 1;
    536    dprint "$next_config selected by select $config\n";
    537}
    538
    539my %process_selects;
    540
    541# loop through all configs, select their dependencies.
    542sub loop_depend {
    543    $repeat = 1;
    544
    545    while ($repeat) {
    546	$repeat = 0;
    547
    548      forloop:
    549	foreach my $config (keys %configs) {
    550
    551	    # If this config is not a module, we do not need to process it
    552	    if (defined($orig_configs{$config}) && $orig_configs{$config} ne "m") {
    553		next forloop;
    554	    }
    555
    556	    $config =~ s/^CONFIG_//;
    557	    $depconfig = $config;
    558
    559	    if (defined($depends{$config})) {
    560		# This config has dependencies. Make sure they are also included
    561		parse_config_depends $depends{$config};
    562	    }
    563
    564	    # If the config has no prompt, then we need to check if a config
    565	    # that is enabled selected it. Or if we need to enable one.
    566	    if (!defined($prompts{$config}) && defined($selects{$config})) {
    567		$process_selects{$config} = 1;
    568	    }
    569	}
    570    }
    571}
    572
    573sub loop_select {
    574
    575    foreach my $config (keys %process_selects) {
    576	$config =~ s/^CONFIG_//;
    577
    578	dprint "Process select $config\n";
    579
    580	# config has no prompt and must be selected.
    581	parse_config_selects $config, $selects{$config};
    582    }
    583}
    584
    585while ($repeat) {
    586    # Get the first set of configs and their dependencies.
    587    loop_depend;
    588
    589    $repeat = 0;
    590
    591    # Now we need to see if we have to check selects;
    592    loop_select;
    593}
    594
    595my %setconfigs;
    596my @preserved_kconfigs;
    597if (defined($ENV{'LMC_KEEP'})) {
    598	@preserved_kconfigs = split(/:/,$ENV{LMC_KEEP});
    599}
    600
    601sub in_preserved_kconfigs {
    602    my $kconfig = $config2kfile{$_[0]};
    603    if (!defined($kconfig)) {
    604	return 0;
    605    }
    606    foreach my $excl (@preserved_kconfigs) {
    607	if($kconfig =~ /^$excl/) {
    608	    return 1;
    609	}
    610    }
    611    return 0;
    612}
    613
    614# Finally, read the .config file and turn off any module enabled that
    615# we could not find a reason to keep enabled.
    616foreach my $line (@config_file) {
    617    $_ = $line;
    618
    619    if (/CONFIG_IKCONFIG/) {
    620	if (/# CONFIG_IKCONFIG is not set/) {
    621	    # enable IKCONFIG at least as a module
    622	    print "CONFIG_IKCONFIG=m\n";
    623	    # don't ask about PROC
    624	    print "# CONFIG_IKCONFIG_PROC is not set\n";
    625	} else {
    626	    print;
    627	}
    628	next;
    629    }
    630
    631    if (/CONFIG_MODULE_SIG_KEY="(.+)"/) {
    632	my $orig_cert = $1;
    633	my $default_cert = "certs/signing_key.pem";
    634
    635	# Check that the logic in this script still matches the one in Kconfig
    636	if (!defined($depends{"MODULE_SIG_KEY"}) ||
    637	    $depends{"MODULE_SIG_KEY"} !~ /"\Q$default_cert\E"/) {
    638	    print STDERR "WARNING: MODULE_SIG_KEY assertion failure, ",
    639		"update needed to ", __FILE__, " line ", __LINE__, "\n";
    640	    print;
    641	} elsif ($orig_cert ne $default_cert && ! -f $orig_cert) {
    642	    print STDERR "Module signature verification enabled but ",
    643		"module signing key \"$orig_cert\" not found. Resetting ",
    644		"signing key to default value.\n";
    645	    print "CONFIG_MODULE_SIG_KEY=\"$default_cert\"\n";
    646	} else {
    647	    print;
    648	}
    649	next;
    650    }
    651
    652    if (/CONFIG_SYSTEM_TRUSTED_KEYS="(.+)"/) {
    653	my $orig_keys = $1;
    654
    655	if (! -f $orig_keys) {
    656	    print STDERR "System keyring enabled but keys \"$orig_keys\" ",
    657		"not found. Resetting keys to default value.\n";
    658	    print "CONFIG_SYSTEM_TRUSTED_KEYS=\"\"\n";
    659	} else {
    660	    print;
    661	}
    662	next;
    663    }
    664
    665    if (/^(CONFIG.*)=(m|y)/) {
    666	if (in_preserved_kconfigs($1)) {
    667	    dprint "Preserve config $1";
    668	    print;
    669	    next;
    670	}
    671	if (defined($configs{$1})) {
    672	    if ($localyesconfig) {
    673		$setconfigs{$1} = 'y';
    674		print "$1=y\n";
    675		next;
    676	    } else {
    677		$setconfigs{$1} = $2;
    678	    }
    679	} elsif ($2 eq "m") {
    680	    print "# $1 is not set\n";
    681	    next;
    682	}
    683    }
    684    print;
    685}
    686
    687# Integrity check, make sure all modules that we want enabled do
    688# indeed have their configs set.
    689loop:
    690foreach my $module (keys(%modules)) {
    691    if (defined($objects{$module})) {
    692	my @arr = @{$objects{$module}};
    693	foreach my $conf (@arr) {
    694	    if (defined($setconfigs{$conf})) {
    695		next loop;
    696	    }
    697	}
    698	print STDERR "module $module did not have configs";
    699	foreach my $conf (@arr) {
    700	    print STDERR " " , $conf;
    701	}
    702	print STDERR "\n";
    703    }
    704}
    705
    706# vim: softtabstop=4