Commit | Line | Data |
---|---|---|
3c2a0909 S |
1 | #!/bin/bash |
2 | ||
3 | # fips_fmp_hmac.sh | |
4 | # | |
5 | # Author : Rohit Kothari (r.kothari@samsung.com) | |
6 | # Created on : 14 Feb 2014 | |
7 | # Copyright (c) Samsung Electronics 2014 | |
8 | ||
9 | # Given a vmlinux file and a System.map, this scripts finds bytes belonging to | |
10 | # Kernel Crypto within vmlinux file.(Under section .text, .init.text, .exit.text and .rodata) | |
11 | # After collecting all the bytes, it calculates a hmac(sha256) on those bytes. | |
12 | # Generated hmac is put back into a fmp rodata variable within vmlinux file itself. | |
13 | # This makes the build time hmac available at runtime, for integrity check. | |
14 | # | |
15 | # To find fmp bytes, this scripts heavily relies on output of arm-eabi-readelf. | |
16 | # If the output of arm-eabi-readelf changes in future, this script might need changes. | |
17 | # | |
18 | # Pre-conditions : $READELF, $HOSTCC variables are set. | |
19 | # | |
20 | # | |
21 | ||
22 | if test $# -ne 2; then | |
23 | echo "Usage: $0 vmlinux System.map" | |
24 | exit 1 | |
25 | fi | |
26 | ||
27 | vmlinux_var=$1 | |
28 | system_map_var=$2 | |
29 | ||
30 | if [[ -z "$vmlinux_var" || -z "$system_map_var" || -z "$READELF" || -z "$HOSTCC" ]]; then | |
31 | echo "$0 : variables not set" | |
32 | exit 1 | |
33 | fi | |
34 | ||
35 | if [[ ! -f $vmlinux_var || ! -f $system_map_var ]]; then | |
36 | echo "$0 : files does not exist" | |
37 | exit 1 | |
38 | fi | |
39 | ||
40 | rm -f vmlinux.elf | |
41 | $READELF -S $vmlinux_var > vmlinux.elf | |
42 | ||
43 | retval=$? | |
44 | if [ $retval -ne 0 ]; then | |
45 | echo "$0 : $READELF returned error" | |
46 | exit 1 | |
47 | fi | |
48 | ||
49 | declare -A array | |
50 | ||
51 | # FOR GENERIC CRYPTO FILES #awk fields to cut | |
52 | array[0]=".text first_fmp_text last_fmp_text \$5 \$6" | |
53 | array[1]=".rodata first_fmp_rodata last_fmp_rodata \$5 \$6" | |
54 | array[2]=".init.text first_fmp_init last_fmp_init \$4 \$5" | |
55 | array[3]=".exit.text first_fmp_exit last_fmp_exit \$4 \$5" | |
56 | ||
57 | rm -f offsets_sizes.txt | |
58 | ||
59 | #Addresses retrieved must be a valid hex | |
60 | reg='^[0-9A-Fa-f]+$' | |
61 | ||
62 | #Total bytes of all fmp sections scanned. Used later for error checking | |
63 | total_bytes=0; | |
64 | ||
65 | # For each type of Section : | |
66 | # first_addr = Address of first_fmp_text, first_fmp_rodata, etc. | |
67 | # last_addr = Address of last_fmp_text, last_fmp_rodata etc. | |
68 | # start_addr = Starting Address of a section within vmlinux | |
69 | # offset = Offset in vmlinux file where the section begins | |
70 | # file_offset = Offset in vmlinux file where the fmp bytes begins. | |
71 | # size = size of fmp bytes. | |
72 | ||
73 | # Output is offsets_sizes.txt, of the format | |
74 | # Section Name fmp_bytes_offse fmp_bytes_size | |
75 | # (in decimal) (in decimal) | |
76 | # .text 2531072 114576 | |
77 | # .rodata 9289648 55388 | |
78 | # : : : | |
79 | ||
80 | for i in "${array[@]}"; do | |
81 | ||
82 | var1=var2=var3=var4=var5="" | |
83 | first_addr=last_addr=start_addr=offset=file_offset=size="" | |
84 | k=1 | |
85 | #This loop creates var1, var2 etc and set them to individual strings of a row in array | |
86 | for j in $i; do | |
87 | export var$k=$j | |
88 | let k+=1 | |
89 | done | |
90 | ||
91 | first_addr=`cat $system_map_var|grep -w $var2|awk '{print $1}'` | |
92 | if [[ ! $first_addr =~ $reg ]]; then echo "$0 : first_addr invalid"; exit 1; fi | |
93 | ||
94 | last_addr=`cat $system_map_var|grep -w $var3|awk '{print $1}'` | |
95 | if [[ ! $last_addr =~ $reg ]]; then echo "$0 : last_addr invalid"; exit 1; fi | |
96 | ||
97 | start_addr=`cat vmlinux.elf |grep -w "$var1 "|grep PROGBITS|awk '{print '$var4'}'` | |
98 | if [[ ! $start_addr =~ $reg ]]; then echo "$0 : start_addr invalid"; exit 1; fi | |
99 | ||
100 | offset=`cat vmlinux.elf |grep -w "$var1 "|grep PROGBITS|awk '{print '$var5'}'` | |
101 | if [[ ! $offset =~ $reg ]]; then echo "$0 : offset invalid"; exit 1; fi | |
102 | ||
103 | if [[ $((16#$first_addr)) -lt $((16#$start_addr)) ]]; then echo "$0 : first_addr < start_addr"; exit 1; fi | |
104 | ||
105 | if [[ $((16#$last_addr)) -le $((16#$first_addr)) ]]; then echo "$0 : last_addr <= first_addr"; exit 1; fi | |
106 | ||
107 | file_offset=`expr $((16#$offset)) + $((16#$first_addr)) - $((16#$start_addr))` | |
108 | if [[ $file_offset -le 0 ]]; then echo "$0 : file_offset invalid"; exit 1; fi | |
109 | ||
110 | size=`expr $((16#$last_addr)) - $((16#$first_addr))` | |
111 | if [[ $size -le 0 ]]; then echo "$0 : fmp section size invalid"; exit 1; fi | |
112 | ||
113 | echo "$var1 " $file_offset " " $size >> offsets_sizes.txt | |
114 | ||
115 | let "total_bytes += `expr $((16#$last_addr)) - $((16#$first_addr))`" | |
116 | done | |
117 | ||
118 | if [[ ! -f offsets_sizes.txt ]]; then | |
119 | echo "$0 : offset_sizes.txt does not exist" | |
120 | exit 1 | |
121 | fi | |
122 | ||
123 | rm -f fips_fmp_utils | |
124 | $HOSTCC -o fips_fmp_utils $srctree/scripts/fips_fmp_utils.c | |
125 | retval=$? | |
126 | if [ $retval -ne 0 ]; then | |
127 | echo "$0 : $HOSTCC returned error" | |
128 | exit 1 | |
129 | fi | |
130 | ||
131 | rm -f builtime_bytes.txt #used for debugging | |
132 | rm -f builtime_bytes.bin #used for calculating hmac | |
133 | ||
134 | date_var=`date` | |
135 | echo "Created on : " $date_var > builtime_bytes.txt | |
136 | ||
137 | #Using offsets_sizes.txt, dump fmp bytes from vmlinux file into builtime_bytes.bin | |
138 | #Also gather printf's into builtime_bytes.txt, for debugging if required | |
139 | while read args; do | |
140 | ./fips_fmp_utils -g $vmlinux_var $args builtime_bytes.bin >> builtime_bytes.txt | |
141 | retval=$? | |
142 | if [ $retval -ne 0 ]; then | |
143 | echo "$0 : fips_fmp_utils : unable to gather fmp bytes from vmlinux" | |
144 | exit 1 | |
145 | fi | |
146 | echo "" >> builtime_bytes.txt | |
147 | done < offsets_sizes.txt # <================== offsets_sizes.txt | |
148 | ||
149 | if [[ ! -f builtime_bytes.bin ]]; then | |
150 | echo "$0 : builtime_bytes.bin does not exist" | |
151 | exit 1 | |
152 | fi | |
153 | ||
154 | file_size=`cat builtime_bytes.bin| wc -c` | |
155 | ||
156 | # Make sure that file size of fmp_hmac.bin is as expected | |
157 | if [ $total_bytes -ne $file_size ]; then | |
158 | echo "$0: Bytes mismatch" | |
159 | exit 1 | |
160 | fi | |
161 | ||
162 | key="The quick brown fox jumps over the lazy dog" | |
163 | ||
164 | # Now, generate the hmac. | |
165 | openssl dgst -sha256 -hmac "$key" -binary -out fmp_hmac.bin builtime_bytes.bin | |
166 | retval=$? | |
167 | if [ $retval -ne 0 ]; then | |
168 | echo "$0 : openssl dgst command returned error" | |
169 | exit 1 | |
170 | fi | |
171 | ||
172 | # Just, for debugging, print the same hmac on console | |
173 | openssl dgst -sha256 -hmac "$key" builtime_bytes.bin | |
174 | retval=$? | |
175 | if [ $retval -ne 0 ]; then | |
176 | echo "$0 : openssl dgst command returned error" | |
177 | exit 1 | |
178 | fi | |
179 | ||
180 | if [[ ! -f fmp_hmac.bin ]]; then | |
181 | echo "$0 : fmp_hmac.bin does not exist" | |
182 | exit 1 | |
183 | fi | |
184 | ||
185 | file_size=`cat fmp_hmac.bin| wc -c` | |
186 | ||
187 | # hmac(sha256) produces 32 bytes of hmac | |
188 | if [ $file_size -ne 32 ]; then | |
189 | echo "$0: Unexpected size of Hash file : " $file_size | |
190 | exit 1 | |
191 | fi | |
192 | ||
193 | ||
194 | # Now that we have the hmac, update this hmac into an rodata "builtime_fmp_hmac" varialble | |
195 | # in vmlinux file. | |
196 | # This variable has a place holder 32 bytes that will be over-written with generated hmac. | |
197 | # This way, this build time hmac, will be available as a read-only variable at run-time. | |
198 | ||
199 | first_addr=`cat $system_map_var|grep -w "builtime_fmp_hmac"|awk '{print $1}' ` | |
200 | if [[ ! $first_addr =~ $reg ]]; then echo "$0 : first_addr of hmac variable invalid"; exit 1; fi | |
201 | ||
202 | start_addr=`cat vmlinux.elf |grep -w ".rodata"|grep PROGBITS|awk '{print $5}' ` | |
203 | if [[ ! $start_addr =~ $reg ]]; then echo "$0 : start_addr of .rodata invalid"; exit 1; fi | |
204 | ||
205 | offset=`cat vmlinux.elf |grep -w ".rodata"|grep PROGBITS| awk '{print $6}' ` | |
206 | if [[ ! $offset =~ $reg ]]; then echo "$0 : offset of .rodata invalid"; exit 1; fi | |
207 | ||
208 | if [[ $((16#$first_addr)) -le $((16#$start_addr)) ]]; then echo "$0 : hmac var first_addr <= start_addr"; exit 1; fi | |
209 | ||
210 | hmac_offset=`expr $((16#$offset)) + $((16#$first_addr)) - $((16#$start_addr))` | |
211 | if [[ $hmac_offset -le 0 ]]; then echo "$0 : hmac_offset invalid"; exit 1; fi | |
212 | ||
213 | # This does the actual update of hmac into vmlinux file, at given offset | |
214 | ./fips_fmp_utils -u $vmlinux_var fmp_hmac.bin $hmac_offset | |
215 | retval=$? | |
216 | if [ $retval -ne 0 ]; then | |
217 | echo "$0 : fips_fmp_utils : unable to update hmac in vmlinux" | |
218 | exit 1 | |
219 | fi | |
220 | ||
221 | # rm -f fmp_hmac.bin | |
222 | # rm -f builtime_bytes.txt | |
223 | # rm -f builtime_bytes.bin | |
224 | # rm -f fips_fmp_utils | |
225 | # rm -f vmlinux.elf | |
226 | # rm -f offsets_sizes.txt | |
227 | ||
228 | # And we are done... |