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
|
From 8caeb440a176cb7f8908403da51106c74e2b5cb8 Mon Sep 17 00:00:00 2001
From: Hilton Chain <hako@ultrarare.space>
Date: Thu, 27 Jul 2023 14:45:14 +0800
Subject: [PATCH] Replace fwdb downloader with a local file option.
Also warn about non-free software.
---
spectre-meltdown-checker.sh | 253 +++---------------------------------
1 file changed, 17 insertions(+), 236 deletions(-)
diff --git a/spectre-meltdown-checker.sh b/spectre-meltdown-checker.sh
index e7b6b33..33bdf71 100755
--- a/spectre-meltdown-checker.sh
+++ b/spectre-meltdown-checker.sh
@@ -23,9 +23,6 @@ exit_cleanup()
[ -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"
- [ -n "${linuxfw_tmp:-}" ] && [ -f "$linuxfw_tmp" ] && rm -f "$linuxfw_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
@@ -97,9 +94,9 @@ show_usage()
--vmm [auto,yes,no] override the detection of the presence of a hypervisor, default: auto
--allow-msr-write allow probing for write-only MSRs, this might produce kernel logs or be blocked by your system
--cpu [#,all] interact with CPUID and MSR of CPU core number #, or all (default: CPU core 0)
- --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
+ --with-fwdb FILE read CPU microcode version information from FILE
+ Note that most CPU microcode is distributed as binaries without source -- relying on
+ such non-free firmware as sole protection against security vulnerabilities is ill-advised.
--dump-mock-data used to mimick a CPU on an other system, mainly used to help debugging this script
Return codes:
@@ -858,217 +855,6 @@ show_header()
_info
}
-# Family-Model-Stepping to CPUID
-# prints CPUID in base-10 to stdout
-fms2cpuid()
-{
- _family="$1"
- _model="$2"
- _stepping="$3"
-
- if [ "$(( _family ))" -le 15 ]; then
- _extfamily=0
- _lowfamily=$(( _family ))
- else
- # when we have a family > 0xF, then lowfamily is stuck at 0xF
- # and extfamily is ADDED to it (as in "+"), to ensure old software
- # never sees a lowfamily < 0xF for newer families
- _lowfamily=15
- _extfamily=$(( (_family) - 15 ))
- fi
- _extmodel=$(( (_model & 0xF0 ) >> 4 ))
- _lowmodel=$(( (_model & 0x0F ) >> 0 ))
- echo $(( (_stepping & 0x0F) | (_lowmodel << 4) | (_lowfamily << 8) | (_extmodel << 16) | (_extfamily << 20) ))
-}
-
-[ -z "$HOME" ] && HOME="$(getent passwd "$(whoami)" | cut -d: -f6)"
-mcedb_cache="$HOME/.mcedb"
-update_fwdb()
-{
- show_header
-
- set -e
-
- 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 -t smc-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 -t smc-intelfw-XXXXXX)"
- intel_url="https://github.com/intel/Intel-Linux-Processor-Microcode-Data-Files/archive/main.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\"")
- if [ -z "$mcedb_revision" ]; then
- echo ERROR "downloaded file seems invalid"
- return 1
- fi
- sqlite3 "$mcedb_tmp" "ALTER TABLE \"Intel\" ADD COLUMN \"origin\" TEXT"
- sqlite3 "$mcedb_tmp" "ALTER TABLE \"AMD\" ADD COLUMN \"origin\" TEXT"
- sqlite3 "$mcedb_tmp" "UPDATE \"Intel\" SET \"origin\"='mce'"
- sqlite3 "$mcedb_tmp" "UPDATE \"AMD\" SET \"origin\"='mce'"
-
- echo OK "MCExtractor database revision $mcedb_revision"
-
- # 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-main/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-main/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\" (\"origin\",\"cpuid\",\"version\",\"yyyymmdd\") VALUES ('%s','%s','%s','%s');" "intel" "$(printf "%08X" "$_cpuid")" "$(printf "%08X" "$_version")" "$_date")"
- sqlite3 "$mcedb_tmp" "$_sqlstm"
- done
- _intel_timestamp=$(stat -c %Y "$intel_tmp/Intel-Linux-Processor-Microcode-Data-Files-main/license" 2>/dev/null)
- if [ -n "$_intel_timestamp" ]; then
- # use this date, it matches the last commit date
- _intel_latest_date=$(date +%Y%m%d -d @"$_intel_timestamp")
- else
- echo "Falling back to the latest microcode date"
- _intel_latest_date=$(sqlite3 "$mcedb_tmp" "SELECT \"yyyymmdd\" FROM \"Intel\" WHERE \"origin\"='intel' ORDER BY \"yyyymmdd\" DESC LIMIT 1;")
- fi
- echo DONE "(version $_intel_latest_date)"
-
- # now parse the most recent linux-firmware amd-ucode README file
- _info_nol "Fetching latest amd-ucode README from linux-firmware project... "
- linuxfw_url="https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/tree/amd-ucode/README"
- linuxfw_tmp=$(mktemp -t smc-linuxfw-XXXXXX)
- if command -v wget >/dev/null 2>&1; then
- wget -q "$linuxfw_url" -O "$linuxfw_tmp"; ret=$?
- elif command -v curl >/dev/null 2>&1; then
- curl -sL "$linuxfw_url" -o "$linuxfw_tmp"; ret=$?
- elif command -v fetch >/dev/null 2>&1; then
- fetch -q "$linuxfw_url" -o "$linuxfw_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 linux-firmware README"
- return $ret
- fi
- echo DONE
-
- _info_nol "Parsing the README... "
- nbfound=0
- for line in $(grep -E 'Family=0x[0-9a-f]+ Model=0x[0-9a-f]+ Stepping=0x[0-9a-f]+: Patch=0x[0-9a-f]+' "$linuxfw_tmp" | tr " " ","); do
- _debug "Parsing line $line"
- _family=$( echo "$line" | grep -Eoi 'Family=0x[0-9a-f]+' | cut -d= -f2)
- _model=$( echo "$line" | grep -Eoi 'Model=0x[0-9a-f]+' | cut -d= -f2)
- _stepping=$(echo "$line" | grep -Eoi 'Stepping=0x[0-9a-f]+' | cut -d= -f2)
- _version=$( echo "$line" | grep -Eoi 'Patch=0x[0-9a-f]+' | cut -d= -f2)
- _version=$(printf "0x%08X" "$(( _version ))")
- _cpuid=$(fms2cpuid "$_family" "$_model" "$_stepping")
- _cpuid=$(printf "0x%08X" "$_cpuid")
- _date="20000101"
- _sqlstm="$(printf "INSERT INTO \"AMD\" (\"origin\",\"cpuid\",\"version\",\"yyyymmdd\") VALUES ('%s','%s','%s','%s');" "linux-firmware" "$(printf "%08X" "$_cpuid")" "$(printf "%08X" "$_version")" "$_date")"
- _debug "family $_family model $_model stepping $_stepping cpuid $_cpuid"
- _debug "$_sqlstm"
- sqlite3 "$mcedb_tmp" "$_sqlstm"
- nbfound=$((nbfound + 1))
- unset _family _model _stepping _version _cpuid _date _sqlstm
- done
- echo "found $nbfound microcodes"
- unset nbfound
-
- dbversion="$mcedb_revision+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";
- # ensure the official Intel DB always has precedence over mcedb, even if mcedb has seen a more recent fw
- sqlite3 "$mcedb_tmp" "DELETE FROM \"Intel\" WHERE \"origin\"!='intel' AND \"cpuid\" IN (SELECT \"cpuid\" FROM \"Intel\" WHERE \"origin\"='intel' GROUP BY \"cpuid\" ORDER BY \"cpuid\" ASC);"
- # we'll use the more recent fw for Intel and AMD
- 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 -t smc-builtin-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
@@ -1158,12 +944,15 @@ while [ -n "${1:-}" ]; do
# deprecated, kept for compatibility
opt_explain=0
shift
- elif [ "$1" = "--update-fwdb" ] || [ "$1" = "--update-mcedb" ]; then
- update_fwdb
- exit $?
- elif [ "$1" = "--update-builtin-fwdb" ] || [ "$1" = "--update-builtin-mcedb" ]; then
- update_fwdb builtin
- exit $?
+ elif [ "$1" = "--with-fwdb" ] || [ "$1" = "--with-mcedb" ]; then
+ opt_fwdb=$2
+ if [ -f "$opt_fwdb" ]; then
+ mcedb_cache=$2
+ else
+ echo "$0: error: --with-fwdb should be a file, got '$opt_fwdb'" >&2
+ exit 255
+ fi
+ shift 2
elif [ "$1" = "--dump-mock-data" ]; then
opt_mock=1
shift
@@ -2192,21 +1981,11 @@ is_xen_domU()
fi
}
-builtin_dbversion=$(awk '/^# %%% MCEDB / { print $4 }' "$0")
if [ -r "$mcedb_cache" ]; then
# we have a local cache file, but it might be older than the builtin version we have
local_dbversion=$( awk '/^# %%% MCEDB / { print $4 }' "$mcedb_cache")
- # sort -V sorts by version number
- older_dbversion=$(printf "%b\n%b" "$local_dbversion" "$builtin_dbversion" | sort -V | head -n1)
- if [ "$older_dbversion" = "$builtin_dbversion" ]; then
- mcedb_source="$mcedb_cache"
- mcedb_info="local firmwares DB $local_dbversion"
- fi
-fi
-# if mcedb_source is not set, either we don't have a local cached db, or it is older than the builtin db
-if [ -z "${mcedb_source:-}" ]; then
- mcedb_source="$0"
- mcedb_info="builtin firmwares DB $builtin_dbversion"
+ mcedb_source="$mcedb_cache"
+ mcedb_info="local firmwares DB $local_dbversion"
fi
read_mcedb()
{
@@ -2222,7 +2001,9 @@ is_latest_known_ucode()
return 2
fi
ucode_latest="latest microcode version for your CPU model is unknown"
- if is_intel; then
+ if [ -z "$mcedb_source" ]; then
+ return 2
+ elif is_intel; then
cpu_brand_prefix=I
elif is_amd; then
cpu_brand_prefix=A
--
2.41.0
|