diff --git a/.gitignore b/.gitignore index 487117e..aaa1502 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/microcode_ctl-2.1-20180425.tar.xz +SOURCES/microcode_ctl-2.1-20180703.tar.xz diff --git a/.microcode_ctl.metadata b/.microcode_ctl.metadata index c9bd3e4..6888465 100644 --- a/.microcode_ctl.metadata +++ b/.microcode_ctl.metadata @@ -1 +1 @@ -6571a7941864bb7bc3feee13d4c2ca40cbb8b7cb SOURCES/microcode_ctl-2.1-20180425.tar.xz +60aeb4e9b797c74941815ca4d5877507caee043c SOURCES/microcode_ctl-2.1-20180703.tar.xz diff --git a/SOURCES/06-4f-01_config b/SOURCES/06-4f-01_config new file mode 100644 index 0000000..c568ed5 --- /dev/null +++ b/SOURCES/06-4f-01_config @@ -0,0 +1,13 @@ +model GenuineIntel 06-4f-01 +path intel-ucode/06-4f-01 +kernel 4.17.0 +kernel 3.10.0-894 +kernel 3.10.0-862.6.1 +kernel 3.10.0-693.35.1 +kernel 3.10.0-514.52.1 +kernel 3.10.0-327.70.1 +kernel 2.6.32-754.1.1 +kernel 2.6.32-573.58.1 +kernel 2.6.32-504.71.1 +kernel 2.6.32-431.90.1 +kernel 2.6.32-358.90.1 diff --git a/SOURCES/06-4f-01_readme b/SOURCES/06-4f-01_readme new file mode 100644 index 0000000..afb4d2d --- /dev/null +++ b/SOURCES/06-4f-01_readme @@ -0,0 +1,19 @@ +The microcode for Broadwell-EP/EX (BDX-ML B/M/R0, family 6, model 79, +stepping 1) processors requires a kernel with special commits present, +otherwise it might result in unexpected system behaviour. In order +to handle this, /usr/libexec/microcode_ctl/update_ucode script creates +necessary symlinks to make it available on kernels with the aforementioned +patches present. + +If you want to avoid adding this ucode for a specific kernel, please create +a disallow-06-4f-01 file inside /lib/firmware/ directory: + + touch /lib/firmware/3.10.0-862.9.1/disallow-06-4f-01 + +If you want to skip processing of this firmware for all kernels, please create +a disallow-06-4f-01 file inside /etc/microcode_ctl/ucode_with_caveats directory: + + touch /etc/microcode_ctl/ucode_with_caveats/disallow-06-4f-01 + +If you want avoid removal of the ucode file during cleanup, please remove the +corresponding readme file. diff --git a/SOURCES/check_caveats b/SOURCES/check_caveats new file mode 100755 index 0000000..04975c2 --- /dev/null +++ b/SOURCES/check_caveats @@ -0,0 +1,251 @@ +#! /bin/bash -eu + +# Script for checking various microcode caveats +# +# +# SPDX-License-Identifier: CC0-1.0 + +: ${MC_CAVEATS_DATA_DIR=/usr/share/microcode_ctl/ucode_with_caveats} + +usage() { + echo 'Usage: check_caveats [-k TARGET_KVER] [-c CONFIG] [-m] [-v]' + echo + echo ' -k - target version to check against, $(uname -r) is used' + echo ' otherwise' + echo ' -c - caveat config(s) to check, all configs are checked' + echo ' otherwise' + echo ' -m - check that caveats actually apply to the current model' + echo ' -v - verbose output' + echo + echo 'Environment:' + echo ' MC_CAVEATS_DATA_DIR - directory that contains caveats' + echo ' configuration data' +} + +debug() { [ 0 = "$verbose" ] || echo "$*" >&2; } + +# A simplified RPM version comparison that takes into account knowledge about +# Y- and Z-streams (so it compares versions inside Y-stram or Z-stream if +# the version against which comparison is performed has appropriate versioning +# scheme). +# +# $1 - kernel version to check +# $* - list of kernel versions to check against +check_kver() +{ + local t_major= t_minor= t_patch= t_y= t_z1= t_z2= t_rest= + local m_major= m_minor= m_patch= m_y= m_z1= m_z2= m_rest= + local cmp_type= + + # IFS=.- read -r t_major t_minor t_patch t_y t_z1 t_z2 t_rest <<<"$1" + # "cannot create temp file for here-document: Read-only file system" + # that's why we can't have nice things. + t_major=${1%%[.-]*} + t_rest=${1#${t_major}} + t_rest=${t_rest#[.-]} + t_minor=${t_rest%%[.-]*} + t_rest=${t_rest#${t_minor}} + t_rest=${t_rest#[.-]} + t_patch=${t_rest%%[.-]*} + t_rest=${t_rest#${t_patch}} + t_rest=${t_rest#[.-]} + t_y=${t_rest%%[.-]*} + t_rest=${t_rest#${t_y}} + t_rest=${t_rest#[.-]} + t_z1=${t_rest%%[.-]*} + t_rest=${t_rest#${t_z1}} + t_rest=${t_rest#[.-]} + t_z2=${t_rest%%[.-]*} + + # minor/major/patch/y should be numeric + [ -n "${t_major##*[!0-9]*}" ] || return 1 + [ -n "${t_minor##*[!0-9]*}" ] || return 1 + [ -n "${t_patch##*[!0-9]*}" ] || return 1 + [ -n "${t_y##*[!0-9]*}" ] || return 1 + # reset z1/z2 to zero if non-numeric + [ -n "${t_z1##*[!0-9]*}" ] || t_z1=0 + [ -n "${t_z2##*[!0-9]*}" ] || t_z2=0 + + while [ 1 -lt "$#" ]; do + cmp_type=upstream + + shift + m_major=${1%%[.-]*} + m_rest=${1#${m_major}} + m_rest=${m_rest#[.-]} + m_minor=${m_rest%%[.-]*} + m_rest=${m_rest#${m_minor}} + m_rest=${m_rest#[.-]} + m_patch=${m_rest%%[.-]*} + m_rest=${m_rest#${m_patch}} + m_rest=${m_rest#[.-]} + m_y=${m_rest%%[.-]*} + m_rest=${m_rest#${m_y}} + m_rest=${m_rest#[.-]} + m_z1=${m_rest%%[.-]*} + m_rest=${m_rest#${m_z1}} + m_rest=${m_rest#[.-]} + m_z2=${m_rest%%[.-]*} + + # minor/major/patch should be numeric + [ -n "${m_major##*[!0-9]*}" ] || continue + [ -n "${m_minor##*[!0-9]*}" ] || continue + [ -n "${m_patch##*[!0-9]*}" ] || continue + # reset z1/z2 to zero if non-numeric + [ -n "${m_y##*[!0-9]*}" ] && cmp_type=y || m_y=0 + [ -n "${m_z1##*[!0-9]*}" ] && cmp_type=z || m_z1=0 + [ -n "${m_z2##*[!0-9]*}" ] && cmp_type=z || m_z2=0 + + # Comparing versions + case "$cmp_type" in + upstream) + [ "$t_major" -ge "$m_major" ] || continue + [ "$t_minor" -ge "$m_minor" ] || continue + [ "$t_patch" -ge "$m_patch" ] || continue + return 0 + ;; + y) + [ "$t_major" -eq "$m_major" ] || continue + [ "$t_minor" -eq "$m_minor" ] || continue + [ "$t_patch" -eq "$m_patch" ] || continue + [ "$t_y" -ge "$m_y" ] || continue + return 0 + ;; + z) + [ "$t_major" -eq "$m_major" ] || continue + [ "$t_minor" -eq "$m_minor" ] || continue + [ "$t_patch" -eq "$m_patch" ] || continue + [ "$t_y" -eq "$m_y" ] || continue + [ "$t_z1" -ge "$m_z1" ] || continue + [ "$t_z2" -ge "$m_z2" ] || continue + return 0 + ;; + esac + done + + return 1 +} + +# Provides model in format "VENDOR_ID FAMILY-MODEL-STEPPING" +# +# We check only the first processor as we don't expect non-symmetrical setups +# with CPUs with caveats +get_model_string() +{ + /usr/bin/printf "%s %02x-%02x-%02x" \ + $(/bin/sed -rn '1,/^$/{ + s/^vendor_id[[:space:]]*: (.*)$/\1/p; + s/^cpu family[[:space:]]*: (.*)$/\1/p; + s/^model[[:space:]]*: (.*)$/\1/p; + s/^stepping[[:space:]]*: (.*)$/\1/p; + }' /proc/cpuinfo) +} + +get_model_name() +{ + /bin/sed -rn '1,/^$/s/^model name[[:space:]]*: (.*)$/\1/p' /proc/cpuinfo +} + +#check_kver "$@" +#get_model_name + +match_model=0 +configs= +kver=$(/bin/uname -r) +verbose=0 + +while getopts "k:c:mv" opt; do + case "${opt}" in + k) + kver="$OPTARG" + ;; + c) + configs="$configs $OPTARG" + ;; + m) + match_model=1 + ;; + v) + verbose=1 + ;; + *) + usage + exit 1; + ;; + esac +done + +: ${configs:=$(find "${MC_CAVEATS_DATA_DIR}" -maxdepth 1 -mindepth 1 -type d -printf "%f\n")} + +cpu_model=$(get_model_string) +cpu_model_name=$(get_model_name) + +for cfg in $(echo "${configs}"); do + dir="$MC_CAVEATS_DATA_DIR/$cfg" + [ -r "${dir}/config" ] || { + debug "File 'config' in ${dir} is not found, skipping" + continue + } + + cfg_model= + cfg_path= + cfg_kvers= + cfg_blacklist= + + while read -r key value; do + case "$key" in + model) + cfg_model="$value" + ;; + path) + cfg_path="$cfg_path $value" + ;; + kernel) + cfg_kvers="$cfg_kvers $value" + ;; + blacklist) + cfg_blacklist=1 + break + ;; + esac + done < "${dir}/config" + + [ -z "${cfg_blacklist}" ] || \ + cfg_blacklist=$(/bin/sed -n '/^blacklist$/,$p' "${dir}/config" | + /usr/bin/tail -n +2) + + debug "${cfg}: model '$cfg_model', path '$cfg_path', kvers '$cfg_kvers'" + debug "${cfg}: blacklist '$cfg_blacklist'" + + if [ -n "$cfg_model" ]; then + [ 0 -eq "$match_model" ] || { + [ "x$cpu_model" = "x$cfg_model" ] || { + debug "Current CPU model '$cpu_model' doesn't" \ + "match config CPU model '$cfg_model'," \ + "skipping" + continue + } + } + fi + + if [ -n "$cfg_kvers" ]; then + check_kver "$kver" $cfg_kvers || { + debug "${cfg}: kernel version check for '$kver'" \ + "against '$cfg_kvers' failed" + exit 1 + } + fi + + if [ -n "$cfg_blacklist" ]; then + echo "$cfg_blacklist" | /bin/grep -vqFx "${cpu_model_name}" || { + debug "${cfg}: model '${cpu_model_name}' is blacklisted" + exit 1 + } + fi + + #printf "%s " "$cfg" + #[ 0 -eq "$match_model" ] || printf "%s " "$cpu_model" + echo $cfg_path +done + +exit 0 diff --git a/SOURCES/dracut_99microcode_ctl-fw_dir_override_module_init.sh b/SOURCES/dracut_99microcode_ctl-fw_dir_override_module_init.sh new file mode 100755 index 0000000..200548c --- /dev/null +++ b/SOURCES/dracut_99microcode_ctl-fw_dir_override_module_init.sh @@ -0,0 +1,79 @@ +#!/bin/bash + +# Hack in kernel-specific firmware directory so it can be processed along with +# the dracut default ones. Note that upstream dracut currently has defaults +# that include kernel-version-specific directories (dracut commit +# 041-100-gb52cfbea). +# +# SPDX-License-Identifier: CC0-1.0 + +check() { + return 0 +} + +DATA_DIR=/usr/share/microcode_ctl/ucode_with_caveats +check_caveats=/usr/libexec/microcode_ctl/check_caveats + +install() { + verbose_opt= + [ 4 -gt "$stdloglvl" ] || verbose_opt="-v" + + # HACK: we override external fw_dir variable in order to get + # an additional ucode based on the kernel version. + dinfo " microcode_ctl module: hacking fw_dir" + + [ -z "$fw_dir_l" ] || { + dinfo " microcode_ctl module: avoid touching fw_dir as" \ + "it has been changed (fw_dir_l is '$fw_dir_l')" + + return 0 + } + + ucode=$(get_ucode_file) + + for i in $(ls "$DATA_DIR"); do + dinfo " microcode_ctl: processing data directory " \ + "\"$DATA_DIR/$i\"..." + [ -e "$DATA_DIR/$i/readme" ] || { + dinfo " microcode_ctl: skipping \"$i\": no readme" + continue + } + [ -e "$DATA_DIR/$i/config" ] || { + dinfo " microcode_ctl: skipping \"$i\": no config" + continue + } + [ ! -e "/etc/microcode_ctl/ucode_with_caveats/disallow-$i" ] || { + dinfo " microcode_ctl: skipping \"$i\":" \ + "\"/etc/microcode_ctl/ucode_with_caveats/disallow-$i\"" \ + "present" + continue + } + path=$($check_caveats -k "$kernel" -c "$i") + fname=$(basename "$path") + + if [ "x" != "x$hostonly" ]; then + [ "x$ucode" = "x$fname" ] || { + dinfo " microcode_ctl: Host-Only mode" \ + "is enabled and ucode name does not" \ + "match the expected one" \ + "(\"$ucode\" != \"$fname\")" + continue + } + fi + + dinfo " microcode_ctl: processing file \"$path\"" + if $check_caveats -k "$kernel" -c "$i" $verbose_opt > /dev/null + then + dinfo " microcode_ctl: caveats check for kernel" \ + "version \"$kernel\" passed, adding" \ + "\"/lib/firmware/$kernel\" to fw_dir variable" + fw_dir="/lib/firmware/$kernel $fw_dir" + break + else + dinfo " microcode_ctl: kernel version \"$kernel\"" \ + "failed caveats check, skipping" + continue + fi + done +} + diff --git a/SOURCES/microcode.service b/SOURCES/microcode.service index 09f542d..a96138f 100644 --- a/SOURCES/microcode.service +++ b/SOURCES/microcode.service @@ -7,6 +7,6 @@ ConditionPathExists=/sys/devices/system/cpu/microcode/reload [Service] Type=oneshot RemainAfterExit=no -ExecStart=/usr/bin/bash -c 'grep -l GenuineIntel /proc/cpuinfo | xargs grep -l -E "model[[:space:]]*: 79$" > /dev/null || echo 1 > /sys/devices/system/cpu/microcode/reload' +ExecStart=/usr/libexec/microcode_ctl/reload_microcode [Install] WantedBy=basic.target diff --git a/SOURCES/reload_microcode b/SOURCES/reload_microcode new file mode 100644 index 0000000..62fb43e --- /dev/null +++ b/SOURCES/reload_microcode @@ -0,0 +1,13 @@ +#! /bin/bash -efu + +# Trigger microcode reload with additional check for BDW-EP that can have +# microcode reloaded only in case kernel has specific patches. +# +# SPDX-License-Identifier: CC0-1.0 + +CHECK_CAVEATS=/usr/libexec/microcode_ctl/check_caveats +trigger=1 + +"$CHECK_CAVEATS" -m > /dev/null || trigger=0 + +[ 0 -eq "$trigger" ] || echo 2>/dev/null 1 > /sys/devices/system/cpu/microcode/reload || true diff --git a/SOURCES/update_ucode b/SOURCES/update_ucode new file mode 100644 index 0000000..df8033f --- /dev/null +++ b/SOURCES/update_ucode @@ -0,0 +1,256 @@ +#! /bin/bash -eu + +# Maintain kernel-version-specific symlinks in /lib/firmware based on +# configuration present in /usr/share/microcode_ctl/ucode_with_caveats. +# +# SPDX-License-Identifier: CC0-1.0 + +usage() +{ + echo "Usage: update_ucode [--action {add|remove|refresh}]" \ + "[--kernel KERNELVER]* [--verbose] [--dry-run]" \ + "[--trigger-dracut] [--cleanup intel_ucode caveats_ucode]" >&2 +} + +debug() { [ 0 = "$verbose" ] || echo "$*" >&2; } + +MC_DIR=/usr/share/microcode_ctl +INTEL_UCODE_DIR=intel-ucode +DATA_DIR=/usr/share/microcode_ctl/ucode_with_caveats +FW_DIR=/lib/firmware +check_caveats=/usr/libexec/microcode_ctl/check_caveats + +action=refresh +kernel= +verbose=0 +verbose_opt= +dry_run=0 +trigger_dracut=0 +remove_cleanup=0 +cleanup_intel= +cleanup_caveats= + +while [ 1 -le "$#" ]; do + case "$1" in + -a|--action) + shift + action="$1" + ;; + -k|--kernel) + shift + kernel="$kernel $1" + ;; + -v|--verbose) + verbose=1 + verbose_opt="-v" + ;; + -n|--dry-run) + dry_run=1 + ;; + -d|--trigger-dracut) + trigger_dracut=1 + ;; + -c|--cleanup) + remove_cleanup=1 + shift + cleanup_intel="$1" + shift + cleanup_caveats="$1" + ;; + *) + echo "Unknown argument \"$1\"" >&2 + usage + exit 1 + esac + shift +done + +cmd= +[ 0 -eq "$dry_run" ] || cmd=echo + +case "$action" in +add|remove|refresh) + # Scan all directories in FW_DIR and all existing kernels + if [ -z "$kernel" ]; then + debug "No kernel versions provided, scanning..." + + kvers=$(find /lib/modules/ -name '[2-9].*' -print) + for k_dir in $kvers; do + k="${k_dir#/lib/modules/}" + [ ! -e "/boot/symvers-$k.gz" ] || { + debug " Adding $k (from /lib/modules)" + kernel="$kernel $k" + } + done + + kvers=$(find /lib/firmware/ -name '[2-9].*' -print) + for k_dir in $kvers; do + k="${k_dir#/lib/firmware/}" + [ ! -d "$k_dir" ] || { + debug " Adding $k (from /lib/firmware)" + kernel="$kernel $k" + } + done + fi + ;; +*) + echo "Unknown action \"$action\"" >&2 + usage + exit 1 + ;; +esac + +# Generic part: managing intel ucode +debug "Running action \"$action\" on common Intel microcode directory" +while :; do + [ ! -e "/etc/microcode_ctl/intel-ucode-disallow" ] || { + debug " Skipping \"$i\":" \ + "\"/etc/microcode_ctl/intel-ucode-disallow\"" \ + "present" + break + } + [ ! -e "$FW_DIR/intel-ucode-disallow" ] || { + debug " Found \"$FW_DIR/intel-ucode-disallow\"," \ + "skipping" + break + } + + # Removing old files + case "$action" in + refresh|remove) + debug " Removing old files from ${MC_DIR}/${INTEL_UCODE_DIR}" + if [ 0 = "$remove_cleanup" ]; then + find "${MC_DIR}/${INTEL_UCODE_DIR}" \ + -maxdepth 1 -mindepth 1 \ + -type f -printf '%f\n' + else + cat "$cleanup_intel" + fi | while read -r fname; do + name="${FW_DIR}/${INTEL_UCODE_DIR}/${fname}" + + # Needed in case we downgrade to a version where + # no symlinks in /lib/firmware were used + if [ 1 = "$remove_cleanup" ]; then + [ -L "$name" ] || continue + fi + + $cmd rm -f $verbose_opt "$name" + done + $cmd rmdir -p $verbose_opt "${FW_DIR}/${INTEL_UCODE_DIR}" 2>/dev/null || true + ;; + esac + + # Adding new ones + case "$action" in + add|refresh) + if grep -q '^flags[[:space:]]*:.*hypervisor' /proc/cpuinfo; then + debug " A virtualised environment has been detected" \ + "(hypervisor flag is present in /proc/cpuinfo)," \ + "skipping" + break + fi + + debug " Creating symlinks in ${MC_DIR}/${INTEL_UCODE_DIR}" + $cmd mkdir -p $verbose_opt "${FW_DIR}/${INTEL_UCODE_DIR}" + $cmd find "${MC_DIR}/${INTEL_UCODE_DIR}" -maxdepth 1 -mindepth 1 \ + -type f -exec bash -c 'ln -s '"$verbose_opt"' '\''{}'\'' \ + "'"${FW_DIR}/${INTEL_UCODE_DIR}/"'$(basename '\''{}'\'')"' \; + ;; + esac + + break +done + +debug "Running action \"$action\" on kernels $kernel" + +if [ 0 = "$remove_cleanup" ]; then + ls "$DATA_DIR" +else + cat "$cleanup_caveats" +fi | while read -r i; do + debug "Processing data directory \"$i\"..." + [ -e "$DATA_DIR/$i/readme" ] || { + debug " Skipping \"$i\": no readme" + continue + } + [ -e "$DATA_DIR/$i/config" ] || { + debug " Skipping \"$i\": no config" + continue + } + [ ! -e "/etc/microcode_ctl/ucode_with_caveats/disallow-$i" ] || { + debug " Skipping \"$i\":" \ + "\"/etc/microcode_ctl/ucode_with_caveats/disallow-$i\"" \ + "present" + continue + } + + for k in $(echo "$kernel"); do + debug " Processing kernel version \"$k\"" + $check_caveats -k "$k" -c "$i" $verbose_opt > /dev/null || { + debug " Checking for caveats failed" \ + "(kernel version \"$k\"), skipping" + continue + } + path=$($check_caveats -k "$k" -c "$i") + + case "$action" in + remove|refresh) + debug " Removing $path (part of $action)..." + + if [ -e "$FW_DIR/$k/readme-$i" ]; then + debug " Removing \"$FW_DIR/$k/$path\"" + $cmd rm -f $verbose_opt "$FW_DIR/$k/$path" + $cmd rm -f $verbose_opt "$FW_DIR/$k/readme-$i" + $cmd rmdir -p $verbose_opt "$(dirname "$FW_DIR/$k/$path")" 2>/dev/null || true + + [ 0 -eq "$trigger_dracut" ] || { + debug " Triggering dracut for kernel \"$k\"" + $cmd dracut -f $verbose_opt --kver "$k" + } + else + debug " \"$FW_DIR/$k/readme-$i\" is not found," \ + "skipping \"$FW_DIR/$k/$path\" removal" + fi + ;; + esac + + case "$action" in + add|refresh) + debug " Adding $path (part of $action)..." + + [ -e "/boot/symvers-$k.gz" ] || { + debug " \"/boot/symvers-$k.gz\"" \ + "does not exist, skipping" + continue + } + if grep -q '^flags[[:space:]]*:.*hypervisor' /proc/cpuinfo; then + debug " A virtualised environment has been detected" \ + "(hypervisor flag is present in /proc/cpuinfo)," \ + "skipping" + break + fi + [ ! -e "$FW_DIR/$k/disallow-$i" ] || { + debug " Found \"$FW_DIR/$k/disallow-$i\"," \ + "skipping" + continue + } + [ ! -e "$FW_DIR/$k/$path" ] || { + debug " \"$FW_DIR/$k/$path\" already exists," \ + "skipping" + continue + } + + debug " Adding \"$FW_DIR/$k/$path\"" + $cmd mkdir -p "$(dirname "$FW_DIR/$k/$path")" + $cmd ln -s "$DATA_DIR/$i/$path" "$FW_DIR/$k/$path" + $cmd cp "$DATA_DIR/$i/readme" "$FW_DIR/$k/readme-$i" + + [ 0 -eq "$trigger_dracut" ] || { + debug " Triggering dracut for kernel \"$k\"" + $cmd dracut -f $verbose_opt --kver "$k" + } + ;; + remove) + esac + done +done diff --git a/SPECS/microcode_ctl.spec b/SPECS/microcode_ctl.spec index fbdeb12..102109d 100644 --- a/SPECS/microcode_ctl.spec +++ b/SPECS/microcode_ctl.spec @@ -1,17 +1,28 @@ -%define upstream_version 2.1-20180425 +%define upstream_version 2.1-20180703 +%define microcode_ctl_libexec /usr/libexec/microcode_ctl +%define update_ucode %{microcode_ctl_libexec}/update_ucode +%define check_caveats %{microcode_ctl_libexec}/check_caveats +%define reload_microcode %{microcode_ctl_libexec}/reload_microcode Summary: Tool to transform and deploy CPU microcode update for x86. Name: microcode_ctl Version: 2.1 -Release: 29.2%{?dist} +Release: 29.10%{?dist} Epoch: 2 Group: System Environment/Base License: GPLv2+ and Redistributable, no modification permitted URL: https://pagure.io/microcode_ctl -Source0: https://releases.pagure.org/microcode_ctl/%{name}-%{upstream_version}.tar.xz +Source0: %{name}-%{upstream_version}.tar.xz Source1: microcode.service Source2: 01-microcode.conf Source3: disclaimer +Source4: update_ucode +Source5: check_caveats +Source6: reload_microcode +Source7: dracut_99microcode_ctl-fw_dir_override_module_init.sh +Source8: 06-4f-01_readme +Source9: 06-4f-01_config + Buildroot: %{_tmppath}/%{name}-%{version}-root ExclusiveArch: %{ix86} x86_64 BuildRequires: systemd-units @@ -34,9 +45,11 @@ back to the old microcode. %build make CFLAGS="$RPM_OPT_FLAGS" %{?_smp_mflags} +find intel-ucode -type f | sed 's/^/%%ghost \/lib\/firmware\//' > ghost_list + %install rm -rf %{buildroot} -make DESTDIR=%{buildroot} PREFIX=%{_prefix} INSDIR=/usr/sbin install clean +make DESTDIR=%{buildroot} PREFIX=%{_prefix} INSDIR=/usr/sbin MICDIR=/usr/share/microcode_ctl install clean mkdir -p %{buildroot}/usr/lib/dracut/dracut.conf.d mkdir -p %{buildroot}%{_unitdir} @@ -44,16 +57,32 @@ install -m 644 %{SOURCE1} %{buildroot}%{_unitdir} install -m 644 %{SOURCE2} %{buildroot}/usr/lib/dracut/dracut.conf.d install -m 644 %{SOURCE3} %{buildroot}/usr/share/doc/microcode_ctl/disclaimer +mkdir -p %{buildroot}/%{microcode_ctl_libexec} +install -m 755 %{SOURCE4} %{buildroot}/%{update_ucode} +install -m 755 %{SOURCE5} %{buildroot}/%{check_caveats} +install -m 755 %{SOURCE6} %{buildroot}/%{reload_microcode} + +mkdir -p "%{buildroot}/usr/lib/dracut/modules.d/99microcode_ctl-fw_dir_override" +install -m 755 %{SOURCE7} %{buildroot}/usr/lib/dracut/modules.d/99microcode_ctl-fw_dir_override/module-setup.sh + +mkdir -p "%{buildroot}/usr/share/microcode_ctl/ucode_with_caveats/intel-06-4f-01/intel-ucode" +install -m 644 intel-ucode-with-caveats/06-4f-01 %{buildroot}/usr/share/microcode_ctl/ucode_with_caveats/intel-06-4f-01/intel-ucode/06-4f-01 +install -m 644 %{SOURCE8} %{buildroot}/usr/share/microcode_ctl/ucode_with_caveats/intel-06-4f-01/readme +install -m 644 %{SOURCE9} %{buildroot}/usr/share/microcode_ctl/ucode_with_caveats/intel-06-4f-01/config + +rm -f intel-ucode-with-caveats/06-4f-01 +rmdir intel-ucode-with-caveats + %post %systemd_post microcode.service +%{update_ucode} # "reload" file is not presented on a certain virtualized hw if [ -w /sys/devices/system/cpu/microcode/reload ] ; then - grep -l GenuineIntel /proc/cpuinfo | xargs grep -l -E "model[[:space:]]*: 79$" > /dev/null || \ - echo 1 > /sys/devices/system/cpu/microcode/reload + %{reload_microcode} fi # send the message to syslog, so it gets recorded on /var/log if [ -e /usr/bin/logger ]; then - /usr/bin/logger -p syslog.notice -t DISCLAIMER -f /usr/share/doc/microcode_ctl/disclaimer + /usr/bin/logger -p syslog.notice -t DISCLAIMER -f /usr/share/doc/microcode_ctl/disclaimer fi # also paste it over dmesg (some customers drop dmesg messages while # others keep them into /var/log for the later case, we'll have the @@ -73,21 +102,97 @@ fi %preun %systemd_preun microcode.service +# Storing ucode list before uninstall +ls /usr/share/microcode_ctl/intel-ucode | + sort > "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode" +ls /usr/share/microcode_ctl/ucode_with_caveats | + sort > "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats" + %postun %systemd_postun microcode.service +ls /usr/share/microcode_ctl/intel-ucode 2> /dev/null | + sort > "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode_after" +ls /usr/share/microcode_ctl/ucode_with_caveats 2> /dev/null | + sort > "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats_after" + +comm -23 \ + "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode" \ + "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode_after" \ + > "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode_diff" + +comm -23 \ + "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats" \ + "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats_after" \ + > "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats_diff" + +if [ -e "%{update_ucode}" ]; then + %{update_ucode} --action remove --cleanup \ + "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode_diff" \ + "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats_diff" || exit 0 +else + while read f; do + [ -L "/lib/firmware/intel-ucode/$f" ] || continue + rm -f "/lib/firmware/intel-ucode/$f" + done < "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode_diff" +fi + +rm -f "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode" +rm -f "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats" + +rm -f "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode_after" +rm -f "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats_after" + +rm -f "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode_diff" +rm -f "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats_diff" + +%triggerin -- kernel +%{update_ucode} + +%triggerpostun -- kernel +%{update_ucode} + + %clean rm -rf %{buildroot} -%files +%files -f ghost_list +%ghost %attr(0100755, root, root) /lib/firmware/intel-ucode/ /usr/sbin/intel-microcode2ucode -/lib/firmware/* +%{microcode_ctl_libexec} +/usr/share/microcode_ctl +/usr/lib/dracut/modules.d/99microcode_ctl-fw_dir_override %config(noreplace) /usr/lib/dracut/dracut.conf.d/01-microcode.conf %{_unitdir}/microcode.service %doc /usr/share/doc/microcode_ctl/* %changelog +* Fri Jul 27 2018 Eugene Syromiatnikov - 2:2.1-29.10 +- Provide %attr for the ghosted /lib/firmware. + +* Thu Jul 26 2018 Eugene Syromiatnikov - 2:2.1-29.9 +- Remove model name blacklists from caveats configuration files. + +* Tue Jul 24 2018 Eugene Syromiatnikov - 2.1-29.8 +- Add model name blacklist infrastructure. +- Store Intel ucode files in /usr/share/microcode_ctl; do not populate them + in a virtualised environment. +- Resolves: #1576334 + +* Tue Jul 17 2018 Eugene Syromiatnikov - 2.1-29.7 +- Add infrastructure for handling kernel-version-dependant microcode. +- Resolves: #1576334 + +* Mon Jul 16 2018 Eugene Syromiatnikov - 2.1-29.4 +- Intel CPU microcode update to 20180703. +- Resolves: #1573456 + +* Wed Jun 13 2018 Petr Oros - 2.1-29.3 +- Fix: Operation not permitted when installing microcode_ctl +- CVE-2018-3639 hw: cpu: speculative store bypass +- Resolves: #1573456 + * Tue May 15 2018 Petr Oros - 2.1-29.2 - Update disclaimer text - Resolves: #1575570