xref: /openbmc/linux/scripts/extract-sys-certs.pl (revision 498495dba268b20e8eadd7fe93c140c68b6cc9d2)
1cb77f0d6SKamil Rytarowski#!/usr/bin/env perl
2*b2441318SGreg Kroah-Hartman# SPDX-License-Identifier: GPL-2.0
32221a6eeSDavid Howells#
4cb77f0d6SKamil Rytarowskiuse warnings;
52221a6eeSDavid Howellsuse strict;
62221a6eeSDavid Howellsuse Math::BigInt;
72221a6eeSDavid Howellsuse Fcntl "SEEK_SET";
82221a6eeSDavid Howells
92221a6eeSDavid Howellsdie "Format: $0 [-s <systemmap-file>] <vmlinux-file> <keyring-file>\n"
102221a6eeSDavid Howells    if ($#ARGV != 1 && $#ARGV != 3 ||
112221a6eeSDavid Howells	$#ARGV == 3 && $ARGV[0] ne "-s");
122221a6eeSDavid Howells
132221a6eeSDavid Howellsmy $sysmap = "";
142221a6eeSDavid Howellsif ($#ARGV == 3) {
152221a6eeSDavid Howells    shift;
162221a6eeSDavid Howells    $sysmap = $ARGV[0];
172221a6eeSDavid Howells    shift;
182221a6eeSDavid Howells}
192221a6eeSDavid Howells
202221a6eeSDavid Howellsmy $vmlinux = $ARGV[0];
212221a6eeSDavid Howellsmy $keyring = $ARGV[1];
222221a6eeSDavid Howells
232221a6eeSDavid Howells#
242221a6eeSDavid Howells# Parse the vmlinux section table
252221a6eeSDavid Howells#
262221a6eeSDavid Howellsopen FD, "objdump -h $vmlinux |" || die $vmlinux;
272221a6eeSDavid Howellsmy @lines = <FD>;
282221a6eeSDavid Howellsclose(FD) || die $vmlinux;
292221a6eeSDavid Howells
302221a6eeSDavid Howellsmy @sections = ();
312221a6eeSDavid Howells
322221a6eeSDavid Howellsforeach my $line (@lines) {
332221a6eeSDavid Howells    chomp($line);
342221a6eeSDavid Howells    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]+)/
352221a6eeSDavid Howells	) {
362221a6eeSDavid Howells	my $seg  = $1;
372221a6eeSDavid Howells	my $name = $2;
382221a6eeSDavid Howells	my $len  = Math::BigInt->new("0x" . $3);
392221a6eeSDavid Howells	my $vma  = Math::BigInt->new("0x" . $4);
402221a6eeSDavid Howells	my $lma  = Math::BigInt->new("0x" . $5);
412221a6eeSDavid Howells	my $foff = Math::BigInt->new("0x" . $6);
422221a6eeSDavid Howells	my $align = 2 ** $7;
432221a6eeSDavid Howells
442221a6eeSDavid Howells	push @sections, { name => $name,
452221a6eeSDavid Howells			  vma => $vma,
462221a6eeSDavid Howells			  len => $len,
472221a6eeSDavid Howells			  foff => $foff };
482221a6eeSDavid Howells    }
492221a6eeSDavid Howells}
502221a6eeSDavid Howells
512221a6eeSDavid Howellsprint "Have $#sections sections\n";
522221a6eeSDavid Howells
532221a6eeSDavid Howells#
542221a6eeSDavid Howells# Try and parse the vmlinux symbol table.  If the vmlinux file has been created
552221a6eeSDavid Howells# from a vmlinuz file with extract-vmlinux then the symbol table will be empty.
562221a6eeSDavid Howells#
572221a6eeSDavid Howellsopen FD, "nm $vmlinux 2>/dev/null |" || die $vmlinux;
582221a6eeSDavid Howells@lines = <FD>;
592221a6eeSDavid Howellsclose(FD) || die $vmlinux;
602221a6eeSDavid Howells
612221a6eeSDavid Howellsmy %symbols = ();
622221a6eeSDavid Howellsmy $nr_symbols = 0;
632221a6eeSDavid Howells
642221a6eeSDavid Howellssub parse_symbols(@) {
652221a6eeSDavid Howells    foreach my $line (@_) {
662221a6eeSDavid Howells	chomp($line);
672221a6eeSDavid Howells	if ($line =~ /([0-9a-f]+)\s([a-zA-Z])\s(\S+)/
682221a6eeSDavid Howells	    ) {
692221a6eeSDavid Howells	    my $addr = "0x" . $1;
702221a6eeSDavid Howells	    my $type = $2;
712221a6eeSDavid Howells	    my $name = $3;
722221a6eeSDavid Howells
732221a6eeSDavid Howells	    $symbols{$name} = $addr;
742221a6eeSDavid Howells	    $nr_symbols++;
752221a6eeSDavid Howells	}
762221a6eeSDavid Howells    }
772221a6eeSDavid Howells}
782221a6eeSDavid Howellsparse_symbols(@lines);
792221a6eeSDavid Howells
802221a6eeSDavid Howellsif ($nr_symbols == 0 && $sysmap ne "") {
812221a6eeSDavid Howells    print "No symbols in vmlinux, trying $sysmap\n";
822221a6eeSDavid Howells
832221a6eeSDavid Howells    open FD, "<$sysmap" || die $sysmap;
842221a6eeSDavid Howells    @lines = <FD>;
852221a6eeSDavid Howells    close(FD) || die $sysmap;
862221a6eeSDavid Howells    parse_symbols(@lines);
872221a6eeSDavid Howells}
882221a6eeSDavid Howells
892221a6eeSDavid Howellsdie "No symbols available\n"
902221a6eeSDavid Howells    if ($nr_symbols == 0);
912221a6eeSDavid Howells
922221a6eeSDavid Howellsprint "Have $nr_symbols symbols\n";
932221a6eeSDavid Howells
942221a6eeSDavid Howellsdie "Can't find system certificate list"
952221a6eeSDavid Howells    unless (exists($symbols{"__cert_list_start"}) &&
968e167898SMehmet Kayaalp	    exists($symbols{"system_certificate_list_size"}));
972221a6eeSDavid Howells
982221a6eeSDavid Howellsmy $start = Math::BigInt->new($symbols{"__cert_list_start"});
998e167898SMehmet Kayaalpmy $end;
1008e167898SMehmet Kayaalpmy $size;
1018e167898SMehmet Kayaalpmy $size_sym = Math::BigInt->new($symbols{"system_certificate_list_size"});
1022221a6eeSDavid Howells
1038e167898SMehmet Kayaalpopen FD, "<$vmlinux" || die $vmlinux;
1048e167898SMehmet Kayaalpbinmode(FD);
1052221a6eeSDavid Howells
1062221a6eeSDavid Howellsmy $s = undef;
1072221a6eeSDavid Howellsforeach my $sec (@sections) {
1082221a6eeSDavid Howells    my $s_name = $sec->{name};
1092221a6eeSDavid Howells    my $s_vma = $sec->{vma};
1102221a6eeSDavid Howells    my $s_len = $sec->{len};
1112221a6eeSDavid Howells    my $s_foff = $sec->{foff};
1122221a6eeSDavid Howells    my $s_vend = $s_vma + $s_len;
1132221a6eeSDavid Howells
1142221a6eeSDavid Howells    next unless ($start >= $s_vma);
1152221a6eeSDavid Howells    next if ($start >= $s_vend);
1162221a6eeSDavid Howells
1178e167898SMehmet Kayaalp    die "Certificate list size was not found on the same section\n"
1188e167898SMehmet Kayaalp	if ($size_sym < $s_vma || $size_sym > $s_vend);
1192221a6eeSDavid Howells
1202221a6eeSDavid Howells    die "Cert object in multiple sections: ", $s_name, " and ", $s->{name}, "\n"
1212221a6eeSDavid Howells	if ($s);
1228e167898SMehmet Kayaalp
1238e167898SMehmet Kayaalp    my $size_off = $size_sym -$s_vma + $s_foff;
1248e167898SMehmet Kayaalp    my $packed;
1258e167898SMehmet Kayaalp    die $vmlinux if (!defined(sysseek(FD, $size_off, SEEK_SET)));
1268e167898SMehmet Kayaalp    sysread(FD, $packed, 8);
1278e167898SMehmet Kayaalp    $size = unpack 'L!', $packed;
1288e167898SMehmet Kayaalp    $end = $start + $size;
1298e167898SMehmet Kayaalp
1308e167898SMehmet Kayaalp    printf "Have %u bytes of certs at VMA 0x%x\n", $size, $start;
1318e167898SMehmet Kayaalp
1328e167898SMehmet Kayaalp    die "Cert object partially overflows section $s_name\n"
1338e167898SMehmet Kayaalp	if ($end > $s_vend);
1348e167898SMehmet Kayaalp
1352221a6eeSDavid Howells    $s = $sec;
1362221a6eeSDavid Howells}
1372221a6eeSDavid Howells
1382221a6eeSDavid Howellsdie "Cert object not inside a section\n"
1392221a6eeSDavid Howells    unless ($s);
1402221a6eeSDavid Howells
1412221a6eeSDavid Howellsprint "Certificate list in section ", $s->{name}, "\n";
1422221a6eeSDavid Howells
1432221a6eeSDavid Howellsmy $foff = $start - $s->{vma} + $s->{foff};
1442221a6eeSDavid Howells
1452221a6eeSDavid Howellsprintf "Certificate list at file offset 0x%x\n", $foff;
1462221a6eeSDavid Howells
1472221a6eeSDavid Howellsdie $vmlinux if (!defined(sysseek(FD, $foff, SEEK_SET)));
1482221a6eeSDavid Howellsmy $buf = "";
1492221a6eeSDavid Howellsmy $len = sysread(FD, $buf, $size);
1502221a6eeSDavid Howellsdie "$vmlinux" if (!defined($len));
1512221a6eeSDavid Howellsdie "Short read on $vmlinux\n" if ($len != $size);
1522221a6eeSDavid Howellsclose(FD) || die $vmlinux;
1532221a6eeSDavid Howells
1542221a6eeSDavid Howellsopen FD, ">$keyring" || die $keyring;
1552221a6eeSDavid Howellsbinmode(FD);
1562221a6eeSDavid Howells$len = syswrite(FD, $buf, $size);
1572221a6eeSDavid Howellsdie "$keyring" if (!defined($len));
1582221a6eeSDavid Howellsdie "Short write on $keyring\n" if ($len != $size);
1592221a6eeSDavid Howellsclose(FD) || die $keyring;
160