Commit | Line | Data |
---|---|---|
1cac41cb MB |
1 | #!/bin/bash |
2 | ||
3 | # fips_crypto_hmac.sh | |
4 | # | |
5 | # Author : Rohit Kothari (r.kothari@samsung.com) | |
6 | # Created on : 14 Feb 2014 | |
7 | # Modified on: 22 Jun 2015 by Jia Ma (jia.ma@samsung.com) /* To adapt to KASLR change */ | |
8 | # Modified on: 09 Jul 2015 by Wenbo Shen (wenbo.s@samsung.com) /* To reduce the hmac generation time */ | |
9 | # Copyright (c) Samsung Electronics 2014 | |
10 | ||
11 | # Given a vmlinux file and a System.map, this scripts finds bytes belonging to | |
12 | # Kernel Crypto within vmlinux file.(Under section .text, .init.text, .exit.text and .rodata) | |
13 | # After collecting all the bytes, it calculates a hmac(sha256) on those bytes. | |
14 | # Generated hmac is put back into a crypto rodata variable within vmlinux file itself. | |
15 | # This makes the build time hmac available at runtime, for integrity check. | |
16 | # | |
17 | # To find crypto bytes, this scripts heavily relies on output of arm-eabi-readelf. | |
18 | # If the output of arm-eabi-readelf changes in future, this script might need changes. | |
19 | # | |
20 | # Pre-conditions : $READELF, $HOSTCC variables are set. | |
21 | # | |
22 | # | |
23 | ||
24 | # Here we want to seperate the oneshot code from the repeated code | |
25 | ################ the repeated code #################### | |
26 | kaslr_patch () { | |
27 | index=$1 | |
28 | ./kaslr_fips $vmlinux_var $reloc_start_addr $reloc_end_addr $dynsym_addr $index $first_crypto_rodata $last_crypto_rodata $first_fmp_rodata $last_fmp_rodata $2 | |
29 | retval=$? | |
30 | if [ $retval -ne 0 ]; then | |
31 | echo "$0 : kaslr_fips : unable to patch the vmlinux" | |
32 | exit 1 | |
33 | fi | |
34 | } | |
35 | ||
36 | hmac_patch() { | |
37 | index=$1 | |
38 | offsets_sizes_file=$2 | |
39 | ||
40 | if [ "$3" == "crypto" ]; then | |
41 | fips_utils=./fips_crypto_utils | |
42 | hmac_offset=`expr $crypto_hmac_offset_base + $((32*$index)) ` | |
43 | elif [ "$3" == "fmp" ]; then | |
44 | fips_utils=./fips_fmp_utils | |
45 | hmac_offset=`expr $fmp_hmac_offset_base + $((32*$index)) ` | |
46 | fi | |
47 | ||
48 | rm -f builtime_bytes.txt #used for debugging | |
49 | rm -f builtime_bytes.bin #used for calculating hmac | |
50 | ||
51 | date_var=`date` | |
52 | echo "Created on : " $date_var > builtime_bytes.txt | |
53 | ||
54 | ||
55 | #Using offsets_sizes.txt, dump crypto bytes from vmlinux file into builtime_bytes.bin | |
56 | #Also gather printf's into builtime_bytes.txt, for debugging if required | |
57 | while read args; do | |
58 | $fips_utils -g $vmlinux_var $args builtime_bytes.bin >> builtime_bytes.txt | |
59 | retval=$? | |
60 | if [ $retval -ne 0 ]; then | |
61 | echo "$0 : $fips_utils : unable to gather $3 bytes from vmlinux" | |
62 | exit 1 | |
63 | fi | |
64 | echo "" >> builtime_bytes.txt | |
65 | done < $offsets_sizes_file | |
66 | ||
67 | ||
68 | if [[ ! -f builtime_bytes.bin ]]; then | |
69 | echo "$0 : builtime_bytes.bin does not exist" | |
70 | exit 1 | |
71 | fi | |
72 | ||
73 | #file_size=`cat builtime_bytes.bin| wc -c` | |
74 | ||
75 | # Make sure that file size of crypto_hmac.bin is as expected | |
76 | #if [ $total_bytes -ne $file_size ]; then | |
77 | #echo "$0: Bytes mismatch" | |
78 | #exit 1 | |
79 | #fi | |
80 | ||
81 | ||
82 | key="The quick brown fox jumps over the lazy dog" | |
83 | ||
84 | # Now, generate the hmac. | |
85 | openssl dgst -sha256 -hmac "$key" -binary -out crypto_hmac.bin builtime_bytes.bin | |
86 | retval=$? | |
87 | if [ $retval -ne 0 ]; then | |
88 | echo "$0 : openssl dgst command returned error" | |
89 | exit 1 | |
90 | fi | |
91 | ||
92 | # Just, for debugging, print the same hmac on console | |
93 | #openssl dgst -sha256 -hmac "$key" builtime_bytes.bin | |
94 | ||
95 | if [[ ! -f crypto_hmac.bin ]]; then | |
96 | echo "$0 : crypto_hmac.bin does not exist" | |
97 | exit 1 | |
98 | fi | |
99 | ||
100 | file_size=`cat crypto_hmac.bin| wc -c` | |
101 | ||
102 | # hmac(sha256) produces 32 bytes of hmac | |
103 | if [ $file_size -ne 32 ]; then | |
104 | echo "$0: Unexpected size of Hash file : " $file_size | |
105 | exit 1 | |
106 | fi | |
107 | ||
108 | # Now that we have the hmac, update this hmac into an rodata "builtime_crypto_hmac" varialble | |
109 | # in vmlinux file. | |
110 | # This variable has a place holder 32 bytes that will be over-written with generated hmac. | |
111 | # This way, this build time hmac, will be available as a read-only variable at run-time. | |
112 | ||
113 | if [[ $hmac_offset -le 0 ]]; then echo "$0 : hmac_offset invalid"; exit 1; fi | |
114 | ||
115 | # This does the actual update of hmac into vmlinux file, at given offset | |
116 | $fips_utils -u $vmlinux_var crypto_hmac.bin $hmac_offset | |
117 | retval=$? | |
118 | if [ $retval -ne 0 ]; then | |
119 | echo "$0 : fips_crypto_utils : unable to update hmac in vmlinux" | |
120 | exit 1 | |
121 | fi | |
122 | ||
123 | rm -f crypto_hmac.bin | |
124 | rm -f builtime_bytes.txt | |
125 | rm -f builtime_bytes.bin | |
126 | } | |
127 | ||
128 | ################ the kaslr patch oneshot code #################### | |
129 | # 1st parameter is the array, 2nd is the output file name | |
130 | offsets_sizes_gen(){ | |
131 | name=$1[@] | |
132 | array=("${!name}") | |
133 | ||
134 | outfile=$2 | |
135 | rm -f $outfile | |
136 | ||
137 | #Addresses retrieved must be a valid hex | |
138 | reg='^[0-9A-Fa-f]+$' | |
139 | ||
140 | #Total bytes of all crypto sections scanned. Used later for error checking | |
141 | #total_bytes=0; | |
142 | ||
143 | # For each type of Section : | |
144 | # first_addr = Address of first_crypto_text, first_crypto_rodata, etc. | |
145 | # last_addr = Address of last_crypto_text, last_crypto_rodata etc. | |
146 | # start_addr = Starting Address of a section within vmlinux | |
147 | # offset = Offset in vmlinux file where the section begins | |
148 | # file_offset = Offset in vmlinux file where the crypto bytes begins. | |
149 | # size = size of crypto bytes. | |
150 | ||
151 | # Output is offsets_sizes.txt, of the format | |
152 | # Section Name crypto_bytes_offset crypto_bytes_size | |
153 | # (in decimal) (in decimal) | |
154 | # .text 2531072 114576 | |
155 | # .rodata 9289648 55388 | |
156 | # : : : | |
157 | ||
158 | for i in "${array[@]}"; do | |
159 | ||
160 | var1=var2=var3=var4=var5="" | |
161 | first_addr=last_addr=start_addr=offset=file_offset=size="" | |
162 | k=1 | |
163 | #This loop creates var1, var2 etc and set them to individual strings of a row in array | |
164 | for j in $i; do | |
165 | export var$k=$j | |
166 | let k+=1 | |
167 | done | |
168 | ||
169 | first_addr=`cat $system_map_var|grep -w $var2|awk '{print $1}'` | |
170 | if [[ ! $first_addr =~ $reg ]]; then echo "$0 : first_addr invalid"; exit 1; fi | |
171 | ||
172 | last_addr=`cat $system_map_var|grep -w $var3|awk '{print $1}'` | |
173 | if [[ ! $last_addr =~ $reg ]]; then echo "$0 : last_addr invalid"; exit 1; fi | |
174 | ||
175 | start_addr=`cat vmlinux.elf |grep -w "$var1 "|grep PROGBITS|awk '{print '$var4'}'` | |
176 | if [[ ! $start_addr =~ $reg ]]; then echo "$0 : start_addr invalid"; exit 1; fi | |
177 | ||
178 | offset=`cat vmlinux.elf |grep -w "$var1 "|grep PROGBITS|awk '{print '$var5'}'` | |
179 | if [[ ! $offset =~ $reg ]]; then echo "$0 : offset invalid"; exit 1; fi | |
180 | ||
181 | if [[ $((16#$first_addr)) -lt $((16#$start_addr)) ]]; then echo "$0 : first_addr < start_addr"; exit 1; fi | |
182 | ||
183 | if [[ $((16#$last_addr)) -le $((16#$first_addr)) ]]; then echo "$0 : last_addr <= first_addr"; exit 1; fi | |
184 | ||
185 | file_offset=`expr $((16#$offset)) + $((16#$first_addr)) - $((16#$start_addr))` | |
186 | if [[ $file_offset -le 0 ]]; then echo "$0 : file_offset invalid"; exit 1; fi | |
187 | ||
188 | size=`expr $((16#$last_addr)) - $((16#$first_addr))` | |
189 | if [[ $size -le 0 ]]; then echo "$0 : crypto section size invalid"; exit 1; fi | |
190 | ||
191 | echo "$var1 " $file_offset " " $size >> $outfile | |
192 | ||
193 | #let "total_bytes += `expr $((16#$last_addr)) - $((16#$first_addr))`" | |
194 | done | |
195 | ||
196 | if [[ ! -f $outfile ]]; then | |
197 | echo "$0 : offset_sizes.txt does not exist" | |
198 | exit 1 | |
199 | fi | |
200 | ||
201 | ||
202 | } | |
203 | ||
204 | cal_hmac_offset(){ | |
205 | first_addr=`cat $system_map_var|grep -w $1|awk '{print $1}' ` | |
206 | if [[ ! $first_addr =~ $reg ]]; then echo "$0 : first_addr of hmac variable invalid"; exit 1; fi | |
207 | ||
208 | start_addr=`cat vmlinux.elf |grep -w $2|grep PROGBITS|awk '{print $5}' ` | |
209 | if [[ ! $start_addr =~ $reg ]]; then echo "$0 : start_addr of .rodata invalid"; exit 1; fi | |
210 | ||
211 | offset=`cat vmlinux.elf |grep -w $2|grep PROGBITS| awk '{print $6}' ` | |
212 | if [[ ! $offset =~ $reg ]]; then echo "$0 : offset of .rodata invalid"; exit 1; fi | |
213 | ||
214 | if [[ $((16#$first_addr)) -le $((16#$start_addr)) ]]; then echo "$0 : hmac var first_addr <= start_addr"; exit 1; fi | |
215 | ||
216 | if [ "$1" == "builtime_crypto_hmac" ]; then | |
217 | crypto_hmac_offset_base=`expr $((16#$offset)) + $((16#$first_addr)) - $((16#$start_addr)) ` | |
218 | elif [ "$1" == "builtime_fmp_hmac" ]; then | |
219 | fmp_hmac_offset_base=`expr $((16#$offset)) + $((16#$first_addr)) - $((16#$start_addr)) ` | |
220 | fi | |
221 | } | |
222 | ||
223 | ################ Start Here ################ | |
224 | ||
225 | START_TIME=$SECONDS | |
226 | ||
227 | if test $# -ne 2; then | |
228 | echo "Usage: $0 vmlinux System.map" | |
229 | exit 1 | |
230 | fi | |
231 | ||
232 | vmlinux_var=$1 | |
233 | system_map_var=$2 | |
234 | ||
235 | if [[ -z "$vmlinux_var" || -z "$system_map_var" || -z "$READELF" || -z "$HOSTCC" ]]; then | |
236 | echo "$0 : variables not set" | |
237 | exit 1 | |
238 | fi | |
239 | ||
240 | if [[ ! -f $vmlinux_var || ! -f $system_map_var ]]; then | |
241 | echo "$0 : files does not exist" | |
242 | exit 1 | |
243 | fi | |
244 | ||
245 | rm -f vmlinux.elf | |
246 | $READELF -S $vmlinux_var > vmlinux.elf | |
247 | ||
248 | retval=$? | |
249 | if [ $retval -ne 0 ]; then | |
250 | echo "$0 : $READELF returned error" | |
251 | exit 1 | |
252 | fi | |
253 | ||
254 | #start patching vmlinux with static patcher, temporary put it here | |
255 | rm -f kaslr_fips | |
256 | $HOSTCC -o kaslr_fips $srctree/scripts/kaslr_fips.c | |
257 | retval=$? | |
258 | if [ $retval -ne 0 ]; then | |
259 | echo "$0 : $HOSTCC returned error" | |
260 | exit 1 | |
261 | fi | |
262 | ||
263 | rm -f fips_crypto_utils | |
264 | $HOSTCC -o fips_crypto_utils $srctree/scripts/fips_crypto_utils.c | |
265 | retval=$? | |
266 | if [ $retval -ne 0 ]; then | |
267 | echo "$0 : $HOSTCC returned error" | |
268 | exit 1 | |
269 | fi | |
270 | ||
271 | rm -f fips_fmp_utils | |
272 | $HOSTCC -o fips_fmp_utils $srctree/scripts/fips_fmp_utils.c | |
273 | retval=$? | |
274 | if [ $retval -ne 0 ]; then | |
275 | echo "$0 : $HOSTCC returned error" | |
276 | exit 1 | |
277 | fi | |
278 | ||
279 | var="__reloc_start" | |
280 | var1=`cat $system_map_var|grep -w $var|awk '{print $1}'` | |
281 | var="__reloc_end" | |
282 | var2=`cat $system_map_var|grep -w $var|awk '{print $1}'` | |
283 | var="__dynsym_start" | |
284 | var3=`cat $system_map_var|grep -w $var|awk '{print $1}'` | |
285 | ||
286 | var="first_crypto_rodata" | |
287 | var4=`cat $system_map_var|grep -w $var|awk '{print $1}'` | |
288 | var="last_crypto_rodata" | |
289 | var5=`cat $system_map_var|grep -w $var|awk '{print $1}'` | |
290 | ||
291 | var="first_fmp_rodata" | |
292 | var6=`cat $system_map_var|grep -w $var|awk '{print $1}'` | |
293 | var="last_fmp_rodata" | |
294 | var7=`cat $system_map_var|grep -w $var|awk '{print $1}'` | |
295 | ||
296 | reloc_start_addr=`expr $((16#$var1))` | |
297 | reloc_end_addr=`expr $((16#$var2))` | |
298 | dynsym_addr=`expr $((16#$var3))` | |
299 | first_crypto_rodata=`expr $((16#$var4))` | |
300 | last_crypto_rodata=`expr $((16#$var5))` | |
301 | first_fmp_rodata=`expr $((16#$var6))` | |
302 | last_fmp_rodata=`expr $((16#$var7))` | |
303 | ||
304 | ################# CRYPTO ####################### | |
305 | # FOR GENERIC CRYPTO FILES #awk fields to cut | |
306 | fips_crypto[0]=".text first_crypto_text last_crypto_text \$5 \$6" | |
307 | fips_crypto[1]=".rodata first_crypto_rodata last_crypto_rodata \$5 \$6" | |
308 | fips_crypto[2]=".init.text first_crypto_init last_crypto_init \$4 \$5" | |
309 | ||
310 | # # FOR ASM CRYPTO FILES | |
311 | fips_crypto[3]=".text first_crypto_asm_text last_crypto_asm_text \$5 \$6" | |
312 | fips_crypto[4]=".rodata first_crypto_asm_rodata last_crypto_asm_rodata \$5 \$6" | |
313 | fips_crypto[5]=".init.text first_crypto_asm_init last_crypto_asm_init \$4 \$5" | |
314 | ||
315 | offsets_sizes_crypto="offsets_sizes_crypto.txt" | |
316 | offsets_sizes_gen fips_crypto $offsets_sizes_crypto | |
317 | ||
318 | #find hmac_offset in vmlinux for updating | |
319 | cal_hmac_offset builtime_crypto_hmac .rodata | |
320 | ||
321 | ||
322 | ################# FMP ####################### | |
323 | fips_fmp[0]=".text first_fmp_text last_fmp_text \$5 \$6" | |
324 | fips_fmp[1]=".rodata first_fmp_rodata last_fmp_rodata \$5 \$6" | |
325 | fips_fmp[2]=".init.text first_fmp_init last_fmp_init \$4 \$5" | |
326 | ||
327 | offsets_sizes_fmp="offsets_sizes_fmp.txt" | |
328 | offsets_sizes_gen fips_fmp $offsets_sizes_fmp | |
329 | ||
330 | #find hmac_offset in vmlinux for updating | |
331 | cal_hmac_offset builtime_fmp_hmac .rodata | |
332 | ||
333 | rodata_va_addr=`cat vmlinux.elf|grep -w '.rodata'|awk '{print $5}'` | |
334 | rodata_file_addr=`cat vmlinux.elf|grep -w '.rodata'|awk '{print $6}'` | |
335 | va_to_file=`expr $((16#$rodata_va_addr)) - $((16#$rodata_file_addr))` | |
336 | ||
337 | # the loop | |
338 | for index in {0..63} | |
339 | do | |
340 | kaslr_patch $index $va_to_file | |
341 | hmac_patch $index $offsets_sizes_crypto crypto | |
342 | hmac_patch $index $offsets_sizes_fmp fmp | |
343 | done | |
344 | ||
345 | rm -f kaslr_fips | |
346 | rm -f fips_crypto_utils | |
347 | rm -f fips_fmp_utils | |
348 | rm -f vmlinux.elf | |
349 | rm -f offsets_sizes* | |
350 | ||
351 | ELAPSED_TIME=$(($SECONDS - $START_TIME)) | |
352 | echo ">>>>> Time used for generated all hashes is $(($ELAPSED_TIME)) sec" | |
353 | ||
354 | # And we are done... |