1#!/usr/bin/env perl 2# 3use warnings; 4use strict; 5use Math::BigInt; 6use Fcntl "SEEK_SET"; 7 8die "Format: $0 [-s <systemmap-file>] <vmlinux-file> <keyring-file>\n" 9 if ($#ARGV != 1 && $#ARGV != 3 || 10 $#ARGV == 3 && $ARGV[0] ne "-s"); 11 12my $sysmap = ""; 13if ($#ARGV == 3) { 14 shift; 15 $sysmap = $ARGV[0]; 16 shift; 17} 18 19my $vmlinux = $ARGV[0]; 20my $keyring = $ARGV[1]; 21 22# 23# Parse the vmlinux section table 24# 25open FD, "objdump -h $vmlinux |" || die $vmlinux; 26my @lines = <FD>; 27close(FD) || die $vmlinux; 28 29my @sections = (); 30 31foreach my $line (@lines) { 32 chomp($line); 33 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]+)/ 34 ) { 35 my $seg = $1; 36 my $name = $2; 37 my $len = Math::BigInt->new("0x" . $3); 38 my $vma = Math::BigInt->new("0x" . $4); 39 my $lma = Math::BigInt->new("0x" . $5); 40 my $foff = Math::BigInt->new("0x" . $6); 41 my $align = 2 ** $7; 42 43 push @sections, { name => $name, 44 vma => $vma, 45 len => $len, 46 foff => $foff }; 47 } 48} 49 50print "Have $#sections sections\n"; 51 52# 53# Try and parse the vmlinux symbol table. If the vmlinux file has been created 54# from a vmlinuz file with extract-vmlinux then the symbol table will be empty. 55# 56open FD, "nm $vmlinux 2>/dev/null |" || die $vmlinux; 57@lines = <FD>; 58close(FD) || die $vmlinux; 59 60my %symbols = (); 61my $nr_symbols = 0; 62 63sub parse_symbols(@) { 64 foreach my $line (@_) { 65 chomp($line); 66 if ($line =~ /([0-9a-f]+)\s([a-zA-Z])\s(\S+)/ 67 ) { 68 my $addr = "0x" . $1; 69 my $type = $2; 70 my $name = $3; 71 72 $symbols{$name} = $addr; 73 $nr_symbols++; 74 } 75 } 76} 77parse_symbols(@lines); 78 79if ($nr_symbols == 0 && $sysmap ne "") { 80 print "No symbols in vmlinux, trying $sysmap\n"; 81 82 open FD, "<$sysmap" || die $sysmap; 83 @lines = <FD>; 84 close(FD) || die $sysmap; 85 parse_symbols(@lines); 86} 87 88die "No symbols available\n" 89 if ($nr_symbols == 0); 90 91print "Have $nr_symbols symbols\n"; 92 93die "Can't find system certificate list" 94 unless (exists($symbols{"__cert_list_start"}) && 95 exists($symbols{"system_certificate_list_size"})); 96 97my $start = Math::BigInt->new($symbols{"__cert_list_start"}); 98my $end; 99my $size; 100my $size_sym = Math::BigInt->new($symbols{"system_certificate_list_size"}); 101 102open FD, "<$vmlinux" || die $vmlinux; 103binmode(FD); 104 105my $s = undef; 106foreach my $sec (@sections) { 107 my $s_name = $sec->{name}; 108 my $s_vma = $sec->{vma}; 109 my $s_len = $sec->{len}; 110 my $s_foff = $sec->{foff}; 111 my $s_vend = $s_vma + $s_len; 112 113 next unless ($start >= $s_vma); 114 next if ($start >= $s_vend); 115 116 die "Certificate list size was not found on the same section\n" 117 if ($size_sym < $s_vma || $size_sym > $s_vend); 118 119 die "Cert object in multiple sections: ", $s_name, " and ", $s->{name}, "\n" 120 if ($s); 121 122 my $size_off = $size_sym -$s_vma + $s_foff; 123 my $packed; 124 die $vmlinux if (!defined(sysseek(FD, $size_off, SEEK_SET))); 125 sysread(FD, $packed, 8); 126 $size = unpack 'L!', $packed; 127 $end = $start + $size; 128 129 printf "Have %u bytes of certs at VMA 0x%x\n", $size, $start; 130 131 die "Cert object partially overflows section $s_name\n" 132 if ($end > $s_vend); 133 134 $s = $sec; 135} 136 137die "Cert object not inside a section\n" 138 unless ($s); 139 140print "Certificate list in section ", $s->{name}, "\n"; 141 142my $foff = $start - $s->{vma} + $s->{foff}; 143 144printf "Certificate list at file offset 0x%x\n", $foff; 145 146die $vmlinux if (!defined(sysseek(FD, $foff, SEEK_SET))); 147my $buf = ""; 148my $len = sysread(FD, $buf, $size); 149die "$vmlinux" if (!defined($len)); 150die "Short read on $vmlinux\n" if ($len != $size); 151close(FD) || die $vmlinux; 152 153open FD, ">$keyring" || die $keyring; 154binmode(FD); 155$len = syswrite(FD, $buf, $size); 156die "$keyring" if (!defined($len)); 157die "Short write on $keyring\n" if ($len != $size); 158close(FD) || die $keyring; 159