diff --git a/.gitignore b/.gitignore index aaa1502..2c9515a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -SOURCES/microcode_ctl-2.1-20180703.tar.xz +SOURCES/microcode-20180807a.tgz +SOURCES/microcode_ctl-2.1-14.tar.xz diff --git a/.microcode_ctl.metadata b/.microcode_ctl.metadata index 6888465..131e43b 100644 --- a/.microcode_ctl.metadata +++ b/.microcode_ctl.metadata @@ -1 +1,2 @@ -60aeb4e9b797c74941815ca4d5877507caee043c SOURCES/microcode_ctl-2.1-20180703.tar.xz +20001bc89a46a40015d12f329910e4eb263d4e82 SOURCES/microcode-20180807a.tgz +e2508bc2b2b359fb45be6fd5595612cffaca8024 SOURCES/microcode_ctl-2.1-14.tar.xz diff --git a/SOURCES/06-4f-01_config b/SOURCES/06-4f-01_config index c568ed5..f589fbf 100644 --- a/SOURCES/06-4f-01_config +++ b/SOURCES/06-4f-01_config @@ -11,3 +11,11 @@ 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 +kernel_early 4.10.0 +kernel_early 3.10.0-930 +kernel_early 3.10.0-862.14.1 +kernel_early 3.10.0-693.38.1 +kernel_early 3.10.0-514.57.1 +kernel_early 3.10.0-327.73.1 +mc_min_ver_late 0xb000019 +disable early late diff --git a/SOURCES/06-4f-01_readme b/SOURCES/06-4f-01_readme index afb4d2d..1eaa758 100644 --- a/SOURCES/06-4f-01_readme +++ b/SOURCES/06-4f-01_readme @@ -1,19 +1,52 @@ -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, +The microcode for Intel Broadwell-EP/EX (BDX-ML B/M/R0, family 6, model 79, +stepping 1) processors requires a kernel with specific 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. +necessary symlinks to make it available only on kernels with the aforementioned +patches present. The required patches are present in the following versions +of the kernel package: + RHEL 7.6: kernel-3.10.0-894 or newer; + RHEL 7.5.z: kernel-3.10.0-862.6.1 or newer; + RHEL 7.4.z: kernel-3.10.0-693.35.1 or newer; + RHEL 7.3.z: kernel-3.10.0-514.52.1 or newer; + RHEL 7.2.z: kernel-3.10.0-327.70.1 or newer. -If you want to avoid adding this ucode for a specific kernel, please create -a disallow-06-4f-01 file inside /lib/firmware/ directory: +Please use the version of the kernel with the aforementioned patches when +running on Intel Broadwell EP/EX processors in order to have the microcode +updated. - touch /lib/firmware/3.10.0-862.9.1/disallow-06-4f-01 +If you want to avoid late loading of this ucode for a specific kernel, please +create "disallow-late-06-4f-01" file inside /lib/firmware/ +directory and run /usr/libexec/microcode_ctl/update_ucode script: -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 /lib/firmware/3.10.0-862.9.1/disallow-late-06-4f-01 + /usr/libexec/microcode_ctl/update_ucode - touch /etc/microcode_ctl/ucode_with_caveats/disallow-06-4f-01 +If you want to avoid late loading of this microcode for all kernels, please +create "disallow-late-06-4f-01" file inside /etc/microcode_ctl/ucode_with +caveats directory and run /usr/libexec/microcode_ctl/update_ucode script: + + mkdir -p /etc/microcode_ctl/ucode_with_caveats + touch /etc/microcode_ctl/ucode_with_caveats/disallow-late-06-4f-01 + /usr/libexec/microcode_ctl/update_ucode + +If you want to enforce addition of this microcode to the firmware directory +for a specific kernel, please create "force-late-06-4f-01" file inside +/lib/firmware/ directory and run +dracut -f --kver "": + + touch /lib/firmware/3.10.0-862.9.1/force-early-06-4f-01 + dracut -f --kver 3.10.0-862.9.1 + +If you want to enforce addition of this microcode for all kernels, add a line +"06-4f-01" to the file /etc/microcode_ctl/force-early-microcode and run +dracut -f --regenerate-all: + + echo 06-4f-01 >> /etc/microcode_ctl/force-early-microcode + dracut -f --regenerate-all If you want avoid removal of the ucode file during cleanup, please remove the -corresponding readme file. +corresponding readme file (copy of this file in /lib/firmware/). + + +See /usr/share/doc/microcode_ctl/README.caveats for additional information. diff --git a/SOURCES/README.caveats b/SOURCES/README.caveats new file mode 100644 index 0000000..a3fea12 --- /dev/null +++ b/SOURCES/README.caveats @@ -0,0 +1,398 @@ +The microcode_ctl package shipped with RHEL contains provisions for the issues +with microcode loading on the old kernels. While those provisions are expected +to suit most users, several knobs are provided in order to provide ability +to override the default behaviour. + + +General behaviour +================= +In RHEL 7, there are currently two main handlers for microcode update: + * Early microcode update. It uses GenuineIntel.bin or AuthenticAMD.bin file + placed at the beginning of an initramfs image + (/boot/initramfs-KERNEL_VERSION.img) in order to update CPU microcode and + is performed very early during the boot process (if the relevant microcode + file is available). + * On-demand (late) microcode update. It can be triggered by writing "1" to + /sys/devices/system/cpu/microcode/reload file (provided my the "microcode" + module). It loads microcode from a file present in one of the following + directories: + /lib/firmware/updates/KERNEL_VERSION/ + /lib/firmware/updates/ + /lib/firmware/KERNEL_VERSION/ + /lib/firmware/ + (there is also an additional directory that can be configured via the + "fw_path_para" module option of the "firmware_class" module; as this module + is built-in in RHEL kernel, a boot parameter "firmware_class.fw_path_para" + should be used for that purpose; this is out of the document's scope, however) + +The firmware for Intel CPUs is searched in "intel-ucode" subdirectory, and for +AMD CPUs, a file under "amd-ucode" is searched. + +For Intel CPUs, the name of the specific microcode file the kernel tries to load +has the format "FF-MM-SS", where "FF" is the family number, "MM" is the model +number, and "SS" is the stepping. All those numbers are zero-filled to two digits +and are written in hexadecimal (letters are in the lower case). For AMD CPUs, +the file name has the format "microcode_amd_famFFh.bin", where "FF" is the +family number, written in hexadecimal, letters are in the lower case, not +zero-filled. + +The early microcode is placed into initramfs image by the "dracut" script, which +scans the aforementioned subdirectories of the configured list of firmware +directories (by default it consists of two directories in RHEL 7, +"/lib/firmware/updates" and "/lib/firmware"). + +In RHEL 7, AMD microcode is shipped as a part of the linux-firmware package, +and Intel microcode is shipped as a part of the microcode_ctl package. + +The microcode_ctl package currently includes the following: + * Intel microcode files, placed in /usr/share/microcode_ctl directory; + * A dracut configuration file, /usr/lib/dracut/dracut.conf.d/01-microcode.conf, + that enables inclusion of early microcode to the generated initramfs + in dracut; + * A dracut module, /usr/lib/dracut/modules.d/99microcode_ctl-fw_dir_override, + that controls which additional firmware directories will be added to dracut's + default configuration; + * A systemd service file, microcode.service, that triggers microcode reload + late during boot; + * A set of directories in /usr/share/microcode_ctl/ucode_with_caveats, that + contain configuration and related data for various caveats related + to microcode; + * A set of support scripts, placed in /usr/libexec/microcode_ctl: + * "check_caveats" is an utility script that performs checks of the target + kernel (and running CPU) in accordance with caveat configuration files + in ucode_with_caveats directory and reports whether it passes them or not; + * "reload_microcode" is a script that is called by microcode.service and + triggers microcode reloading (by writing "1" to + /sys/devices/system/cpu/microcode/reload) if the running kernel passes + check_caveats checks. + * "update_ucode" is a script that populates symlinks to microcode files + in /lib/firmware, so it can be picked up by relevant kernels for the late + microcode loading. + +Also, microcode_ctl RPM includes triggers that run update_ucode script on every +installation or removal of a kernel RPM in order to provide microcode files +for newly installed kernels and cleanup symlinks for the uninstalled ones. + + +Caveat configuration +-------------------- +There is a directory for each caveat under +/usr/share/microcode_ctl/ucode_with_caveats, containing the following files: + * "config", a configuration file for the caveat; + * "readme", that contains description of the caveat; + * set of related associated microcode files. + +"config" file is a set of lines each containing option name and its value, +separated by white space. Currently, the following options are supported: + * "model" option, which has format "VENDOR_ID FF-MM-SS", that specifies + to which CPU model the caveat is applicable (check_caveats ignores caveats + with non-matching models if "-m" option is passed to it). Can be set + in the configuration file only once (the last provided value is used). + * "vendor" option specifies CPUs of which vendor (as provided + in the /proc/cpuinfo file) the caveat is applicable to (check_caveats + ignores caveats with non-matching models when it is invoked with "-m" + option). Can be set in the configuration file only once. + * "path" is a glob pattern that specifies set of microcode files associated + with the caveat as a relative path to the caveat directory. This option + is used for populating files in /lib/firmware by update_ucode script and + for matching microcode file when dracut is run in host-only mode + (as in that case it uses only the first directory in firmware directory list + to look for the microcode file applicable to the host CPU). Can be set + in the configuration file multiple times. + * "kernel" is a minimal kernel version that supports proper handling + of the related microcode files during late microcode load. It may be + provided in one of the following formats that affect the way it is compared + to the running kernel version: + * A.B.C (where A, B, and C are decimal numbers), "upstream version". In this + case, simple version comparison against the respective part of the running + kernel version is used, and the running kernel version should be greater + or equal than the version provided in the configuration option in order + for comparison to succeed (that is, the first part, major version number, + of the running kernel version should be greater than the value provided + in the configuration option, or those should be equal and the second part, + minor version number, should be greater than the minor version number + of the kernel version provided in the configuration option, or the first + two parts should be equal and the third part, patch level, should + be greater or equal the patch level of the version in the configuration + option). + * A.B.C-Y (where A, B, C, and Y are decimal numbers), "Y-stream version". + In this case, A.B.C part should be equal, and Y part of the running kernel + version should be greater or equal than the Y part of the configuration + option version in order to satisfy the comparison requirement. + * A.B.C-Y.Z1.Z2 (where A, B, C, Y, Z1, and Z2 are decimal numbers), + "Z-stream version". In this case, A.B.C-Y part should be equal and Z1.Z2 + part of the running kernel should be greater or equal than the respective + part of the configuration option version (when compared as a version) + for comparison to succeed. + Kernel version check passed if at least one comparison of the running kernel + version against a kernel version provided in a configuration option + succeeded. The "kernel" configuration option can be provided + in the configuration file multiple times. + * "kernel_early" is a minimal kernel version that supports proper handling + of the related microcode during early microcode load. The format of the + option and its semantics is similar to the "kernel" configuration options. + This option can be provided multiple times as well. + * "mc_min_ver_late" is the minimal version of the currently loaded microcode + on the CPU (as reported in /proc/cpuinfo) that supports late microcode + update. Microcode update will be attempted only if the currently loaded + microcode version is greater or equal the microcode version provided + in the configuration option. Can be set in the configuration file only once. + * "disable" is a way to disable a specific caveat from inside its + configuration. Argument for the argument is a list of stages ("early", + "late") for which the caveat should be disable. The configuration option + can be provided multiple times in a configuration file. + * "blacklist" is a marker for a start of list of blacklisted model names, + one model name per line. The model name of the running CPU (as reported + in /proc/cpuinfo) is compared against the names in the provided list, and, + if there is a match, caveat check fails. + + +check_caveats script +-------------------- +"check_caveats" is an utility script (called by update_ucode, reload_microcode, +dracut module) that performs checks of the target kernel (and running CPU) +in accordance with caveat configuration files in directory +"/usr/share/microcode_ctl/ucode_with_caveats", and returns information, whether +the system passes the checks, or not. + +Usage: + check_caveats [-e] [-k TARGET_KVER] [-c CONFIG]* [-m] [-v]' + +Options: + -e - check for early microcode load possibility (instead of late microcode + load). "kernel_early" caveat configuration options are used for checking + instead of "kernel", and "mc_min_ver_late" is not checked. + -k - target kernel version to check against, $(uname -r) is used otherwise. + -c - caveat(s) to check, all caveat configurations found inside + $MC_CAVEATS_DATA_DIR are checked otherwise. + -m - ignore caveats that do not apply to the current CPU model. + -v - verbose output. + +Environment: + MC_CAVEATS_DATA_DIR - directory that contains caveats configurations + FW_DIR - directory containing firmware files (per-kernel configuration + overrides are checked there) + CFG_DIR - directory containing global caveats overrides. + +Output: + Script returns information about caveats check results. Output has a format + of "KEY VALUE1 VALUE2 ..." with KEY defining the semantics of the VALUEs. + Currently, the following data is issued: + - "cfgs" - list of caveats that have been processed (and not skipped + due to missing "config", "readme", or a disallow-* override described + below); + - "skip_cfgs" - list of caveats that have been skipped (due to missing + config/readme file, or because of overrides); + - "paths" - list of glob patterns matching files associated with caveats + that have been processed; + - "ok_cfgs" - list of caveat configurations that have all the checks passed + (or have enforced by one of force-* overrides described below); + - "ok_paths" - list of glob patterns associated with caveat files from + the "ok_cfgs" list; + - "fail_cfgs" - list of caveats that have one of the checks failed. + - "fail_paths" - list of glob patterns associated with caveats from the + "fail_cfgs" list. + +Return value: + - 0 in case caveats check has passed, 1 otherwise. + - In "-d" mode, 0 is always returned. + +Overrides: + +When check_caveats perform its checks, it also checks for presence of files +in specific places, and, if they exist, check_caveats skips a caveat or ignores +its checks; that mechanism allows overriding the information provided +in configuration on local systems and affect the behaviour of the microcode +update process. + +Current list of overrides (where $FW_DIR and $CFG_DIR are the environment +options described earlier; $kver - the currently processed kernel version, +$s is the requested stage ("early" or "late"), $cfg is the caveat directory +name): + $FW_DIR/$kver/disallow-$s-$cfg - skip a caveat for the requested stage for + a specific kernel version.. + $FW_DIR/$kver/force-$s-$cfg - apply a specific caveat file for a specific + kernel version for the requested stage without + performing any checks. + $FW_DIR/$kver/disallow-$cfg - skip a caveat for any stage for a specific + kernel version. + $FW_DIR/$kver/force-$cfg - apply a specific caveat for any stage + for a specific kernel version without checks. + $FW_DIR/$kver/disallow-$s - skip all caveats for a specific stage + for a specific kernel version. + $CFG_DIR/disallow-$s-$cfg - skip a caveat for a specific stage for all + kernel versions. + $FW_DIR/$kver/force-$s - apply all caveats for a specific stage + for a specific kernel version without checks. + $CFG_DIR/force-$s-$cfg - apply a specific caveat for a specific stage for + all kernel versions without checks. + $FW_DIR/$kver/disallow - skip all caveats for all stages for a specific + kernel version. + $CFG_DIR/disallow-$cfg - skip a caveat for all stages for all kernel + versions. + $FW_DIR/$kver/force - apply all caveats for all stages for a specific kernel + version without checks. + $CFG_DIR/force-$cfg - apply a caveat for all stages for all kernel versions + without checks. + $CFG_DIR/disallow-$s - skip all caveat for all kernel versions + for a specific stage. + $CFG_DIR/force-$s - apply all caveats for all kernel versions for specific + stage without checks. + $CFG_DIR/disallow - skip all caveats for all stages for all kernel versions + (disable everything). + $CFG_DIR/force - force all caveats for all stages for all kernel versions + (enable everything). + +The "apply" action above means creating symlinks in /lib/firmware by +update_ucode in case of the "late" stage and adding caveat directory to the list +of firmware directories by dracut plugin in case of the "early" stage. + +The files are checked for existence until the first match, so more specific +overrides can override more broad ones. + +Also, a caveat is ignored if it lacks either config or readme file. + + +update_ucode script +------------------- +"update_ucode" populates symlinks to microcode files in accordance with caveats +configuration. It enables late microcode loading that is invoked by triggering +/sys/devices/system/cpu/microcode/reload file. Since caveats depend +on the kernel version, symlinks are populated inside +"/lib/firmware/KERNEL_VERSION" directory for each installed kernel. +As a consequence, this script is triggered upon each kernel package installation +and removal. + +The script has two parts: common and kernel-version-specific. + +During the common part, files are populated from +/usr/share/microcode_ctl/intel-ucode in /lib/firmware/intel-ucode. There are +several possibilities to affect the process: + * Presence of "/etc/microcode_ctl/intel-ucode-disallow" file leads to skipping + the common part of the script. + * The same for "/lib/firmware/intel-ucode-disallow". + +During the kernel-version-specific part, each caveat is checked against every +kernel version, and those combinations, for which caveat check succeeds, +gets the symlinks to the associated microcode files populated. + * Absence of "/lib/firmware/KERNEL_VERSION/readme-CAVEAT" prevents update_ucode + from removing symlinks related to the caveat for specific kernel version. + * Since the check is being done by check_caveats, all the overrides that + described there also stay. + +Usage: + update_ucode [--action {add|remove|refresh|list}] [--kernel KERNELVER]* + [--verbose] [--dry-run] [--cleanup intel_ucode caveats_ucode] + [--skip-common] [--skip-kernel-specific] + +Options: + --action - action to perform. Currently, the following actions are supported: + * "add" - create new symlinks. + * "remove" - remove old symlinks that are no longer needed. + * "refresh" - re-populate symlinks. + * "list" - list files under control of update_ucode. + By default, "refresh" action is executed. + --kernel - kernel version to process. By default, list of kernel versions + is formed based on contents of /lib/firmware and /lib/modules + directories. + --verbose - verbose output. + --dry-run - do not call commands, just print the invocation lines. + --cleanup - cleanup mode. Used by post-uninstall script during package + upgrades. Removes excess files in accordance to the contents + of the files provided in the arguments to the option. + --skip-common - do not process /lib/firmware directory. + --skip-kernel-specific - do not process /lib/firmware/KERNEL_VERSION + directories. + +Return value: + 0 on success, 1 on error. + + +reload_microcode script +----------------------- +"reload_microcode" is a script that is called by microcode.service and +triggers late microcode reloading (by writing "1" to +/sys/devices/system/cpu/microcode/reload) if the running kernel passes +check_caveats checks that applicable to the current CPU model. + +The script checks /proc/cpuinfo for the presence of "hypervisor" flag +and avoids triggering microcode update if it is there. + +The script has no options and always returns 0. + +In addition to overrides that affect check_caveats, the presence of the +"/etc/microcode_ctl/ignore-hypervisor-flag" flag provides an ability +to skip "hypervisor" flag check. + + +99microcode_ctl-fw_dir_override dracut module +--------------------------------------------- +This dracut module injects directories with microcode files for caveats +that pass "early" check_caveats check (with "-e" flag). In addition +to check_caveats overrides, the following abilities to control module behaviour +are present: + * Presence of one of the following files: + - /etc/microcode_ctl/ucode_with_caveats/skip-host-only-check + - /etc/microcode_ctl/ucode_with_caveats/skip-host-only-check-$cfg + - /lib/firmware/$kver/skip-host-only-check + - /lib/firmware/$kver/skip-host-only-check-$cfg + (where "$kver" is the kernel version in question and "$cfg" is the caveat + directory name) allows skipping matching of microcode file name when dracut's + Host-Only mode is enabled. + +When caveats_check succeeds, caveats directory (and not +/lib/firmware/KERNEL_VERSION) is added to the list of firmware search +directories. It is done so in order to enable independent caveat enablement +for the initramfs image. + +The module can be disabled by running dracut with +"-o microcode_ctl-fw_dir_override" (for one-time exclusion) or by creating +a file *.conf inside /usr/lib/dracut/dracut.conf.d that contains +"omit_dracutmodules+=' microcode_ctl-fw_dir_override '" in order to disable +it permanently. See dracut(8), section "Omitting dracut Modules", and +dracut.conf(5), variable "omit_dracutmodules" for additional information. + + +Caveats +======= + +Intel Broadwell-EP/EX ("BDX-ML B/M/R0") caveat +---------------------------------------------- +The microcode for Intel Broadwell-EP/EX (BDX-ML B/M/R0, family 6, model 79, +stepping 1) processors requires a kernel with specific commits present, +otherwise it might result in unexpected system behaviour. + +Affected microcode: intel-ucode/06-4f-01. + +Mitigation: late microcode loading is disabled for the affected CPU model. + +Minimum versions of kernel RPM that contain the fix: + - RHEL 7.6: 3.10.0-894 + - RHEL 7.5: 3.10.0-862.6.1 + - RHEL 7.4: 3.10.0-693.35.1 + - RHEL 7.3: 3.10.0-514.52.1 + - RHEL 7.2: 3.10.0-327.70.1 + - RHEL 6.10: 2.6.32-754.1.1 + - RHEL 6.7: 2.6.32-573.58.1 + - RHEL 6.6: 2.6.32-504.71.1 + - RHEL 6.5: 2.6.32-431.90.1 + - RHEL 6.4: 2.6.32-358.90.1 + + +Early microcode load inside a virtual machine +--------------------------------------------- +RHEL 7 kernel supports early microcode load from cpio archive placed +at the beginning of initramfs image. However, when early microcode loading +is attempted inside some virtualised environments, that may result +in unexpected system behaviour. + +Affected microcode: all. + +Mitigation: early microcode loading is disabled for all CPU models. + +Minimum versions of kernel RPM that contain the fix: + - RHEL 7.6: 3.10.0-930 + - RHEL 7.5: 3.10.0-862.14.1 + - RHEL 7.4: 3.10.0-693.38.1 + - RHEL 7.3: 3.10.0-514.57.1 + - RHEL 7.2; 3.10.0-327.73.1 diff --git a/SOURCES/check_caveats b/SOURCES/check_caveats index 04975c2..dd52742 100755 --- a/SOURCES/check_caveats +++ b/SOURCES/check_caveats @@ -6,10 +6,14 @@ # SPDX-License-Identifier: CC0-1.0 : ${MC_CAVEATS_DATA_DIR=/usr/share/microcode_ctl/ucode_with_caveats} +: ${FW_DIR=/lib/firmware} +: ${CFG_DIR=/etc/microcode_ctl/ucode_with_caveats} usage() { - echo 'Usage: check_caveats [-k TARGET_KVER] [-c CONFIG] [-m] [-v]' + echo 'Usage: check_caveats [-e] [-k TARGET_KVER] [-c CONFIG] [-m] [-v]' echo + echo ' -e - check for early microcode load possibility (instead of' + echo ' late microcode load)' echo ' -k - target version to check against, $(uname -r) is used' echo ' otherwise' echo ' -c - caveat config(s) to check, all configs are checked' @@ -40,22 +44,22 @@ check_kver() # 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_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_rest#${t_minor}} - t_rest=${t_rest#[.-]} - t_patch=${t_rest%%[.-]*} + 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_rest#${t_y}} - t_rest=${t_rest#[.-]} - t_z1=${t_rest%%[.-]*} + t_rest=${t_rest#.} + t_z1=${t_rest%%.*} t_rest=${t_rest#${t_z1}} - t_rest=${t_rest#[.-]} - t_z2=${t_rest%%[.-]*} + t_rest=${t_rest#.} + t_z2=${t_rest%%.*} # minor/major/patch/y should be numeric [ -n "${t_major##*[!0-9]*}" ] || return 1 @@ -70,22 +74,22 @@ check_kver() cmp_type=upstream shift - m_major=${1%%[.-]*} + 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_rest#${m_minor}} - m_rest=${m_rest#[.-]} - m_patch=${m_rest%%[.-]*} + 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_rest#${m_y}} - m_rest=${m_rest#[.-]} - m_z1=${m_rest%%[.-]*} + m_rest=${m_rest#.} + m_z1=${m_rest%%.*} m_rest=${m_rest#${m_z1}} - m_rest=${m_rest#[.-]} - m_z2=${m_rest%%[.-]*} + m_rest=${m_rest#.} + m_z2=${m_rest%%.*} # minor/major/patch should be numeric [ -n "${m_major##*[!0-9]*}" ] || continue @@ -146,6 +150,24 @@ get_model_name() /bin/sed -rn '1,/^$/s/^model name[[:space:]]*: (.*)$/\1/p' /proc/cpuinfo } +get_vendor_id() +{ + /bin/sed -rn '1,/^$/s/^vendor_id[[:space:]]*: (.*)$/\1/p' /proc/cpuinfo +} + +get_mc_ver() +{ + /bin/sed -rn '1,/^$/s/^microcode[[:space:]]*: (.*)$/\1/p' /proc/cpuinfo +} + +fail() +{ + ret=1 + + fail_cfgs="$fail_cfgs $cfg" + fail_paths="$fail_paths $cfg_path" +} + #check_kver "$@" #get_model_name @@ -153,9 +175,15 @@ match_model=0 configs= kver=$(/bin/uname -r) verbose=0 +early_check=0 + +ret=0 -while getopts "k:c:mv" opt; do +while getopts "ek:c:mv" opt; do case "${opt}" in + e) + early_check=1 + ;; k) kver="$OPTARG" ;; @@ -179,30 +207,74 @@ done cpu_model=$(get_model_string) cpu_model_name=$(get_model_name) +cpu_vendor=$(get_vendor_id) + +ret_paths="" +ok_paths="" +fail_paths="" + +ret_cfgs="" +ok_cfgs="" +fail_cfgs="" + +skip_cfgs="" + +if [ 1 -eq "$early_check" ]; then + stage="early" +else + stage="late" +fi + for cfg in $(echo "${configs}"); do dir="$MC_CAVEATS_DATA_DIR/$cfg" + + # We add cfg to the skip list first and then, if we do not skip it, + # we remove the configuration from the list. + skip_cfgs="$skip_cfgs $cfg" + + [ -r "${dir}/readme" ] || { + debug "File 'readme' in ${dir} is not found, skipping" + continue + } + [ -r "${dir}/config" ] || { debug "File 'config' in ${dir} is not found, skipping" continue } cfg_model= + cfg_vendor= cfg_path= cfg_kvers= + cfg_kvers_early= cfg_blacklist= + cfg_mc_min_ver_late= + cfg_disable= while read -r key value; do case "$key" in model) cfg_model="$value" ;; + vendor) + cfg_vendor="$value" + ;; path) cfg_path="$cfg_path $value" ;; kernel) cfg_kvers="$cfg_kvers $value" ;; + kernel_early) + cfg_kvers_early="$cfg_kvers_early $value" + ;; + mc_min_ver_late) + cfg_mc_min_ver_late="$value" + ;; + disable) + cfg_disable="$cfg_disable $value " + ;; blacklist) cfg_blacklist=1 break @@ -217,35 +289,161 @@ for cfg in $(echo "${configs}"); do 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 - } + # Check for override files in the following order: + # - disallow early/late specific caveat for specific kernel + # - force early/late specific caveat for specific kernel + # - disallow specific caveat for specific kernel + # - force specific caveat for specific kernel + # + # - disallow early/late specific caveat for any kernel + # - disallow early/late any caveat for specific kernel + # - force early/late specific caveat for any kernel + # - force early/late any caveat for specific kernel + # - disallow specific caveat for any kernel + # - disallow any caveat for specific kernel + # - force specific caveat for any kernel + # - force any caveat for specific kernel + # + # - disallow early/late everything + # - force early/late everyhting + # - disallow everything + # - force everyhting + ignore_cfg=0 + force_cfg=0 + override_file="" + overrides=" + 0:$FW_DIR/$kver/disallow-$stage-$cfg + 1:$FW_DIR/$kver/force-$stage-$cfg + 0:$FW_DIR/$kver/disallow-$cfg + 1:$FW_DIR/$kver/force-$cfg + 0:$FW_DIR/$kver/disallow-$stage + 0:$CFG_DIR/disallow-$stage-$cfg + 1:$FW_DIR/$kver/force-$stage + 1:$CFG_DIR/force-$stage-$cfg + 0:$FW_DIR/$kver/disallow + 0:$CFG_DIR/disallow-$cfg + 1:$FW_DIR/$kver/force + 1:$CFG_DIR/force-$cfg + 0:$CFG_DIR/disallow-$stage + 1:$CFG_DIR/force-$stage + 0:$CFG_DIR/disallow + 1:$CFG_DIR/force" + for o in $(echo "$overrides"); do + o_force=${o%%:*} + override_file=${o#$o_force:} + + [ -e "$override_file" ] || continue + + if [ 0 -eq "$o_force" ]; then + ignore_cfg=1 + else + force_cfg=1 + fi + + break + done + + [ 0 -eq "$ignore_cfg" ] || { + debug "Configuration \"$cfg\" is ignored due to presence of" \ + "\"$override_file\"." + continue + } + + # Check model if model filter is enabled + if [ 1 -eq "$match_model" -a -n "$cfg_model" ]; then + [ "x$cpu_model" = "x$cfg_model" ] || { + debug "Current CPU model '$cpu_model' doesn't" \ + "match configuration CPU model '$cfg_model'," \ + "skipping" + continue + } + fi + + # Check vendor if model filter is enabled + if [ 1 -eq "$match_model" -a -n "$cfg_vendor" ]; then + [ "x$cpu_vendor" = "x$cfg_vendor" ] || { + debug "Current CPU vendor '$cpu_vendor' doesn't" \ + "match configuration CPU vendor '$cfg_vendor'," \ + "skipping" + continue } fi - if [ -n "$cfg_kvers" ]; then + # Check configuration files + + ret_cfgs="$ret_cfgs $cfg" + ret_paths="$ret_paths $cfg_path" + skip_cfgs="${skip_cfgs% $cfg}" + + [ 0 -eq "$force_cfg" ] || { + debug "Checks for configuration \"$cfg\" are ignored due to" \ + "presence of \"$override_file\"." + + ok_cfgs="$ok_cfgs $cfg" + ok_paths="$ok_paths $cfg_path" + + continue + } + + [ "x${cfg_disable%%* $stage *}" = "x$cfg_disable" ] || { + debug "${cfg}: caveat is disabled in configuration" + fail + continue + } + + # Check late load kernel version + if [ 1 -ne "$early_check" -a -n "$cfg_kvers" ]; then check_kver "$kver" $cfg_kvers || { - debug "${cfg}: kernel version check for '$kver'" \ - "against '$cfg_kvers' failed" - exit 1 + debug "${cfg}: late load kernel version check for" \ + " '$kver' against '$cfg_kvers' failed" + fail + continue } fi + # Check early load kernel version + if [ 0 -ne "$early_check" -a -n "$cfg_kvers_early" ]; then + check_kver "$kver" $cfg_kvers_early || { + debug "${cfg}: early load kernel version check for" \ + "'$kver' against '$cfg_kvers_early' failed" + fail + continue + } + fi + + # Check model blacklist if [ -n "$cfg_blacklist" ]; then echo "$cfg_blacklist" | /bin/grep -vqFx "${cpu_model_name}" || { debug "${cfg}: model '${cpu_model_name}' is blacklisted" - exit 1 + fail + continue + } + fi + + # Check current microcode version for the late update + if [ -n "$cfg_mc_min_ver_late" -a 1 -ne "$early_check" -a \ + "x$cpu_model" = "x$cfg_model" ]; then + cpu_mc_ver="$(get_mc_ver)" + + [ 1 -eq $((cpu_mc_ver >= cfg_mc_min_ver_late)) ] || { + debug "${cfg}: CPU microcode version $cpu_mc_ver" \ + "failed check (should be at least" \ + "${cfg_mc_min_ver_late})" + fail + continue } fi - #printf "%s " "$cfg" - #[ 0 -eq "$match_model" ] || printf "%s " "$cpu_model" - echo $cfg_path + ok_cfgs="$ok_cfgs $cfg" + ok_paths="$ok_paths $cfg_path" done -exit 0 +echo "cfgs$ret_cfgs" +echo "skip_cfgs$skip_cfgs" +echo "paths$ret_paths" +echo "ok_cfgs$ok_cfgs" +echo "ok_paths$ok_paths" +echo "fail_cfgs$fail_cfgs" +echo "fail_paths$fail_paths" + +exit $ret diff --git a/SOURCES/dracut_99microcode_ctl-fw_dir_override_module_init.sh b/SOURCES/dracut_99microcode_ctl-fw_dir_override_module_init.sh index 200548c..7d88111 100755 --- a/SOURCES/dracut_99microcode_ctl-fw_dir_override_module_init.sh +++ b/SOURCES/dracut_99microcode_ctl-fw_dir_override_module_init.sh @@ -1,9 +1,6 @@ #!/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). +# Hack in additional firmware directories for supported caveats. # # SPDX-License-Identifier: CC0-1.0 @@ -11,69 +8,146 @@ check() { return 0 } -DATA_DIR=/usr/share/microcode_ctl/ucode_with_caveats -check_caveats=/usr/libexec/microcode_ctl/check_caveats - install() { + local FW_DIR=/lib/firmware + local DATA_DIR=/usr/share/microcode_ctl/ucode_with_caveats + local CFG_DIR="/etc/microcode_ctl/ucode_with_caveats" + local check_caveats=/usr/libexec/microcode_ctl/check_caveats + + local verbose_opt + local cc_out + local path + local ignored + local do_skip_host_only + local p + 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" + dinfo " microcode_ctl module: mangling fw_dir" [ -z "$fw_dir_l" ] || { - dinfo " microcode_ctl module: avoid touching fw_dir as" \ + dinfo " microcode_ctl: avoid touching fw_dir as" \ "it has been changed (fw_dir_l is '$fw_dir_l')" return 0 } - ucode=$(get_ucode_file) + # Reset fw_dir to avoid inclusion of kernel-version-specific directories + # populated with microcode for the late load + [ "x$fw_dir" != \ + "x/lib/firmware/updates /lib/firmware /lib/firmware/$kernel" ] || { + fw_dir="/lib/firmware/updates /lib/firmware" + dinfo " microcode_ctl: reset fw_dir to \"${fw_dir}\"" + } - for i in $(ls "$DATA_DIR"); do + while read -d "/" -r i; 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" + + if ! cc_out=$($check_caveats -e -k "$kernel" -c "$i" $verbose_opt) + then + dinfo " microcode_ctl: kernel version \"$kernel\"" \ + "failed early load check for \"$i\", skipping" continue - } - [ ! -e "/etc/microcode_ctl/ucode_with_caveats/disallow-$i" ] || { - dinfo " microcode_ctl: skipping \"$i\":" \ - "\"/etc/microcode_ctl/ucode_with_caveats/disallow-$i\"" \ - "present" + fi + + path=$(printf "%s" "$cc_out" | sed -n 's/^paths //p') + [ -n "$path" ] || { + ignored=$(printf "%s" "$cc_out" | \ + sed -n 's/^skip_cfgs //p') + + if [ -n "$ignored" ]; then + dinfo " microcode_ctl: configuration" \ + "\"$i\" is ignored" + else + dinfo " microcode_ctl: no microcode paths" \ + "are associated with \"$i\", skipping" + fi + 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\")" + do_skip_host_only=0 + + local sho_overrides=" + $CFG_DIR/skip-host-only-check + $CFG_DIR/skip-host-only-check-$i + $FW_DIR/$kernel/skip-host-only-check + $FW_DIR/$kernel/skip-host-only-check-$i" + + for p in $(echo "$sho_overrides"); do + [ -e "$p" ] || continue + + do_skip_host_only=1 + dinfo " microcode_ctl: $i; skipping" \ + "Host-Only check, since \"$p\" exists." + break + done + else + do_skip_host_only=1 + fi + + if [ 0 -eq "$do_skip_host_only" ]; then + local hostonly_passed=0 + local ucode + local uvendor + local ucode_dir="" + + ucode=$(get_ucode_file) + uvendor=$(get_cpu_vendor) + + case "$uvendor" in + Intel) + ucode_dir="intel-ucode" + ;; + AMD) + ucode_dir="and-ucode" + ;; + *) + dinfo " microcode_ctl: unknown CPU" \ + "vendor: \"$uvendor\", bailing out of" \ + "Host-Only check" + continue + ;; + esac + + # $path is a list of globs, so it needs special care + for p in $(printf "%s" "$path"); do + find "$DATA_DIR/$i" -path "$DATA_DIR/$i/$p" \ + -print0 \ + | grep -zFxq \ + "$DATA_DIR/$i/$ucode_dir/$ucode" \ + || continue + + dinfo " microcode_ctl: $i: Host-Only" \ + "mode is enabled and" \ + "\"$ucode_dir/$ucode\" matches \"$p\"" + + hostonly_passed=1 + break + done + + [ 1 -eq "$hostonly_passed" ] || { + dinfo " microcode_ctl: $i: Host-Only mode" \ + "is enabled and ucode name does not" \ + "match the expected one, skipping" \ + "caveat (\"$ucode\" not in \"$path\")" 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 + dinfo " microcode_ctl: $i: caveats check for kernel" \ + "version \"$kernel\" passed, adding" \ + "\"$DATA_DIR/$i\" to fw_dir variable" + fw_dir="$DATA_DIR/$i $fw_dir" + done <<-EOF + $(find "$DATA_DIR" -maxdepth 1 -mindepth 1 -type d -printf "%f/") + EOF + + dinfo " microcode_ctl: final fw_dir: \"${fw_dir}\"" } diff --git a/SOURCES/intel-microcode2ucode.8.in b/SOURCES/intel-microcode2ucode.8.in new file mode 100644 index 0000000..829ec9f --- /dev/null +++ b/SOURCES/intel-microcode2ucode.8.in @@ -0,0 +1,90 @@ +.\" intel-microcode2ucode stub man page +.\" +.\" SPDX-License-Identifier: CC0-1.0 +.\" +.TH INTEL-MICROCODE2UCODE 8 "@DATE@" "MICROCODE_CTL @VERSION@" +.\" +.SH NAME +intel\-microcode2ucode \- convert Intel microcode.dat file into ucode files +.\" +.SH SYNOPSIS +.SY intel\-microcode2ucode +.RI [ MICROCODE_FILE ] +.YS +.\" +.SH DESCRIPTION +.B intel\-microcode2ucode +parses Intel microcode combined text data file (which usually has name +.BR microcode.dat ) +and splits it into individual binary microcode files that can be loaded by the +Linux kernel. +.LP +Generated microcode files are placed into +.B intel-ucode +directory, which is created in the current working directory, and have file name +format of +.IR FF - MM - SS , +where +.I FF +is the CPU family number, +.I MM +is the model number, and +.I SS +is stepping. +All three values are zero-filled to two digits and are hexadecimal +(letters are in the lower case). +.LP +This tool is mostly of historic interest, as Intel ships separate microcode +files now. +.\" +.SH OPTIONS +.\" +.TP +.I MICROCODE_FILE +Path to the +.B microcode.dat +file. +If no path has been provided, the default path +.B /lib/firmware/microcode.dat +is used. +If +.B - +(single dash) is provided as an argument, data is read from the standard input. +.\" +.SH EXIT STATUS +.TP +.B 0 +Success. +.TP +.B 1 +Error occurred: +temporary buffer cannot be allocated, +input microcode file cannot be opened, +microcode version and/or format are unknown, +cannot open output file, +cannot write to the output file. +.\" +.SH REPORTING BUGS +Problems with +.B intel-microcode2ucode +should be reported to +.UR https://bugzilla.redhat.com/ +Red Hat Bugzilla +.UE +.\" +.SH AUTHORS +.B intel-microcode2ucode +was written by +Kay Sievers and +Anton Arapov . +This manpage was written for Red Hat Enterprise Linux and may be +used, modified, and/or distributed freely by anyone. +.\" +.SH "SEE ALSO" +.UR https://gitlab.com\:/iucode-tool\:/iucode-tool +iucode-tool, a tool for manipulating Intel microcode files +.UE , +.LP +.UR @MICROCODE_URL@ +Intel microcode +.UE diff --git a/SOURCES/intel_config b/SOURCES/intel_config new file mode 100644 index 0000000..d37878d --- /dev/null +++ b/SOURCES/intel_config @@ -0,0 +1,8 @@ +path intel-ucode/* +vendor_id GenuineIntel +kernel_early 4.10.0 +kernel_early 3.10.0-930 +kernel_early 3.10.0-862.14.1 +kernel_early 3.10.0-693.38.1 +kernel_early 3.10.0-514.57.1 +kernel_early 3.10.0-327.73.1 diff --git a/SOURCES/intel_readme b/SOURCES/intel_readme new file mode 100644 index 0000000..6250d1e --- /dev/null +++ b/SOURCES/intel_readme @@ -0,0 +1,53 @@ +Older RHEL 7 kernels try to early load microcode even inside virtual +machine, which may lead to panic on some hypervisors. In order to circumvent +that, microcode is installed into a kernel-version-specific directory (which +is not scanned by the dracut script, that constructs early microcode binary +in initramfs, by default), and path to microcode files provided only in case +initramfs is generated for the kernel version that properly handles early +microcode inside a virtual machine (i.e. do not attempts yo load it). +The versions of the kernel package that properly handle early microcode load +inside a virtual machine are as follows: + RHEL 7.6: kernel-3.10.0-930 or newer; + RHEL 7.5: kernel-3.10.0-862.14.1 or newer; + RHEL 7.4: kernel-3.10.0-693.38.1 or newer; + RHEL 7.3: kernel-3.10.0-514.57.1 or newer. + RHEL 7.2: kernel-3.10.0-327.73.1 or newer. + +If you want to avoid adding this ucode for a specific kernel, please create +"disallow-early-intel" file inside /lib/firmware/ directory +and run dracut -f: + + touch /lib/firmware/3.10.0-862.9.1/disallow-intel + /usr/libexec/microcode_ctl/update_ucode + dracut -f --kver 3.10.0-862.9.1 + +If you want to skip processing of this microcode for all kernels, please create +"disallow-early-intel" file inside the "/etc/microcode_ctl/ucode_with_caveats" +directory and run dracut -f --regenerate-all: + + mkdir -p /etc/microcode_ctl/ucode_with_caveats + touch /etc/microcode_ctl/ucode_with_caveats/disallow-intel + dracut -f --kver 3.10.0-862.9.1 + +If you want to enforce addition of this microcode to initramfs for a specific +kernel, please create "force-early-intel" file inside +/lib/firmware/ directory and run +dracut -f --kver "": + + modir -p/lib/firmware/3.10.0-862.9.1/ + touch /lib/firmware/3.10.0-862.9.1/force-early-intel + dracut -f --kver 3.10.0-862.9.1 + +If you want to enforce addition of this microcode for all kernels, please +create "force-early-intel" file inside /etc/microcode_ctl/ucode_with_caveats +directory and run dracut -f --kver "": + + mkdir -p /etc/microcode_ctl/ucode_with_caveats + touch /etc/microcode_ctl/ucode_with_caveats/force-early-intel + dracut -f --regenerate-all + +In order to override late load behaviour, the "early" part of file names should +be replaced with "late". + + +See /usr/share/doc/microcode_ctl/README.caveats for additional information. diff --git a/SOURCES/microcode_ctl-do-not-install-intel-ucode.patch b/SOURCES/microcode_ctl-do-not-install-intel-ucode.patch new file mode 100644 index 0000000..5e5603c --- /dev/null +++ b/SOURCES/microcode_ctl-do-not-install-intel-ucode.patch @@ -0,0 +1,20 @@ +Index: microcode_ctl-2.1-14/Makefile +=================================================================== +--- microcode_ctl-2.1-14.orig/Makefile 2018-08-29 04:23:03.368699515 +0200 ++++ microcode_ctl-2.1-14/Makefile 2018-08-29 04:24:00.498140839 +0200 +@@ -29,14 +29,13 @@ + tar -xf $(MICROCODE_INTEL) + + clean: +- rm -rf $(PROGRAM) intel-ucode ++ rm -rf $(PROGRAM) + + install: + $(INS) -d $(DESTDIR)$(INSDIR) $(DESTDIR)$(DOCDIR) \ + $(DESTDIR)$(MICDIRINTEL) + $(INS) -m 755 $(PROGRAM) $(DESTDIR)$(INSDIR) + $(INS) -m 644 README $(DESTDIR)$(DOCDIR) +- $(INS) -m 644 intel-ucode/* $(DESTDIR)$(MICDIRINTEL) + + uninstall: + rm -rf $(DESTDIR)$(INSDIR)/$(PROGRAM) \ diff --git a/SOURCES/microcode_ctl-do-not-pipe-to-intel_microcode2ucode.patch b/SOURCES/microcode_ctl-do-not-pipe-to-intel_microcode2ucode.patch new file mode 100644 index 0000000..fc6934b --- /dev/null +++ b/SOURCES/microcode_ctl-do-not-pipe-to-intel_microcode2ucode.patch @@ -0,0 +1,13 @@ +Index: microcode_ctl-2.1-14/Makefile +=================================================================== +--- microcode_ctl-2.1-14.orig/Makefile 2017-11-22 08:19:31.000000000 +0100 ++++ microcode_ctl-2.1-14/Makefile 2018-08-09 07:10:34.562202626 +0200 +@@ -26,7 +26,7 @@ + + microcode_ctl: intel-microcode2ucode.c + $(CC) $(CFLAGS) -o $(PROGRAM) intel-microcode2ucode.c +- tar -xOf $(MICROCODE_INTEL) | ./intel-microcode2ucode - >/dev/null ++ tar -xf $(MICROCODE_INTEL) + + clean: + rm -rf $(PROGRAM) intel-ucode diff --git a/SOURCES/microcode_ctl-intel-microcode2ucode-buf-handling.patch b/SOURCES/microcode_ctl-intel-microcode2ucode-buf-handling.patch new file mode 100644 index 0000000..9a014a8 --- /dev/null +++ b/SOURCES/microcode_ctl-intel-microcode2ucode-buf-handling.patch @@ -0,0 +1,95 @@ +Fix most obvious intel-microcode2ucode buffer overruns. +Index: microcode_ctl-2.1-19/intel-microcode2ucode.c +=================================================================== +--- microcode_ctl-2.1-19.orig/intel-microcode2ucode.c 2018-08-20 04:32:26.803450076 +0200 ++++ microcode_ctl-2.1-19/intel-microcode2ucode.c 2018-08-20 04:33:49.324661025 +0200 +@@ -47,16 +47,25 @@ + char c[0]; + }; + ++#define MAX_MICROCODE 4000000 ++ + int main(int argc, char *argv[]) + { + char *filename = "/lib/firmware/microcode.dat"; + FILE *input, *f; + char line[LINE_MAX]; +- char buf[4000000]; ++ char *buf = NULL; + union mcbuf *mc; + size_t bufsize, count, start; + int rc = EXIT_SUCCESS; + ++ buf = malloc(MAX_MICROCODE); ++ if (!buf) { ++ printf("can't allocate buffer\n"); ++ rc = EXIT_FAILURE; ++ goto out; ++ } ++ + if (argv[1] != NULL) + filename = argv[1]; + +@@ -74,6 +83,12 @@ + count = 0; + mc = (union mcbuf *) buf; + while (fgets(line, sizeof(line), input) != NULL) { ++ if ((count + 3) >= (MAX_MICROCODE / sizeof(mc->i[0]))) { ++ printf("input file is too big"); ++ rc = EXIT_FAILURE; ++ goto out; ++ } ++ + if (sscanf(line, "%x, %x, %x, %x", + &mc->i[count], + &mc->i[count + 1], +@@ -102,6 +117,10 @@ + unsigned int family, model, stepping; + unsigned int year, month, day; + ++ if ((start > bufsize) || ++ ((bufsize - start) < sizeof(struct microcode_header_intel))) ++ goto out; ++ + mc = (union mcbuf *) &buf[start]; + + if (mc->hdr.totalsize) +@@ -109,8 +128,12 @@ + else + size = 2000 + sizeof(struct microcode_header_intel); + ++ if (size > (bufsize - start)) ++ goto out; ++ + if (mc->hdr.ldrver != 1 || mc->hdr.hdrver != 1) { +- printf("unknown version/format:\n"); ++ printf("unknown version/format: %d/%d\n", ++ mc->hdr.ldrver, mc->hdr.hdrver); + rc = EXIT_FAILURE; + break; + } +@@ -135,7 +158,11 @@ + month = mc->hdr.date >> 24; + day = (mc->hdr.date >> 16) & 0xff; + +- asprintf(&filename, "intel-ucode/%02x-%02x-%02x", family, model, stepping); ++ if (asprintf(&filename, "intel-ucode/%02x-%02x-%02x", family, ++ model, stepping) == -1) { ++ printf("Failed to generate ucode filename\n"); ++ goto out; ++ } + printf("\n"); + printf("%s\n", filename); + printf("signature: 0x%02x\n", mc->hdr.sig); +@@ -164,6 +191,11 @@ + } + printf("\n"); + ++ if (start != bufsize) ++ printf("Finished parsing at byte %zu of %zu\n", start, bufsize); ++ + out: ++ free(buf); ++ + return rc; + } diff --git a/SOURCES/microcode_ctl-use-microcode-20180807a-tgz.patch b/SOURCES/microcode_ctl-use-microcode-20180807a-tgz.patch new file mode 100644 index 0000000..f39cb1f --- /dev/null +++ b/SOURCES/microcode_ctl-use-microcode-20180807a-tgz.patch @@ -0,0 +1,13 @@ +Index: microcode_ctl-2.1-18/Makefile +=================================================================== +--- microcode_ctl-2.1-18.orig/Makefile 2018-07-24 09:15:12.463115045 +0200 ++++ microcode_ctl-2.1-18/Makefile 2018-08-09 06:18:45.524503945 +0200 +@@ -8,7 +8,7 @@ + # 2 of the License, or (at your option) any later version. + + PROGRAM = intel-microcode2ucode +-MICROCODE_INTEL = microcode-20171117.tgz ++MICROCODE_INTEL = microcode-20180807a.tgz + + INS = install + CC = gcc diff --git a/SOURCES/reload_microcode b/SOURCES/reload_microcode index 62fb43e..82ff2b9 100644 --- a/SOURCES/reload_microcode +++ b/SOURCES/reload_microcode @@ -6,8 +6,16 @@ # SPDX-License-Identifier: CC0-1.0 CHECK_CAVEATS=/usr/libexec/microcode_ctl/check_caveats +IGNORE_HYPERVISOR="/etc/microcode_ctl/ignore-hypervisor-flag" trigger=1 +[ -e "$IGNORE_HYPERVISOR" ] || { + if grep -q '^flags[[:space:]]*:.* hypervisor\( .*\)\?$' /proc/cpuinfo + then + exit 0 + fi +} + "$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 index df8033f..431148a 100644 --- a/SOURCES/update_ucode +++ b/SOURCES/update_ucode @@ -7,9 +7,10 @@ usage() { - echo "Usage: update_ucode [--action {add|remove|refresh}]" \ + echo "Usage: update_ucode [--action {add|remove|refresh|list}]" \ "[--kernel KERNELVER]* [--verbose] [--dry-run]" \ - "[--trigger-dracut] [--cleanup intel_ucode caveats_ucode]" >&2 + "[--cleanup intel_ucode caveats_ucode]" \ + "[--skip-common] [--skip-kernel-specific]" >&2 } debug() { [ 0 = "$verbose" ] || echo "$*" >&2; } @@ -25,13 +26,20 @@ kernel= verbose=0 verbose_opt= dry_run=0 -trigger_dracut=0 remove_cleanup=0 cleanup_intel= cleanup_caveats= +skip_common=0 +skip_caveats=0 while [ 1 -le "$#" ]; do case "$1" in + -C|--skip-common) + skip_common=1 + ;; + -K|--skip-kernel-specific) + skip_caveats=1 + ;; -a|--action) shift action="$1" @@ -47,9 +55,6 @@ while [ 1 -le "$#" ]; do -n|--dry-run) dry_run=1 ;; - -d|--trigger-dracut) - trigger_dracut=1 - ;; -c|--cleanup) remove_cleanup=1 shift @@ -69,7 +74,7 @@ cmd= [ 0 -eq "$dry_run" ] || cmd=echo case "$action" in -add|remove|refresh) +add|remove|refresh|list) # Scan all directories in FW_DIR and all existing kernels if [ -z "$kernel" ]; then debug "No kernel versions provided, scanning..." @@ -91,6 +96,8 @@ add|remove|refresh) kernel="$kernel $k" } done + + kernel=$(printf "%s" "$kernel" | xargs -n 1 | sort -u) fi ;; *) @@ -103,6 +110,8 @@ esac # Generic part: managing intel ucode debug "Running action \"$action\" on common Intel microcode directory" while :; do + [ 0 -eq "$skip_common" ] || break + [ ! -e "/etc/microcode_ctl/intel-ucode-disallow" ] || { debug " Skipping \"$i\":" \ "\"/etc/microcode_ctl/intel-ucode-disallow\"" \ @@ -117,8 +126,8 @@ while :; do # Removing old files case "$action" in - refresh|remove) - debug " Removing old files from ${MC_DIR}/${INTEL_UCODE_DIR}" + refresh|remove|list) + debug " Removing old files from ${FW_DIR}/${INTEL_UCODE_DIR}" if [ 0 = "$remove_cleanup" ]; then find "${MC_DIR}/${INTEL_UCODE_DIR}" \ -maxdepth 1 -mindepth 1 \ @@ -134,23 +143,25 @@ while :; do [ -L "$name" ] || continue fi + [ "xlist" != "x$action" ] || { + echo "$name" + continue + } + $cmd rm -f $verbose_opt "$name" done - $cmd rmdir -p $verbose_opt "${FW_DIR}/${INTEL_UCODE_DIR}" 2>/dev/null || true + [ "xlist" = "x$action" ] || { + $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}" + debug " Creating symlinks in ${FW_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"' '\''{}'\'' \ @@ -168,87 +179,110 @@ if [ 0 = "$remove_cleanup" ]; then else cat "$cleanup_caveats" fi | while read -r i; do + [ 0 -eq "$skip_caveats" ] || break + 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" + { + out=$($check_caveats -k "$k" -c "$i" $verbose_opt) + ret="$?" + } || : + paths=$(printf "%s" "$out" | sed -n 's/^paths //p') + ignore=$(printf "%s" "$out" | sed -n 's/^skip_cfgs //p') + + [ -z "$ignore" ] || { + debug " Configuration is ignored, skipping" continue } - path=$($check_caveats -k "$k" -c "$i") case "$action" in - remove|refresh) - debug " Removing $path (part of $action)..." + remove|refresh|list) + [ "xlist" = "x$action" ] || \ + debug " Removing \"$paths\" (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" + for p in $(printf "%s" "$paths"); do + find "$DATA_DIR/$i" -path "$DATA_DIR/$i/$p" \ + -printf "%P\n" + done | while read -r path; do + [ -e "$FW_DIR/$k/readme-$i" ] || { + debug " \"$FW_DIR/$k/readme-$i\"" \ + "is not found, skipping" \ + "\"$paths\" removal" + + break } - else - debug " \"$FW_DIR/$k/readme-$i\" is not found," \ - "skipping \"$FW_DIR/$k/$path\" removal" + + if [ "xlist" = "x$action" ]; then + echo "$FW_DIR/$k/$path" + else + debug " Removing \"$FW_DIR/$k/$path\"" + $cmd rm -f $verbose_opt "$FW_DIR/$k/$path" + $cmd rmdir -p $verbose_opt \ + "$FW_DIR/$k/$(dirname $path)" 2>/dev/null \ + || true + fi + done + + if [ -e "$FW_DIR/$k/readme-$i" ]; then + if [ "xlist" = "x$action" ]; then + echo "$FW_DIR/$k/readme-$i" + else + $cmd rm -f $verbose_opt \ + "$FW_DIR/$k/readme-$i" + $cmd rmdir -p $verbose_opt \ + "$FW_DIR/$k" 2>/dev/null || true + fi fi ;; esac + [ 0 -eq "$ret" ] || { + debug " Checking for caveats failed" \ + "(kernel version \"$k\"), skipping" + continue + } + + [ -n "$paths" ] || { + debug " List of paths to add is empty, skipping" + continue + } + case "$action" in add|refresh) - debug " Adding $path (part of $action)..." + debug " Adding $paths (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" + for p in $(printf "%s" "$paths"); do + find "$DATA_DIR/$i" -path "$DATA_DIR/$i/$p" \ + -printf "%P\n" + done | while read -r path; do + [ ! -e "$FW_DIR/$k/$path" ] || { + debug " $FW_DIR/$k/$path already" \ + "exists, skipping" + continue + } + + debug " Adding \"$FW_DIR/$k/$path\"" + $cmd mkdir -p $verbose_opt \ + "$(dirname "$FW_DIR/$k/$path")" + $cmd ln -s $verbose_opt "$DATA_DIR/$i/$path" \ + "$FW_DIR/$k/$path" + done - [ 0 -eq "$trigger_dracut" ] || { - debug " Triggering dracut for kernel \"$k\"" - $cmd dracut -f $verbose_opt --kver "$k" - } + if [ -e "$FW_DIR/$k/readme-$i" ]; then + debug " $FW_DIR/$k/readme-$i already" \ + "exists, skipping creation" + else + $cmd cp $verbose_opt "$DATA_DIR/$i/readme" \ + "$FW_DIR/$k/readme-$i" + fi ;; remove) esac diff --git a/SPECS/microcode_ctl.spec b/SPECS/microcode_ctl.spec index 102109d..e1a6ac9 100644 --- a/SPECS/microcode_ctl.spec +++ b/SPECS/microcode_ctl.spec @@ -1,27 +1,47 @@ -%define upstream_version 2.1-20180703 -%define microcode_ctl_libexec /usr/libexec/microcode_ctl +%define upstream_version 2.1-14 +%define intel_ucode_version 20180807a +%define intel_ucode_file_id 28087 +%define microcode_ctl_libexec %{_libexecdir}/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 +%define dracutlibdir %{_prefix}/lib/dracut +%define i_m2u_man intel-microcode2ucode.8 Summary: Tool to transform and deploy CPU microcode update for x86. Name: microcode_ctl Version: 2.1 -Release: 29.10%{?dist} +Release: 29.16%{?dist} Epoch: 2 Group: System Environment/Base License: GPLv2+ and Redistributable, no modification permitted URL: https://pagure.io/microcode_ctl -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 +Source0: https://releases.pagure.org/microcode_ctl/%{name}-%{upstream_version}.tar.xz +Source1: https://downloadmirror.intel.com/%{intel_ucode_file_id}/eng/microcode-%{intel_ucode_version}.tgz + +Source2: microcode.service + +Source3: 01-microcode.conf +Source4: dracut_99microcode_ctl-fw_dir_override_module_init.sh + +Source5: update_ucode +Source6: check_caveats +Source7: reload_microcode +Source8: disclaimer + +Source10: 06-4f-01_readme +Source11: 06-4f-01_config + +Source20: intel_readme +Source21: intel_config + +Source30: README.caveats +Source31: %{i_m2u_man}.in + +Patch1: microcode_ctl-do-not-pipe-to-intel_microcode2ucode.patch +Patch2: microcode_ctl-use-microcode-%{intel_ucode_version}-tgz.patch +Patch4: microcode_ctl-do-not-install-intel-ucode.patch +Patch5: microcode_ctl-intel-microcode2ucode-buf-handling.patch Buildroot: %{_tmppath}/%{name}-%{version}-root ExclusiveArch: %{ix86} x86_64 @@ -41,45 +61,91 @@ back to the old microcode. %prep %setup -q -n %{name}-%{upstream_version} +%patch1 -p1 + +# Use microcode-20180807a.tgz instead of microcode-20171117.tgz bundled with +# upstream microcode_ctl-2.1-14. +cp "%{SOURCE1}" . +%patch2 -p1 + +# We install ucode files manually into "intel" caveat directory +%patch4 -p1 + +%patch5 -p1 %build make CFLAGS="$RPM_OPT_FLAGS" %{?_smp_mflags} -find intel-ucode -type f | sed 's/^/%%ghost \/lib\/firmware\//' > ghost_list +# We do not populate any intel-ucode files into /lib/firmware directly due to +# early microcode load inside VM issue: +# https://bugzilla.redhat.com/show_bug.cgi?id=1596627 +# https://bugzilla.redhat.com/show_bug.cgi?id=1607899 +#find intel-ucode -type f | sed 's/^/%%ghost \/lib\/firmware\//' > ghost_list +touch ghost_list + +# man page +sed "%{SOURCE31}" \ + -e "s/@DATE@/2018-08-28/g" \ + -e "s/@VERSION@/%{version}-%{release}/g" \ + -e "s|@MICROCODE_URL@|https://downloadcenter.intel.com/download/%{intel_ucode_file_id}|g" > "%{i_m2u_man}" %install rm -rf %{buildroot} 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}%{dracutlibdir}/dracut.conf.d mkdir -p %{buildroot}%{_unitdir} -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 +install -m 644 %{SOURCE2} -t %{buildroot}%{_unitdir} +install -m 644 %{SOURCE3} -t %{buildroot}%{dracutlibdir}/dracut.conf.d +install -m 644 %{SOURCE8} %{buildroot}/usr/share/doc/microcode_ctl/disclaimer +mkdir -p "%{buildroot}%{dracutlibdir}/modules.d/99microcode_ctl-fw_dir_override" +install -m 755 %{SOURCE4} \ + %{buildroot}%{dracutlibdir}/modules.d/99microcode_ctl-fw_dir_override/module-setup.sh + +# Internal helper scripts 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} +install -m 755 %{SOURCE5} %{buildroot}/%{update_ucode} +install -m 755 %{SOURCE6} %{buildroot}/%{check_caveats} +install -m 755 %{SOURCE7} %{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 +# caveats readme +install -m 644 %{SOURCE30} -t %{buildroot}/usr/share/doc/microcode_ctl/ -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 +# Provide Intel microcode license, as it requires so +install -m 644 license %{buildroot}/usr/share/doc/microcode_ctl/LICENSE.intel-ucode +# Handle ucode with caveats +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 \ + -t %{buildroot}/usr/share/microcode_ctl/ucode_with_caveats/intel-06-4f-01/intel-ucode/ +install -m 644 %{SOURCE10} \ + %{buildroot}/usr/share/microcode_ctl/ucode_with_caveats/intel-06-4f-01/readme +install -m 644 %{SOURCE11} \ + %{buildroot}/usr/share/microcode_ctl/ucode_with_caveats/intel-06-4f-01/config + +mkdir -p "%{buildroot}/usr/share/microcode_ctl/ucode_with_caveats/intel/intel-ucode" +install -m 644 intel-ucode/* \ + -t %{buildroot}/usr/share/microcode_ctl/ucode_with_caveats/intel/intel-ucode/ +install -m 644 %{SOURCE20} \ + %{buildroot}/usr/share/microcode_ctl/ucode_with_caveats/intel/readme +install -m 644 %{SOURCE21} \ + %{buildroot}/usr/share/microcode_ctl/ucode_with_caveats/intel/config + +# Man page +install -m 755 -d %{buildroot}/%{_mandir}/man8/ +install -m 644 "%{i_m2u_man}" -t %{buildroot}/%{_mandir}/man8/ + +# Cleanup rm -f intel-ucode-with-caveats/06-4f-01 rmdir intel-ucode-with-caveats +rm -rf intel-ucode %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 - %{reload_microcode} -fi +%{reload_microcode} + # 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 @@ -95,7 +161,12 @@ cat /usr/share/doc/microcode_ctl/disclaimer > /dev/kmsg # dependency, it is pointless at best to regenerate the initramfs, # and also does not work with rpm-ostree: # https://bugzilla.redhat.com/show_bug.cgi?id=1199582 -if [ -d /run/systemd/system ]; then +# +# Also check that the running kernel is actually installed: +# https://bugzilla.redhat.com/show_bug.cgi?id=1591664 +# We use the presence of symvers file as an indicator, the check similar +# to what weak-modules script does. +if [ -d /run/systemd/system -a -e "/boot/symvers-$(uname -r).gz" ]; then dracut -f fi @@ -107,44 +178,61 @@ 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" +%{update_ucode} --action list --skip-common | + sort > "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_file_list" %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" +if [ -e "%{update_ucode}" ]; then + 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_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" + 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 + + 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" else - while read f; do + while read -r 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" + + rmdir "/lib/firmware/intel-ucode" 2>/dev/null || : + + # We presume that if we don't have update_ucode script, we can remove + # all the caveats-related files. + while read -r f; do + if [ -L "$f" ] || [ "${f%%readme-*}" != "$f" ]; then + rm -f "$f" + rmdir -p $(dirname "$f") 2>/dev/null || : + fi + done < "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_file_list" 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_file_list" -rm -f "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode_diff" -rm -f "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats_diff" +exit 0 %triggerin -- kernel %{update_ucode} @@ -157,17 +245,41 @@ rm -f "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats_diff" rm -rf %{buildroot} %files -f ghost_list -%ghost %attr(0100755, root, root) /lib/firmware/intel-ucode/ +%ghost %attr(0755, root, root) /lib/firmware/intel-ucode/ /usr/sbin/intel-microcode2ucode %{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 +%{dracutlibdir}/modules.d/99microcode_ctl-fw_dir_override +%config(noreplace) %{dracutlibdir}/dracut.conf.d/01-microcode.conf %{_unitdir}/microcode.service %doc /usr/share/doc/microcode_ctl/* +%{_mandir}/man8/* %changelog +* Wed Sep 05 2018 Eugene Syromiatnikov - 2:2.1-29.16 +- Add 7.3.z kernel version to kernel_early configuration. + +* Thu Aug 30 2018 Eugene Syromiatnikov - 2:2.1-29.15 +- Fix dracut module checks in Host-Only mode. + +* Thu Aug 30 2018 Eugene Syromiatnikov - 2:2.1-29.14 +- Disable 06-4f-01 microcode in config (#1623630). + +* Wed Aug 29 2018 Eugene Syromiatnikov - 2:2.1-29.12 +- Drop "hypervisor" /proc/cpuinfo flag check. +- Intel CPU microcode update to 20180807a. +- Add README.caveats documentation file. +- Add intel-microcode2ucode manual page. +- Add check for early microcode load, use it in microcode_ctl dracut module. +- Check that the currently running kernel is installed before + running dracut -f. + +* Fri Aug 10 2018 Eugene Syromiatnikov - 2:2.1-29.11 +- Add an ability to disable "hypervisor" /proc/cpuinfo flag check. +- Intel CPU microcode update to 20180807. +- Resolves: #1614847. + * Fri Jul 27 2018 Eugene Syromiatnikov - 2:2.1-29.10 - Provide %attr for the ghosted /lib/firmware.