aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2015-10-21 09:04:47 -0400
committerDavid Howells <dhowells@redhat.com>2015-10-21 10:18:36 -0400
commit2221a6ee73e7c8f43af802a1ef9426d4b0d122d3 (patch)
tree2d44a90830df72ff6d85ce6d806b05176da9bbf9 /scripts
parent27720e75a7a1597252a81dadcd178331c83af861 (diff)
KEYS: Provide a script to extract the sys cert list from a vmlinux file
The supplied script takes a vmlinux file - and if necessary a System.map file - locates the system certificates list and extracts it to the named file. Call as: ./scripts/extract-sys-certs vmlinux certs if vmlinux contains symbols and: ./scripts/extract-sys-certs -s System.map vmlinux certs if it does not. It prints something like the following to stdout: Have 27 sections No symbols in vmlinux, trying System.map Have 80088 symbols Have 1346 bytes of certs at VMA 0xffffffff8201c540 Certificate list in section .init.data Certificate list at file offset 0x141c540 If vmlinux contains symbols then that is used rather than System.map - even if one is given. Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/extract-sys-certs.pl144
1 files changed, 144 insertions, 0 deletions
diff --git a/scripts/extract-sys-certs.pl b/scripts/extract-sys-certs.pl
new file mode 100755
index 000000000000..d476e7d1fd88
--- /dev/null
+++ b/scripts/extract-sys-certs.pl
@@ -0,0 +1,144 @@
1#!/usr/bin/perl -w
2#
3use strict;
4use Math::BigInt;
5use Fcntl "SEEK_SET";
6
7die "Format: $0 [-s <systemmap-file>] <vmlinux-file> <keyring-file>\n"
8 if ($#ARGV != 1 && $#ARGV != 3 ||
9 $#ARGV == 3 && $ARGV[0] ne "-s");
10
11my $sysmap = "";
12if ($#ARGV == 3) {
13 shift;
14 $sysmap = $ARGV[0];
15 shift;
16}
17
18my $vmlinux = $ARGV[0];
19my $keyring = $ARGV[1];
20
21#
22# Parse the vmlinux section table
23#
24open FD, "objdump -h $vmlinux |" || die $vmlinux;
25my @lines = <FD>;
26close(FD) || die $vmlinux;
27
28my @sections = ();
29
30foreach my $line (@lines) {
31 chomp($line);
32 if ($line =~ /\s*([0-9]+)\s+(\S+)\s+([0-9a-f]+)\s+([0-9a-f]+)\s+([0-9a-f]+)\s+([0-9a-f]+)\s+2[*][*]([0-9]+)/
33 ) {
34 my $seg = $1;
35 my $name = $2;
36 my $len = Math::BigInt->new("0x" . $3);
37 my $vma = Math::BigInt->new("0x" . $4);
38 my $lma = Math::BigInt->new("0x" . $5);
39 my $foff = Math::BigInt->new("0x" . $6);
40 my $align = 2 ** $7;
41
42 push @sections, { name => $name,
43 vma => $vma,
44 len => $len,
45 foff => $foff };
46 }
47}
48
49print "Have $#sections sections\n";
50
51#
52# Try and parse the vmlinux symbol table. If the vmlinux file has been created
53# from a vmlinuz file with extract-vmlinux then the symbol table will be empty.
54#
55open FD, "nm $vmlinux 2>/dev/null |" || die $vmlinux;
56@lines = <FD>;
57close(FD) || die $vmlinux;
58
59my %symbols = ();
60my $nr_symbols = 0;
61
62sub parse_symbols(@) {
63 foreach my $line (@_) {
64 chomp($line);
65 if ($line =~ /([0-9a-f]+)\s([a-zA-Z])\s(\S+)/
66 ) {
67 my $addr = "0x" . $1;
68 my $type = $2;
69 my $name = $3;
70
71 $symbols{$name} = $addr;
72 $nr_symbols++;
73 }
74 }
75}
76parse_symbols(@lines);
77
78if ($nr_symbols == 0 && $sysmap ne "") {
79 print "No symbols in vmlinux, trying $sysmap\n";
80
81 open FD, "<$sysmap" || die $sysmap;
82 @lines = <FD>;
83 close(FD) || die $sysmap;
84 parse_symbols(@lines);
85}
86
87die "No symbols available\n"
88 if ($nr_symbols == 0);
89
90print "Have $nr_symbols symbols\n";
91
92die "Can't find system certificate list"
93 unless (exists($symbols{"__cert_list_start"}) &&
94 exists($symbols{"__cert_list_end"}));
95
96my $start = Math::BigInt->new($symbols{"__cert_list_start"});
97my $end = Math::BigInt->new($symbols{"__cert_list_end"});
98my $size = $end - $start;
99
100printf "Have %u bytes of certs at VMA 0x%x\n", $size, $start;
101
102my $s = undef;
103foreach my $sec (@sections) {
104 my $s_name = $sec->{name};
105 my $s_vma = $sec->{vma};
106 my $s_len = $sec->{len};
107 my $s_foff = $sec->{foff};
108 my $s_vend = $s_vma + $s_len;
109
110 next unless ($start >= $s_vma);
111 next if ($start >= $s_vend);
112
113 die "Cert object partially overflows section $s_name\n"
114 if ($end > $s_vend);
115
116 die "Cert object in multiple sections: ", $s_name, " and ", $s->{name}, "\n"
117 if ($s);
118 $s = $sec;
119}
120
121die "Cert object not inside a section\n"
122 unless ($s);
123
124print "Certificate list in section ", $s->{name}, "\n";
125
126my $foff = $start - $s->{vma} + $s->{foff};
127
128printf "Certificate list at file offset 0x%x\n", $foff;
129
130open FD, "<$vmlinux" || die $vmlinux;
131binmode(FD);
132die $vmlinux if (!defined(sysseek(FD, $foff, SEEK_SET)));
133my $buf = "";
134my $len = sysread(FD, $buf, $size);
135die "$vmlinux" if (!defined($len));
136die "Short read on $vmlinux\n" if ($len != $size);
137close(FD) || die $vmlinux;
138
139open FD, ">$keyring" || die $keyring;
140binmode(FD);
141$len = syswrite(FD, $buf, $size);
142die "$keyring" if (!defined($len));
143die "Short write on $keyring\n" if ($len != $size);
144close(FD) || die $keyring;