Bug 2218104

Summary: [RHEL 9] check_caveats dead loops when executing with ja_JP.SJIS locale
Product: Red Hat Enterprise Linux 9 Reporter: Eugene Syromiatnikov <esyr>
Component: microcode_ctlAssignee: Eugene Syromiatnikov <esyr>
Status: CLOSED ERRATA QA Contact: Jeff Bastian <jbastian>
Severity: high Docs Contact:
Priority: high    
Version: 9.3CC: jbastian, rmetrich
Target Milestone: rcKeywords: Triaged
Target Release: ---   
Hardware: x86_64   
OS: Linux   
Whiteboard:
Fixed In Version: microcode_ctl-20230214-4.el9 Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: 2218096 Environment:
Last Closed: 2023-11-07 08:53:48 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On: 2218096    
Bug Blocks:    

Description Eugene Syromiatnikov 2023-06-28 07:26:15 UTC
+++ This bug was initially created as a clone of Bug #2218096 +++

Description of problem:

When the system is configured with ja_JP.SJIS locale (see https://access.redhat.com/solutions/202713), it appears that executing the following command (which is executed as part of reinstalling the microcode_ctl package for example) dead loops:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
# export LANG=ja_JP.sjis
# /bin/bash -eu /usr/libexec/microcode_ctl/check_caveats -k 4.18.0-425.19.2.el8_7.x86_64 -c intel-06-8e-9e-0x-dell
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

Digging further, there is an issue when the script tries to remove from shortest front pattern on line 346 (instrumented code, should be line 345):
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
 305         while [ -n "$opts" ]; do
 :
 345                 debug "was '$opts', opt='$opt'"
 346                 opts="${opts#"${opt}"}"
 347                 debug "now '$opts'"
 348                 continue
 :
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

In debug mode, we can see that the "mode=fail-equal" is not removed from the $opts variable, causing the dead loop to occur:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
 :
was 'mode=fail-equal no-model-mode=success key=bios_vendor val="Dell Inc."', opt='mode=fail-equal'
now 'mode=fail-equal no-model-mode=success key=bios_vendor val="Dell Inc."'
was 'mode=fail-equal no-model-mode=success key=bios_vendor val="Dell Inc."', opt='mode=fail-equal'
now 'mode=fail-equal no-model-mode=success key=bios_vendor val="Dell Inc."'
was 'mode=fail-equal no-model-mode=success key=bios_vendor val="Dell Inc."', opt='mode=fail-equal'
now 'mode=fail-equal no-model-mode=success key=bios_vendor val="Dell Inc."'
 :
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

The issue is with the double-quotes used multiple times:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
opts="${opts#"${opt}"}"
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

should be

-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
opts="${opts#${opt}}"
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

But this doesn't solve the issue completely, because even with fixing this, the issue persists with last token ("Dell Inc."), which somehow starts containg a double quote at the end because of some quoting handling on lines 315-322 (instrumented code):

-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
 305         while [ -n "$opts" ]; do
 306                 opt="${opts%%[  ]*}"
 307                 [ -n "${opt}" ] || { opts="${opts#[     ]}"; continue; }
 308                 debug "(308) opt='$opt'"
 :
 315                 # Handle possible quoting
 316                 [ "x${opt#val=}" = "x${opt}" ] || {
 317                         case "${opt#val=}" in
 318                         [\']*) opt_="${opts#val=\'}"; val="${opt_%%\'*}"; opt="val='${val}'" ;;
 319                         [\"]*) opt_="${opts#val=\"}"; val="${opt_%%\"*}"; opt="val=\"${val}\"" ;;
 320                         *)    val="${opt#val=}" ;;
 321                         esac
 322                 } 
 323                 debug "(323) opt='$opt'"
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

Result with instrumentation (and line 346 "fixed"):
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
was 'key=bios_vendor val="Dell Inc."', opt='key=bios_vendor'
now ' val="Dell Inc."'
(308) opt='val="Dell'
(323) opt='val="Dell Inc.""'
                         ^^^^^ doubled double quote

was 'val="Dell Inc."', opt='val="Dell Inc.""'
now 'val="Dell Inc."'
(308) opt='val="Dell'
(323) opt='val="Dell Inc.""'
 :
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

Original line 345 has to be fixed, and, to avoid any other possible issue with locale, "LANG=C" should be set at the beginning of the script to make sure we control the behavior.

Version-Release number of selected component (if applicable):

microcode_ctl

How reproducible:

Always

Steps to Reproduce:
1. Create the special locale

    # yum -y install glibc-locale-source glibc-langpack-ja
    # localedef -f SHIFT_JIS -i ja_JP ja_JP.SJIS

2. Set the locale in the environment and execute the script

    # export LANG=ja_JP.sjis
    # /bin/bash -eu /usr/libexec/microcode_ctl/check_caveats -k 4.18.0-425.19.2.el8_7.x86_64 -c intel-06-8e-9e-0x-dell

Actual results:

Spin on the CPU

Expected results:

Script proceeds properly

--- Additional comment from Eugene Syromiatnikov on 2023-06-28 07:22:41 UTC ---

The quotes are necessary to avoid expansion of the $opt's value (try, for example, to put an asterisk ("*") as a parameter), but the export LC_ALL=C in the beginning is indeed required to avoid any unexpected behaviour.

--- Additional comment from Eugene Syromiatnikov on 2023-06-28 07:24:46 UTC ---

(As a side note, when I tried to reproduce the issue on RHEL 9.2, I got the different beaviour when the parameters are not parsed at all)

Comment 5 Jeff Bastian 2023-08-21 21:50:43 UTC
Verified with microcode_ctl-20230214-4.el9 and glibc-langpack-ja-2.34-78.el9.

[root@localhost ~]# rpm -q glibc-langpack-ja glibc-locale-source microcode_ctl
glibc-langpack-ja-2.34-78.el9.x86_64
glibc-locale-source-2.34-78.el9.x86_64
microcode_ctl-20230214-4.el9.noarch

[root@localhost ~]# export LANG=ja_JP.sjis

[root@localhost ~]# localedef -f SHIFT_JIS -i ja_JP ja_JP.SJIS
failed to set locale!
[warning] character map `SHIFT_JIS' is not ASCII compatible, locale not ISO C compliant [--no-warnings=ascii]

[root@localhost ~]# /bin/bash -eu /usr/libexec/microcode_ctl/check_caveats -k 4.18.0-425.19.2.el8_7.x86_64 -c intel-06-8e-9e-0x-dell
cfgs intel-06-8e-9e-0x-dell
skip_cfgs
paths  intel-ucode/*
ok_cfgs intel-06-8e-9e-0x-dell
ok_paths  intel-ucode/*
fail_cfgs
fail_paths

[root@localhost ~]# uptime
 17:49:30 up 24 min,  1 user,  load average: 0.00, 0.00, 0.02

Comment 7 errata-xmlrpc 2023-11-07 08:53:48 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory (microcode_ctl bug fix and enhancement update), and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHEA-2023:6637