-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspectre-meltdown-checker.sh
executable file
·5946 lines (5586 loc) · 214 KB
/
spectre-meltdown-checker.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#! /bin/sh
# SPDX-License-Identifier: GPL-3.0-only
# vim: set ts=8 sw=8 sts=4 noet:
#
# Spectre & Meltdown checker
#
# Check for the latest version at:
# https://github.com/speed47/spectre-meltdown-checker
# git clone https://github.com/speed47/spectre-meltdown-checker.git
# or wget https://meltdown.ovh -O spectre-meltdown-checker.sh
# or curl -L https://meltdown.ovh -o spectre-meltdown-checker.sh
#
# Stephane Lesimple
#
VERSION='0.43'
trap 'exit_cleanup' EXIT
trap '_warn "interrupted, cleaning up..."; exit_cleanup; exit 1' INT
exit_cleanup()
{
# cleanup the temp decompressed config & kernel image
[ -n "$dumped_config" ] && [ -f "$dumped_config" ] && rm -f "$dumped_config"
[ -n "$kerneltmp" ] && [ -f "$kerneltmp" ] && rm -f "$kerneltmp"
[ -n "$kerneltmp2" ] && [ -f "$kerneltmp2" ] && rm -f "$kerneltmp2"
[ -n "$mcedb_tmp" ] && [ -f "$mcedb_tmp" ] && rm -f "$mcedb_tmp"
[ -n "$intel_tmp" ] && [ -d "$intel_tmp" ] && rm -rf "$intel_tmp"
[ "$mounted_debugfs" = 1 ] && umount /sys/kernel/debug 2>/dev/null
[ "$mounted_procfs" = 1 ] && umount "$procfs" 2>/dev/null
[ "$insmod_cpuid" = 1 ] && rmmod cpuid 2>/dev/null
[ "$insmod_msr" = 1 ] && rmmod msr 2>/dev/null
[ "$kldload_cpuctl" = 1 ] && kldunload cpuctl 2>/dev/null
[ "$kldload_vmm" = 1 ] && kldunload vmm 2>/dev/null
}
# if we were git clone'd, adjust VERSION
if [ -d "$(dirname "$0")/.git" ] && command -v git >/dev/null 2>&1; then
describe=$(git -C "$(dirname "$0")" describe --tags --dirty 2>/dev/null)
[ -n "$describe" ] && VERSION=$(echo "$describe" | sed -e s/^v//)
fi
show_usage()
{
# shellcheck disable=SC2086
cat <<EOF
Usage:
Live mode (auto): $(basename $0) [options]
Live mode (manual): $(basename $0) [options] <[--kernel <kimage>] [--config <kconfig>] [--map <mapfile>]> --live
Offline mode: $(basename $0) [options] <[--kernel <kimage>] [--config <kconfig>] [--map <mapfile>]>
Modes:
Two modes are available.
First mode is the "live" mode (default), it does its best to find information about the currently running kernel.
To run under this mode, just start the script without any option (you can also use --live explicitly)
Second mode is the "offline" mode, where you can inspect a non-running kernel.
This mode is automatically enabled when you specify the location of the kernel file, config and System.map files:
--kernel kernel_file specify a (possibly compressed) Linux or BSD kernel file
--config kernel_config specify a kernel config file (Linux only)
--map kernel_map_file specify a kernel System.map file (Linux only)
If you want to use live mode while specifying the location of the kernel, config or map file yourself,
you can add --live to the above options, to tell the script to run in live mode instead of the offline mode,
which is enabled by default when at least one file is specified on the command line.
Options:
--no-color don't use color codes
--verbose, -v increase verbosity level, possibly several times
--explain produce an additional human-readable explanation of actions to take to mitigate a vulnerability
--paranoid require IBPB to deem Variant 2 as mitigated
also require SMT disabled + unconditional L1D flush to deem Foreshadow-NG VMM as mitigated
also require SMT disabled to deem MDS vulnerabilities mitigated
--no-sysfs don't use the /sys interface even if present [Linux]
--sysfs-only only use the /sys interface, don't run our own checks [Linux]
--coreos special mode for CoreOS (use an ephemeral toolbox to inspect kernel) [Linux]
--arch-prefix PREFIX specify a prefix for cross-inspecting a kernel of a different arch, for example "aarch64-linux-gnu-",
so that invoked tools will be prefixed with this (i.e. aarch64-linux-gnu-objdump)
--batch text produce machine readable output, this is the default if --batch is specified alone
--batch short produce only one line with the vulnerabilities separated by spaces
--batch json produce JSON output formatted for Puppet, Ansible, Chef...
--batch nrpe produce machine readable output formatted for NRPE
--batch prometheus produce output for consumption by prometheus-node-exporter
--variant VARIANT specify which variant you'd like to check, by default all variants are checked
VARIANT can be one of 1, 2, 3, 3a, 4, l1tf, msbds, mfbds, mlpds, mdsum, taa, mcepsc, srbds
can be specified multiple times (e.g. --variant 2 --variant 3)
--cve [cve1,cve2,...] specify which CVE you'd like to check, by default all supported CVEs are checked
--hw-only only check for CPU information, don't check for any variant
--no-hw skip CPU information and checks, if you're inspecting a kernel not to be run on this host
--vmm [auto,yes,no] override the detection of the presence of a hypervisor, default: auto
--update-fwdb update our local copy of the CPU microcodes versions database (using the awesome
MCExtractor project and the Intel firmwares GitHub repository)
--update-builtin-fwdb same as --update-fwdb but update builtin DB inside the script itself
--dump-mock-data used to mimick a CPU on an other system, mainly used to help debugging this script
Return codes:
0 (not vulnerable), 2 (vulnerable), 3 (unknown), 255 (error)
IMPORTANT:
A false sense of security is worse than no security at all.
Please use the --disclaimer option to understand exactly what this script does.
EOF
}
show_disclaimer()
{
cat <<EOF
Disclaimer:
This tool does its best to determine whether your system is immune (or has proper mitigations in place) for the
collectively named "speculative execution" vulnerabilities. It doesn't attempt to run any kind of exploit, and can't guarantee
that your system is secure, but rather helps you verifying whether your system has the known correct mitigations in place.
However, some mitigations could also exist in your kernel that this script doesn't know (yet) how to detect, or it might
falsely detect mitigations that in the end don't work as expected (for example, on backported or modified kernels).
Your system exposure also depends on your CPU. As of now, AMD and ARM processors are marked as immune to some or all of these
vulnerabilities (except some specific ARM models). All Intel processors manufactured since circa 1995 are thought to be vulnerable,
except some specific/old models, such as some early Atoms. Whatever processor one uses, one might seek more information
from the manufacturer of that processor and/or of the device in which it runs.
The nature of the discovered vulnerabilities being quite new, the landscape of vulnerable processors can be expected
to change over time, which is why this script makes the assumption that all CPUs are vulnerable, except if the manufacturer
explicitly stated otherwise in a verifiable public announcement.
Please also note that for Spectre vulnerabilities, all software can possibly be exploited, this tool only verifies that the
kernel (which is the core of the system) you're using has the proper protections in place. Verifying all the other software
is out of the scope of this tool. As a general measure, ensure you always have the most up to date stable versions of all
the software you use, especially for those who are exposed to the world, such as network daemons and browsers.
This tool has been released in the hope that it'll be useful, but don't use it to jump to conclusions about your security.
EOF
}
os=$(uname -s)
# parse options
opt_kernel=''
opt_config=''
opt_map=''
opt_live=-1
opt_no_color=0
opt_batch=0
opt_batch_format='text'
opt_verbose=1
opt_cve_list=''
opt_cve_all=1
opt_no_sysfs=0
opt_sysfs_only=0
opt_coreos=0
opt_arch_prefix=''
opt_hw_only=0
opt_no_hw=0
opt_vmm=-1
opt_explain=0
opt_paranoid=0
opt_mock=0
global_critical=0
global_unknown=0
nrpe_vuln=''
supported_cve_list='CVE-2017-5753 CVE-2017-5715 CVE-2017-5754 CVE-2018-3640 CVE-2018-3639 CVE-2018-3615 CVE-2018-3620 CVE-2018-3646 CVE-2018-12126 CVE-2018-12130 CVE-2018-12127 CVE-2019-11091 CVE-2019-11135 CVE-2018-12207 CVE-2020-0543'
# find a sane command to print colored messages, we prefer `printf` over `echo`
# because `printf` behavior is more standard across Linux/BSD
# we'll try to avoid using shell builtins that might not take options
echo_cmd_type='echo'
# ignore SC2230 here because `which` ignores builtins while `command -v` doesn't, and
# we don't want builtins here. Even if `which` is not installed, we'll fallback to the
# `echo` builtin anyway, so this is safe.
# shellcheck disable=SC2230
if command -v printf >/dev/null 2>&1; then
echo_cmd=$(command -v printf)
echo_cmd_type='printf'
elif which echo >/dev/null 2>&1; then
echo_cmd=$(which echo)
else
# maybe the `which` command is broken?
[ -x /bin/echo ] && echo_cmd=/bin/echo
# for Android
[ -x /system/bin/echo ] && echo_cmd=/system/bin/echo
fi
# still empty? fallback to builtin
[ -z "$echo_cmd" ] && echo_cmd='echo'
__echo()
{
opt="$1"
shift
_msg="$*"
if [ "$opt_no_color" = 1 ] ; then
# strip ANSI color codes
# some sed versions (i.e. toybox) can't seem to handle
# \033 aka \x1B correctly, so do it for them.
if [ "$echo_cmd_type" = printf ]; then
_interpret_chars=''
else
_interpret_chars='-e'
fi
_ctrlchar=$($echo_cmd $_interpret_chars "\033")
_msg=$($echo_cmd $_interpret_chars "$_msg" | sed -r "s/$_ctrlchar\[([0-9][0-9]?(;[0-9][0-9]?)?)?m//g")
fi
if [ "$echo_cmd_type" = printf ]; then
if [ "$opt" = "-n" ]; then
$echo_cmd "$_msg"
else
$echo_cmd "$_msg\n"
fi
else
# shellcheck disable=SC2086
$echo_cmd $opt -e "$_msg"
fi
}
_echo()
{
if [ "$opt_verbose" -ge "$1" ]; then
shift
__echo '' "$*"
fi
}
_echo_nol()
{
if [ "$opt_verbose" -ge "$1" ]; then
shift
__echo -n "$*"
fi
}
_warn()
{
_echo 0 "\033[31m$*\033[0m" >&2
}
_info()
{
_echo 1 "$*"
}
_info_nol()
{
_echo_nol 1 "$*"
}
_verbose()
{
_echo 2 "$*"
}
_verbose_nol()
{
_echo_nol 2 "$*"
}
_debug()
{
_echo 3 "\033[34m(debug) $*\033[0m"
}
explain()
{
if [ "$opt_explain" = 1 ] ; then
_info ''
_info "> \033[41m\033[30mHow to fix:\033[0m $*"
fi
}
cve2name()
{
case "$1" in
CVE-2017-5753) echo "Spectre Variant 1, bounds check bypass";;
CVE-2017-5715) echo "Spectre Variant 2, branch target injection";;
CVE-2017-5754) echo "Variant 3, Meltdown, rogue data cache load";;
CVE-2018-3640) echo "Variant 3a, rogue system register read";;
CVE-2018-3639) echo "Variant 4, speculative store bypass";;
CVE-2018-3615) echo "Foreshadow (SGX), L1 terminal fault";;
CVE-2018-3620) echo "Foreshadow-NG (OS), L1 terminal fault";;
CVE-2018-3646) echo "Foreshadow-NG (VMM), L1 terminal fault";;
CVE-2018-12126) echo "Fallout, microarchitectural store buffer data sampling (MSBDS)";;
CVE-2018-12130) echo "ZombieLoad, microarchitectural fill buffer data sampling (MFBDS)";;
CVE-2018-12127) echo "RIDL, microarchitectural load port data sampling (MLPDS)";;
CVE-2019-11091) echo "RIDL, microarchitectural data sampling uncacheable memory (MDSUM)";;
CVE-2019-11135) echo "ZombieLoad V2, TSX Asynchronous Abort (TAA)";;
CVE-2018-12207) echo "No eXcuses, iTLB Multihit, machine check exception on page size changes (MCEPSC)";;
CVE-2020-0543) echo "Special Register Buffer Data Sampling (SRBDS)";;
*) echo "$0: error: invalid CVE '$1' passed to cve2name()" >&2; exit 255;;
esac
}
is_cpu_vulnerable_cached=0
_is_cpu_vulnerable_cached()
{
# shellcheck disable=SC2086
case "$1" in
CVE-2017-5753) return $variant1;;
CVE-2017-5715) return $variant2;;
CVE-2017-5754) return $variant3;;
CVE-2018-3640) return $variant3a;;
CVE-2018-3639) return $variant4;;
CVE-2018-3615) return $variantl1tf_sgx;;
CVE-2018-3620) return $variantl1tf;;
CVE-2018-3646) return $variantl1tf;;
CVE-2018-12126) return $variant_msbds;;
CVE-2018-12130) return $variant_mfbds;;
CVE-2018-12127) return $variant_mlpds;;
CVE-2019-11091) return $variant_mdsum;;
CVE-2019-11135) return $variant_taa;;
CVE-2018-12207) return $variant_itlbmh;;
CVE-2020-0543) return $variant_srbds;;
*) echo "$0: error: invalid variant '$1' passed to is_cpu_vulnerable()" >&2; exit 255;;
esac
}
is_cpu_vulnerable()
{
# param: one of the $supported_cve_list items
# returns 0 if vulnerable, 1 if not vulnerable
# (note that in shell, a return of 0 is success)
# by default, everything is vulnerable, we work in a "whitelist" logic here.
# usage: is_cpu_vulnerable CVE-xxxx-yyyy && do something if vulnerable
if [ "$is_cpu_vulnerable_cached" = 1 ]; then
_is_cpu_vulnerable_cached "$1"
return $?
fi
variant1=''
variant2=''
variant3=''
variant3a=''
variant4=''
variantl1tf=''
variant_msbds=''
variant_mfbds=''
variant_mlpds=''
variant_mdsum=''
variant_taa=''
variant_itlbmh=''
variant_srbds=''
if is_cpu_mds_free; then
[ -z "$variant_msbds" ] && variant_msbds=immune
[ -z "$variant_mfbds" ] && variant_mfbds=immune
[ -z "$variant_mlpds" ] && variant_mlpds=immune
[ -z "$variant_mdsum" ] && variant_mdsum=immune
_debug "is_cpu_vulnerable: cpu not affected by Microarchitectural Data Sampling"
fi
if is_cpu_taa_free; then
[ -z "$variant_taa" ] && variant_taa=immune
_debug "is_cpu_vulnerable: cpu not affected by TSX Asynhronous Abort"
fi
if is_cpu_srbds_free; then
[ -z "$variant_srbds" ] && variant_srbds=immune
_debug "is_cpu_vulnerable: cpu not affected by Special Register Buffer Data Sampling"
fi
if is_cpu_specex_free; then
variant1=immune
variant2=immune
variant3=immune
variant3a=immune
variant4=immune
variantl1tf=immune
variant_msbds=immune
variant_mfbds=immune
variant_mlpds=immune
variant_mdsum=immune
variant_taa=immune
variant_srbds=immune
elif is_intel; then
# Intel
# https://github.com/crozone/SpectrePoC/issues/1 ^F E5200 => spectre 2 not vulnerable
# https://github.com/paboldin/meltdown-exploit/issues/19 ^F E5200 => meltdown vulnerable
# model name : Pentium(R) Dual-Core CPU E5200 @ 2.50GHz
if echo "$cpu_friendly_name" | grep -qE 'Pentium\(R\) Dual-Core[[:space:]]+CPU[[:space:]]+E[0-9]{4}K?'; then
variant1=vuln
[ -z "$variant2" ] && variant2=immune
variant3=vuln
fi
if [ "$capabilities_rdcl_no" = 1 ]; then
# capability bit for future Intel processor that will explicitly state
# that they're not vulnerable to Meltdown
# this var is set in check_cpu()
[ -z "$variant3" ] && variant3=immune
[ -z "$variantl1tf" ] && variantl1tf=immune
_debug "is_cpu_vulnerable: RDCL_NO is set so not vuln to meltdown nor l1tf"
fi
if [ "$capabilities_ssb_no" = 1 ]; then
# capability bit for future Intel processor that will explicitly state
# that they're not vulnerable to Variant 4
# this var is set in check_cpu()
[ -z "$variant4" ] && variant4=immune
_debug "is_cpu_vulnerable: SSB_NO is set so not vuln to variant4"
fi
if is_cpu_ssb_free; then
[ -z "$variant4" ] && variant4=immune
_debug "is_cpu_vulnerable: cpu not affected by speculative store bypass so not vuln to variant4"
fi
# variant 3a
if [ "$cpu_family" = 6 ]; then
if [ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNL" ] || [ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNM" ]; then
_debug "is_cpu_vulnerable: xeon phi immune to variant 3a"
[ -z "$variant3a" ] && variant3a=immune
elif [ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_D" ]; then
# https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00115.html
# https://github.com/speed47/spectre-meltdown-checker/issues/310
# => silvermont CPUs (aka cherry lake for tablets and brawsell for mobile/desktop) don't seem to be vulnerable
# => goldmont ARE vulnerable
_debug "is_cpu_vulnerable: silvermont immune to variant 3a"
[ -z "$variant3a" ] && variant3a=immune
fi
fi
# L1TF (RDCL_NO already checked above)
if [ "$cpu_family" = 6 ]; then
if [ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL_TABLET" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_BONNELL" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_BONNELL_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_D" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT_NP" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_D" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_PLUS" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_TREMONT_D" ] || \
[ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNL" ] || \
[ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNM" ]; then
_debug "is_cpu_vulnerable: intel family 6 but model known to be immune to l1tf"
[ -z "$variantl1tf" ] && variantl1tf=immune
else
_debug "is_cpu_vulnerable: intel family 6 is vuln to l1tf"
variantl1tf=vuln
fi
elif [ "$cpu_family" -lt 6 ]; then
_debug "is_cpu_vulnerable: intel family < 6 is immune to l1tf"
[ -z "$variantl1tf" ] && variantl1tf=immune
fi
elif is_amd || is_hygon; then
# AMD revised their statement about variant2 => vulnerable
# https://www.amd.com/en/corporate/speculative-execution
variant1=vuln
variant2=vuln
[ -z "$variant3" ] && variant3=immune
# https://www.amd.com/en/corporate/security-updates
# "We have not identified any AMD x86 products susceptible to the Variant 3a vulnerability in our analysis to-date."
[ -z "$variant3a" ] && variant3a=immune
if is_cpu_ssb_free; then
[ -z "$variant4" ] && variant4=immune
_debug "is_cpu_vulnerable: cpu not affected by speculative store bypass so not vuln to variant4"
fi
variantl1tf=immune
elif [ "$cpu_vendor" = CAVIUM ]; then
variant3=immune
variant3a=immune
variantl1tf=immune
elif [ "$cpu_vendor" = ARM ]; then
# ARM
# reference: https://developer.arm.com/support/security-update
# some devices (phones or other) have several ARMs and as such different part numbers,
# an example is "bigLITTLE". we shouldn't rely on the first CPU only, so we check the whole list
i=0
for cpupart in $cpu_part_list
do
i=$(( i + 1 ))
# do NOT quote $cpu_arch_list below
# shellcheck disable=SC2086
cpuarch=$(echo $cpu_arch_list | awk '{ print $'$i' }')
_debug "checking cpu$i: <$cpupart> <$cpuarch>"
# some kernels report AArch64 instead of 8
[ "$cpuarch" = "AArch64" ] && cpuarch=8
if [ -n "$cpupart" ] && [ -n "$cpuarch" ]; then
# Cortex-R7 and Cortex-R8 are real-time and only used in medical devices or such
# I can't find their CPU part number, but it's probably not that useful anyway
# model R7 R8 A8 A9 A12 A15 A17 A57 A72 A73 A75 A76
# part ? ? c08 c09 c0d c0f c0e d07 d08 d09 d0a d0b?
# arch 7? 7? 7 7 7 7 7 8 8 8 8 8
#
# Whitelist identified non-vulnerable processors, use vulnerability information from
# https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability
#
# Maintain cumulative check of vulnerabilities -
# if at least one of the cpu is vulnerable, then the system is vulnerable
if [ "$cpuarch" = 7 ] && echo "$cpupart" | grep -q -w -e 0xc08 -e 0xc09 -e 0xc0d -e 0xc0e; then
variant1=vuln
variant2=vuln
[ -z "$variant3" ] && variant3=immune
[ -z "$variant3a" ] && variant3a=immune
[ -z "$variant4" ] && variant4=immune
_debug "checking cpu$i: armv7 A8/A9/A12/A17 non vulnerable to variants 3, 3a & 4"
elif [ "$cpuarch" = 7 ] && echo "$cpupart" | grep -q -w -e 0xc0f; then
variant1=vuln
variant2=vuln
[ -z "$variant3" ] && variant3=immune
variant3a=vuln
[ -z "$variant4" ] && variant4=immune
_debug "checking cpu$i: armv7 A15 non vulnerable to variants 3 & 4"
elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -q -w -e 0xd07 -e 0xd08; then
variant1=vuln
variant2=vuln
[ -z "$variant3" ] && variant3=immune
variant3a=vuln
variant4=vuln
_debug "checking cpu$i: armv8 A57/A72 non vulnerable to variants 3"
elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -q -w -e 0xd09; then
variant1=vuln
variant2=vuln
[ -z "$variant3" ] && variant3=immune
[ -z "$variant3a" ] && variant3a=immune
variant4=vuln
_debug "checking cpu$i: armv8 A73 non vulnerable to variants 3 & 3a"
elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -q -w -e 0xd0a; then
variant1=vuln
variant2=vuln
variant3=vuln
[ -z "$variant3a" ] && variant3a=immune
variant4=vuln
_debug "checking cpu$i: armv8 A75 non vulnerable to variant 3a"
elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -q -w -e 0xd0b; then
variant1=vuln
[ -z "$variant2" ] && variant2=immune
[ -z "$variant3" ] && variant3=immune
[ -z "$variant3a" ] && variant3a=immune
variant4=vuln
_debug "checking cpu$i: armv8 A76 non vulnerable to variant 2, 3 & 3a"
elif [ "$cpuarch" -le 7 ] || { [ "$cpuarch" = 8 ] && [ $(( cpupart )) -lt $(( 0xd07 )) ]; } ; then
[ -z "$variant1" ] && variant1=immune
[ -z "$variant2" ] && variant2=immune
[ -z "$variant3" ] && variant3=immune
[ -z "$variant3a" ] && variant3a=immune
[ -z "$variant4" ] && variant4=immune
_debug "checking cpu$i: arm arch$cpuarch, all immune (v7 or v8 and model < 0xd07)"
else
variant1=vuln
variant2=vuln
variant3=vuln
variant3a=vuln
variant4=vuln
_debug "checking cpu$i: arm unknown arch$cpuarch part$cpupart, considering vuln"
fi
fi
_debug "is_cpu_vulnerable: for cpu$i and so far, we have <$variant1> <$variant2> <$variant3> <$variant3a> <$variant4>"
done
variantl1tf=immune
fi
# we handle iTLB Multihit here (not linked to is_specex_free)
if is_intel; then
# commit f9aa6b73a407b714c9aac44734eb4045c893c6f7
if [ "$cpu_family" = 6 ]; then
if [ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL_TABLET" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_BONNELL" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_BONNELL_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_D" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNL" ] || \
[ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNM" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_D" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_PLUS" ]; then
_debug "is_cpu_vulnerable: intel family 6 but model known to be immune to itlbmh"
[ -z "$variant_itlbmh" ] && variant_itlbmh=immune
else
_debug "is_cpu_vulnerable: intel family 6 is vuln to itlbmh"
variant_itlbmh=vuln
fi
elif [ "$cpu_family" -lt 6 ]; then
_debug "is_cpu_vulnerable: intel family < 6 is immune to itlbmh"
[ -z "$variant_itlbmh" ] && variant_itlbmh=immune
fi
else
_debug "is_cpu_vulnerable: non-intel not vulnerable to itlbmh"
[ -z "$variant_itlbmh" ] && variant_itlbmh=immune
fi
_debug "is_cpu_vulnerable: temp results are <$variant1> <$variant2> <$variant3> <$variant3a> <$variant4> <$variantl1tf>"
[ "$variant1" = "immune" ] && variant1=1 || variant1=0
[ "$variant2" = "immune" ] && variant2=1 || variant2=0
[ "$variant3" = "immune" ] && variant3=1 || variant3=0
[ "$variant3a" = "immune" ] && variant3a=1 || variant3a=0
[ "$variant4" = "immune" ] && variant4=1 || variant4=0
[ "$variantl1tf" = "immune" ] && variantl1tf=1 || variantl1tf=0
[ "$variant_msbds" = "immune" ] && variant_msbds=1 || variant_msbds=0
[ "$variant_mfbds" = "immune" ] && variant_mfbds=1 || variant_mfbds=0
[ "$variant_mlpds" = "immune" ] && variant_mlpds=1 || variant_mlpds=0
[ "$variant_mdsum" = "immune" ] && variant_mdsum=1 || variant_mdsum=0
[ "$variant_taa" = "immune" ] && variant_taa=1 || variant_taa=0
[ "$variant_itlbmh" = "immune" ] && variant_itlbmh=1 || variant_itlbmh=0
[ "$variant_srbds" = "immune" ] && variant_srbds=1 || variant_srbds=0
variantl1tf_sgx="$variantl1tf"
# even if we are vulnerable to L1TF, if there's no SGX, we're not vulnerable to the original foreshadow
[ "$cpuid_sgx" = 0 ] && variantl1tf_sgx=1
_debug "is_cpu_vulnerable: final results are <$variant1> <$variant2> <$variant3> <$variant3a> <$variant4> <$variantl1tf> <$variantl1tf_sgx>"
is_cpu_vulnerable_cached=1
_is_cpu_vulnerable_cached "$1"
return $?
}
is_cpu_specex_free()
{
# return true (0) if the CPU doesn't do speculative execution, false (1) if it does.
# if it's not in the list we know, return false (1).
# source: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/common.c#n882
# { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SALTWELL, X86_FEATURE_ANY },
# { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SALTWELL_TABLET, X86_FEATURE_ANY },
# { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_BONNELL_MID, X86_FEATURE_ANY },
# { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SALTWELL_MID, X86_FEATURE_ANY },
# { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_BONNELL, X86_FEATURE_ANY },
# { X86_VENDOR_CENTAUR, 5 },
# { X86_VENDOR_INTEL, 5 },
# { X86_VENDOR_NSC, 5 },
# { X86_VENDOR_ANY, 4 },
parse_cpu_details
if is_intel; then
if [ "$cpu_family" = 6 ]; then
if [ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL_TABLET" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_BONNELL_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_BONNELL" ]; then
return 0
fi
elif [ "$cpu_family" = 5 ]; then
return 0
fi
fi
[ "$cpu_family" = 4 ] && return 0
return 1
}
is_cpu_mds_free()
{
# return true (0) if the CPU isn't affected by microarchitectural data sampling, false (1) if it does.
# if it's not in the list we know, return false (1).
# source: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/common.c
#VULNWL_INTEL(ATOM_GOLDMONT, NO_MDS | NO_L1TF),
#VULNWL_INTEL(ATOM_GOLDMONT_X, NO_MDS | NO_L1TF),
#VULNWL_INTEL(ATOM_GOLDMONT_PLUS, NO_MDS | NO_L1TF),
#/* AMD Family 0xf - 0x12 */
#VULNWL_AMD(0x0f, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
#VULNWL_AMD(0x10, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
#VULNWL_AMD(0x11, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
#VULNWL_AMD(0x12, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
#/* FAMILY_ANY must be last, otherwise 0x0f - 0x12 matches won't work */
#VULNWL_AMD(X86_FAMILY_ANY, NO_MELTDOWN | NO_L1TF | NO_MDS),
#VULNWL_HYGON(X86_FAMILY_ANY, NO_MELTDOWN | NO_L1TF | NO_MDS),
parse_cpu_details
if is_intel; then
if [ "$cpu_family" = 6 ]; then
if [ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_D" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_PLUS" ]; then
return 0
fi
fi
[ "$capabilities_mds_no" = 1 ] && return 0
fi
# official statement from AMD says none of their CPUs are vulnerable
# https://www.amd.com/en/corporate/product-security
# https://www.amd.com/system/files/documents/security-whitepaper.pdf
if is_amd; then
return 0
elif is_hygon; then
return 0
elif [ "$cpu_vendor" = CAVIUM ]; then
return 0
elif [ "$cpu_vendor" = ARM ]; then
return 0
fi
return 1
}
is_cpu_taa_free()
{
# return true (0) if the CPU isn't affected by tsx asynchronous aborts, false (1) if it does.
# There are three types of processors that do not require additional mitigations.
# 1. CPUs that do not support Intel TSX are not affected.
# 2. CPUs that enumerate IA32_ARCH_CAPABILITIES[TAA_NO] (bit 8)=1 are not affected.
# 3. CPUs that support Intel TSX and do not enumerate IA32_ARCH_CAPABILITIES[MDS_NO] (bit 5)=1
# do not need additional mitigations beyond what is already required to mitigate MDS.
if ! is_intel; then
return 0
# is intel
elif [ "$capabilities_taa_no" = 1 ] || [ "$cpuid_rtm" = 0 ]; then
return 0
fi
return 1
}
is_cpu_srbds_free()
{
# return zero (0) if the CPU isn't affected by special register buffer data sampling, one (1) if it is.
# If it's not in the list we know, return one (1).
# source: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/common.c
#
# A processor is affected by SRBDS if its Family_Model and stepping is in the
# following list, with the exception of the listed processors
# exporting MDS_NO while Intel TSX is available yet not enabled. The
# latter class of processors are only affected when Intel TSX is enabled
# by software using TSX_CTRL_MSR otherwise they are not affected.
#
# ============= ============ ========
# common name Family_Model Stepping
# ============= ============ ========
# IvyBridge 06_3AH All (INTEL_FAM6_IVYBRIDGE)
#
# Haswell 06_3CH All (INTEL_FAM6_HASWELL)
# Haswell_L 06_45H All (INTEL_FAM6_HASWELL_L)
# Haswell_G 06_46H All (INTEL_FAM6_HASWELL_G)
#
# Broadwell_G 06_47H All (INTEL_FAM6_BROADWELL_G)
# Broadwell 06_3DH All (INTEL_FAM6_BROADWELL)
#
# Skylake_L 06_4EH All (INTEL_FAM6_SKYLAKE_L)
# Skylake 06_5EH All (INTEL_FAM6_SKYLAKE)
#
# Kabylake_L 06_8EH <=0xC (MDS_NO) (INTEL_FAM6_KABYLAKE_L)
#
# Kabylake 06_9EH <=0xD (MDS_NO) (INTEL_FAM6_KABYLAKE)
# ============= ============ ========
parse_cpu_details
if is_intel; then
if [ "$cpu_family" = 6 ]; then
if [ "$cpu_model" = "$INTEL_FAM6_IVYBRIDGE" ] || \
[ "$cpu_model" = "$INTEL_FAM6_HASWELL" ] || \
[ "$cpu_model" = "$INTEL_FAM6_HASWELL_L" ] || \
[ "$cpu_model" = "$INTEL_FAM6_HASWELL_G" ] || \
[ "$cpu_model" = "$INTEL_FAM6_BROADWELL_G" ] || \
[ "$cpu_model" = "$INTEL_FAM6_BROADWELL" ] || \
[ "$cpu_model" = "$INTEL_FAM6_SKYLAKE_L" ] || \
[ "$cpu_model" = "$INTEL_FAM6_SKYLAKE" ]; then
return 1
elif [ "$cpu_model" = "$INTEL_FAM6_KABYLAKE_L" ] && [ "$cpu_stepping" -le 12 ] || \
[ "$cpu_model" = "$INTEL_FAM6_KABYLAKE" ] && [ "$cpu_stepping" -le 13 ]; then
if [ "$capabilities_mds_no" -eq 1 ] && { [ "$cpuid_rtm" -eq 0 ] || [ "$tsx_ctrl_msr_rtm_disable" -eq 1 ] ;} ; then
return 0
else
return 1
fi
fi
fi
fi
return 0
}
is_cpu_ssb_free()
{
# return true (0) if the CPU isn't affected by speculative store bypass, false (1) if it does.
# if it's not in the list we know, return false (1).
# source1: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/common.c#n945
# source2: https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git/tree/arch/x86/kernel/cpu/common.c
# Only list CPUs that speculate but are immune, to avoid duplication of cpus listed in is_cpu_specex_free()
#{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT },
#{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT },
#{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT_X },
#{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT_MID },
#{ X86_VENDOR_INTEL, 6, INTEL_FAM6_CORE_YONAH },
#{ X86_VENDOR_INTEL, 6, INTEL_FAM6_XEON_PHI_KNL },
#{ X86_VENDOR_INTEL, 6, INTEL_FAM6_XEON_PHI_KNM },
#{ X86_VENDOR_AMD, 0x12, },
#{ X86_VENDOR_AMD, 0x11, },
#{ X86_VENDOR_AMD, 0x10, },
#{ X86_VENDOR_AMD, 0xf, },
parse_cpu_details
if is_intel; then
if [ "$cpu_family" = 6 ]; then
if [ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_D" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_MID" ]; then
return 0
elif [ "$cpu_model" = "$INTEL_FAM6_CORE_YONAH" ] || \
[ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNL" ] || \
[ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNM" ]; then
return 0
fi
fi
fi
if is_amd; then
if [ "$cpu_family" = "18" ] || \
[ "$cpu_family" = "17" ] || \
[ "$cpu_family" = "16" ] || \
[ "$cpu_family" = "15" ]; then
return 0
fi
fi
if is_hygon; then
return 1
fi
[ "$cpu_family" = 4 ] && return 0
return 1
}
show_header()
{
_info "Spectre and Meltdown mitigation detection tool v$VERSION"
_info
}
[ -z "$HOME" ] && HOME="$(getent passwd "$(whoami)" | cut -d: -f6)"
mcedb_cache="$HOME/.mcedb"
update_fwdb()
{
show_header
if [ -r "$mcedb_cache" ]; then
previous_dbversion=$(awk '/^# %%% MCEDB / { print $4 }' "$mcedb_cache")
fi
# first, download the MCE.db from the excellent platomav's MCExtractor project
mcedb_tmp="$(mktemp /tmp/mcedb-XXXXXX)"
mcedb_url='https://github.com/platomav/MCExtractor/raw/master/MCE.db'
_info_nol "Fetching MCE.db from the MCExtractor project... "
if command -v wget >/dev/null 2>&1; then
wget -q "$mcedb_url" -O "$mcedb_tmp"; ret=$?
elif command -v curl >/dev/null 2>&1; then
curl -sL "$mcedb_url" -o "$mcedb_tmp"; ret=$?
elif command -v fetch >/dev/null 2>&1; then
fetch -q "$mcedb_url" -o "$mcedb_tmp"; ret=$?
else
echo ERROR "please install one of \`wget\`, \`curl\` of \`fetch\` programs"
return 1
fi
if [ "$ret" != 0 ]; then
echo ERROR "error $ret while downloading MCE.db"
return $ret
fi
echo DONE
# second, get the Intel firmwares from GitHub
intel_tmp="$(mktemp -d /tmp/intelfw-XXXXXX)"
intel_url="https://github.com/intel/Intel-Linux-Processor-Microcode-Data-Files/archive/master.zip"
_info_nol "Fetching Intel firmwares... "
## https://github.com/intel/Intel-Linux-Processor-Microcode-Data-Files.git
if command -v wget >/dev/null 2>&1; then
wget -q "$intel_url" -O "$intel_tmp/fw.zip"; ret=$?
elif command -v curl >/dev/null 2>&1; then
curl -sL "$intel_url" -o "$intel_tmp/fw.zip"; ret=$?
elif command -v fetch >/dev/null 2>&1; then
fetch -q "$intel_url" -o "$intel_tmp/fw.zip"; ret=$?
else
echo ERROR "please install one of \`wget\`, \`curl\` of \`fetch\` programs"
return 1
fi
if [ "$ret" != 0 ]; then
echo ERROR "error $ret while downloading Intel firmwares"
return $ret
fi
echo DONE
# now extract MCEdb contents using sqlite
_info_nol "Extracting MCEdb data... "
if ! command -v sqlite3 >/dev/null 2>&1; then
echo ERROR "please install the \`sqlite3\` program"
return 1
fi
mcedb_revision=$(sqlite3 "$mcedb_tmp" "select revision from MCE")
mcedb_date=$(sqlite3 "$mcedb_tmp" "select strftime('%Y/%m/%d', date, 'unixepoch') from MCE")
if [ -z "$mcedb_revision" ]; then
echo ERROR "downloaded file seems invalid"
return 1
fi
echo OK "MCExtractor database revision $mcedb_revision dated $mcedb_date"
# parse Intel firmwares to get their versions
_info_nol "Integrating Intel firmwares data to db... "
if ! command -v unzip >/dev/null 2>&1; then
echo ERROR "please install the \`unzip\` program"
return 1
fi
( cd "$intel_tmp" && unzip fw.zip >/dev/null; )
if ! [ -d "$intel_tmp/Intel-Linux-Processor-Microcode-Data-Files-master/intel-ucode" ]; then
echo ERROR "expected the 'intel-ucode' folder in the downloaded zip file"
return 1
fi
if ! command -v iucode_tool >/dev/null 2>&1; then
if ! command -v iucode-tool >/dev/null 2>&1; then
echo ERROR "please install the \`iucode-tool\` program"
return 1
else
iucode_tool="iucode-tool"
fi
else
iucode_tool="iucode_tool"
fi
# 079/001: sig 0x000106c2, pf_mask 0x01, 2009-04-10, rev 0x0217, size 5120
# 078/004: sig 0x000106ca, pf_mask 0x10, 2009-08-25, rev 0x0107, size 5120
$iucode_tool -l "$intel_tmp/Intel-Linux-Processor-Microcode-Data-Files-master/intel-ucode" | grep -wF sig | while read -r _line
do
_line=$( echo "$_line" | tr -d ',')
_cpuid=$( echo "$_line" | awk '{print $3}')
_cpuid=$(( _cpuid ))
_cpuid=$(printf "0x%08X" "$_cpuid")
_date=$( echo "$_line" | awk '{print $6}' | tr -d '-')
_version=$(echo "$_line" | awk '{print $8}')
_version=$(( _version ))
_version=$(printf "0x%08X" "$_version")
_sqlstm="$(printf "INSERT INTO Intel (cpuid,version,yyyymmdd) VALUES (\"%s\",\"%s\",\"%s\");" "$(printf "%08X" "$_cpuid")" "$(printf "%08X" "$_version")" "$_date")"
sqlite3 "$mcedb_tmp" "$_sqlstm"
done
_intel_latest_date=$(sqlite3 "$mcedb_tmp" "SELECT yyyymmdd from Intel ORDER BY yyyymmdd DESC LIMIT 1;")
echo DONE "(version $_intel_latest_date)"
dbdate=$(echo "$mcedb_date" | tr -d '/')
if [ "$dbdate" -lt "$_intel_latest_date" ]; then
dbdate="$_intel_latest_date"
fi
dbversion="$mcedb_revision.$dbdate+i$_intel_latest_date"
if [ "$1" != builtin ] && [ -n "$previous_dbversion" ] && [ "$previous_dbversion" = "v$dbversion" ]; then
echo "We already have this version locally, no update needed"
return 0
fi
_info_nol "Building local database... "
{
echo "# Spectre & Meltdown Checker";
echo "# %%% MCEDB v$dbversion";
sqlite3 "$mcedb_tmp" "SELECT '# I,0x'||t1.cpuid||',0x'||MAX(t1.version)||','||t1.yyyymmdd FROM Intel AS t1 LEFT OUTER JOIN Intel AS t2 ON t2.cpuid=t1.cpuid AND t2.yyyymmdd > t1.yyyymmdd WHERE t2.yyyymmdd IS NULL GROUP BY t1.cpuid ORDER BY t1.cpuid ASC;" | grep -v '^# .,0x00000000,';
sqlite3 "$mcedb_tmp" "SELECT '# A,0x'||t1.cpuid||',0x'||MAX(t1.version)||','||t1.yyyymmdd FROM AMD AS t1 LEFT OUTER JOIN AMD AS t2 ON t2.cpuid=t1.cpuid AND t2.yyyymmdd > t1.yyyymmdd WHERE t2.yyyymmdd IS NULL GROUP BY t1.cpuid ORDER BY t1.cpuid ASC;" | grep -v '^# .,0x00000000,';
} > "$mcedb_cache"
echo DONE "(version $dbversion)"
if [ "$1" = builtin ]; then
newfile=$(mktemp /tmp/smc-XXXXXX)
awk '/^# %%% MCEDB / { exit }; { print }' "$0" > "$newfile"
awk '{ if (NR>1) { print } }' "$mcedb_cache" >> "$newfile"
cat "$newfile" > "$0"
rm -f "$newfile"
fi
}
parse_opt_file()
{
# parse_opt_file option_name option_value
option_name="$1"
option_value="$2"
if [ -z "$option_value" ]; then
show_header
show_usage
echo "$0: error: --$option_name expects one parameter (a file)" >&2
exit 1
elif [ ! -e "$option_value" ]; then
show_header
echo "$0: error: couldn't find file $option_value" >&2
exit 1
elif [ ! -f "$option_value" ]; then
show_header
echo "$0: error: $option_value is not a file" >&2
exit 1
elif [ ! -r "$option_value" ]; then
show_header
echo "$0: error: couldn't read $option_value (are you root?)" >&2
exit 1
fi
echo "$option_value"
exit 0
}
while [ -n "$1" ]; do
if [ "$1" = "--kernel" ]; then
opt_kernel=$(parse_opt_file kernel "$2"); ret=$?
[ $ret -ne 0 ] && exit 255
shift 2
elif [ "$1" = "--config" ]; then
opt_config=$(parse_opt_file config "$2"); ret=$?
[ $ret -ne 0 ] && exit 255
shift 2
elif [ "$1" = "--map" ]; then
opt_map=$(parse_opt_file map "$2"); ret=$?