From 62dafb1c739985097038432b851a02cad2fbe036 Mon Sep 17 00:00:00 2001
From: Miha Purg <miha.purg@canonical.com>
Date: Mon, 18 Mar 2024 21:49:13 +0100
Subject: [PATCH] Fix handling of grub.d configs in grub2_bootloader_argument

Fixed failing check on Ubuntu when grub parameters were defined in
/etc/default/grub.d/*cfg but not in /etc/default/grub.

The fixed oval checks for the existence of the parameter
in *either* /etc/default/grub or *at least one*
/etc/default/grub.d/*cfg, ignoring loading order or overriden values.

We can avoid the added complexity of checking the loading
order and potentially overridden GRUB_CMDLINE_LINUX variables,
because the tests with /etc/default/grub* are redundant to begin with.
The OVAL checks also the parameters in the generated grub configs
in /boot (as prescribed by CIS 1.0.0 for Ubuntu 22.04).
---
 .../grub2_bootloader_argument/oval.template   | 62 +++++++++++++++----
 .../tests/correct_value_configdir.pass.sh     |  2 +-
 2 files changed, 51 insertions(+), 13 deletions(-)

diff --git a/shared/templates/grub2_bootloader_argument/oval.template b/shared/templates/grub2_bootloader_argument/oval.template
index 63478873a01..374aca885a1 100644
--- a/shared/templates/grub2_bootloader_argument/oval.template
+++ b/shared/templates/grub2_bootloader_argument/oval.template
@@ -9,6 +9,7 @@
 {{% set system_with_referenced_kernel_options_in_loader_entries = false -%}}
 {{% set system_with_kernel_options_in_grubenv = false -%}}
 {{% set system_with_kernel_options_in_etc_default_grub = true -%}}
+{{% set system_with_kernel_options_in_etc_default_grub_d = false -%}}
 {{% set system_with_expanded_kernel_options_in_grub_cfg = false -%}}
 {{% set system_with_bios_and_uefi_support = false -%}}
 
@@ -25,6 +26,10 @@
 {{% set system_with_expanded_kernel_options_in_grub_cfg = true %}}
 {{%- endif -%}}
 
+{{% if 'ubuntu' in product -%}}
+{{% set system_with_kernel_options_in_etc_default_grub_d = true -%}}
+{{%- endif -%}}
+
 {{% if grub2_uefi_boot_path and grub2_uefi_boot_path != grub2_boot_path -%}}
 {{% set system_with_bios_and_uefi_support = true %}}
 {{%- endif -%}}
@@ -66,11 +71,23 @@
       {{%- endif %}}
       {{% if system_with_kernel_options_in_etc_default_grub -%}}
         <criteria operator="OR">
-          <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument"
-          comment="check for {{{ ARG_NAME_VALUE }}} in /etc/default/grub via GRUB_CMDLINE_LINUX" />
+          <criteria operator="OR">
+            <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument"
+            comment="check for {{{ ARG_NAME_VALUE }}} in /etc/default/grub via GRUB_CMDLINE_LINUX" />
+            {{% if system_with_kernel_options_in_etc_default_grub_d -%}}
+            <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_configdir"
+            comment="check for {{{ ARG_NAME_VALUE }}} in /etc/default/grub.d/*cfg via GRUB_CMDLINE_LINUX" />
+            {{%- endif %}}
+          </criteria>
           <criteria operator="AND">
-            <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_default"
-            comment="check for {{{ ARG_NAME_VALUE }}} in /etc/default/grub via GRUB_CMDLINE_LINUX_DEFAULT" />
+            <criteria operator="OR">
+              <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_default"
+              comment="check for {{{ ARG_NAME_VALUE }}} in /etc/default/grub via GRUB_CMDLINE_LINUX_DEFAULT" />
+              {{% if system_with_kernel_options_in_etc_default_grub_d -%}}
+              <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_default_configdir"
+              comment="check for {{{ ARG_NAME_VALUE }}} in /etc/default/grub.d/*cfg via GRUB_CMDLINE_LINUX_DEFAULT" />
+              {{%- endif %}}
+            </criteria>
             <extend_definition definition_ref="bootloader_disable_recovery_set_to_true"
             comment="Check GRUB_DISABLE_RECOVERY=true in /etc/default/grub" />
           </criteria>
@@ -88,11 +105,7 @@
   </ind:textfilecontent54_test>
 
   <ind:textfilecontent54_object id="object_grub2_{{{ SANITIZED_ARG_NAME }}}_argument" version="1">
-    {{%- if 'ubuntu' in product %}}
-    <ind:filepath operation="pattern match">^/etc/default/grub(\.d/[^/]+\.cfg)?$</ind:filepath>
-    {{%- else %}}
     <ind:filepath>/etc/default/grub</ind:filepath>
-    {{%- endif %}}
     <ind:pattern operation="pattern match">^\s*GRUB_CMDLINE_LINUX="(.*)"$</ind:pattern>
     <ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
   </ind:textfilecontent54_object>
@@ -106,11 +119,36 @@
 
   <ind:textfilecontent54_object id="object_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_default"
   version="1">
-    {{%- if 'ubuntu' in product %}}
-    <ind:filepath operation="pattern match">^/etc/default/grub(\.d/[^/]+\.cfg)?$</ind:filepath>
-    {{%- else %}}
     <ind:filepath>/etc/default/grub</ind:filepath>
-    {{%- endif %}}
+    <ind:pattern operation="pattern match">^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$</ind:pattern>
+    <ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
+  </ind:textfilecontent54_object>
+{{%- endif %}}
+
+{{% if system_with_kernel_options_in_etc_default_grub_d -%}}
+  <ind:textfilecontent54_test id="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_configdir"
+  comment="check for {{{ ARG_NAME_VALUE }}} in /etc/default/grub.d/*cfg via GRUB_CMDLINE_LINUX"
+  check="all" check_existence="any_exist" version="1">
+    <ind:object object_ref="object_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_configdir" />
+    <ind:state state_ref="state_grub2_{{{ SANITIZED_ARG_NAME }}}_argument" />
+  </ind:textfilecontent54_test>
+
+  <ind:textfilecontent54_test id="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_default_configdir"
+  comment="check for {{{ ARG_NAME_VALUE }}} in /etc/default/grub via GRUB_CMDLINE_LINUX_DEFAULT"
+  check="all" check_existence="all_exist" version="1">
+    <ind:object object_ref="object_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_default_configdir" />
+    <ind:state state_ref="state_grub2_{{{ SANITIZED_ARG_NAME }}}_argument" />
+  </ind:textfilecontent54_test>
+
+  <ind:textfilecontent54_object id="object_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_configdir" version="1">
+    <ind:filepath>/etc/default/grub.d/*.cfg</ind:filepath>
+    <ind:pattern operation="pattern match">^\s*GRUB_CMDLINE_LINUX="(.*)"$</ind:pattern>
+    <ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
+  </ind:textfilecontent54_object>
+
+  <ind:textfilecontent54_object id="object_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_default_configdir"
+  version="1">
+    <ind:filepath>/etc/default/grub.d/*.cfg</ind:filepath>
     <ind:pattern operation="pattern match">^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$</ind:pattern>
     <ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
   </ind:textfilecontent54_object>
diff --git a/shared/templates/grub2_bootloader_argument/tests/correct_value_configdir.pass.sh b/shared/templates/grub2_bootloader_argument/tests/correct_value_configdir.pass.sh
index 734142a4e3a..4a74b29a467 100644
--- a/shared/templates/grub2_bootloader_argument/tests/correct_value_configdir.pass.sh
+++ b/shared/templates/grub2_bootloader_argument/tests/correct_value_configdir.pass.sh
@@ -10,7 +10,7 @@
 
 source common.sh
 
-echo > /etc/default/grub
+echo "GRUB_CMDLINE_LINUX=\"\"" > /etc/default/grub
 rm -f /etc/default/grub.d/*
 
 echo "GRUB_CMDLINE_LINUX=\"\$GRUB_CMDLINE_LINUX {{{ ARG_NAME_VALUE }}}\"" > /etc/default/grub.d/custom.cfg