<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>This feature looks like a great addition, however, giving how
      critical the ubuntu_boot a-c-t is (This test is now a gate for
      initial kernel builds), we need to be careful how we update it. <br>
    </p>
    <p>Upon testing this patch against a test harness using Focal amd64
      vm:</p>
    <p><br>
    </p>
    <pre style="box-sizing: inherit; font-family: monospace, monospace; font-size: 14px; direction: ltr; hyphens: none; tab-size: 4; word-spacing: 0px; overflow-wrap: break-word; background-color: rgb(247, 247, 247); border: 1px solid rgb(205, 205, 205); border-radius: 0.125rem; color: rgb(17, 17, 17); display: block; margin-bottom: 1.5rem; margin-top: 0px; overflow: auto; padding: 0px; text-align: left; text-shadow: none; white-space: pre; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 300; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><span id="line-number-83" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">01:08:17 INFO |  START   ubuntu_boot.kernel_revocation_list      ubuntu_boot.kernel_revocation_list      timestamp=1627520897    timeout=300     localtime=Jul 29 01:08:17       
</span><span id="line-number-84" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">01:08:17 DEBUG| Persistent state client._record_indent now set to 2
</span><span id="line-number-85" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">01:08:17 DEBUG| Persistent state client.unexpected_reboot now set to ('ubuntu_boot.kernel_revocation_list', 'ubuntu_boot.kernel_revocation_list')
</span><span id="line-number-86" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">01:08:17 DEBUG| Waiting for pid 2357 for 300 seconds
</span><span id="line-number-87" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">01:08:17 WARNI| System python is too old, crash handling disabled
</span><span id="line-number-88" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">01:08:17 ERROR| Exception escaping from test:
</span><span id="line-number-89" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">Traceback (most recent call last):
</span><span id="line-number-90" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">  File "/home/ubuntu/autotest/client/shared/test.py", line 411, in _exec
</span><span id="line-number-91" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">    _call_test_function(self.execute, *p_args, **p_dargs)
</span><span id="line-number-92" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">  File "/home/ubuntu/autotest/client/shared/test.py", line 830, in _call_test_function
</span><span id="line-number-93" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">    raise error.UnhandledTestFail(e)
</span><span id="line-number-94" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">UnhandledTestFail: Unhandled AttributeError: 'tuple' object has no attribute 'release'
</span><span id="line-number-95" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">Traceback (most recent call last):
</span><span id="line-number-96" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">  File "/home/ubuntu/autotest/client/shared/test.py", line 823, in _call_test_function
</span><span id="line-number-97" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">    return func(*args, **dargs)
</span><span id="line-number-98" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">  File "/home/ubuntu/autotest/client/shared/test.py", line 291, in execute
</span><span id="line-number-99" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">    postprocess_profiled_run, args, dargs)
</span><span id="line-number-100" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">  File "/home/ubuntu/autotest/client/shared/test.py", line 212, in _call_run_once
</span><span id="line-number-101" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">    self.run_once(*args, **dargs)
</span><span id="line-number-102" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">  File "/home/ubuntu/autotest/client/tests/ubuntu_boot/ubuntu_boot.py", line 97, in run_once
</span><span id="line-number-103" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">    self.kernel_revocation_list()
</span><span id="line-number-104" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">  File "/home/ubuntu/autotest/client/tests/ubuntu_boot/ubuntu_boot.py", line 60, in kernel_revocation_list
</span><span id="line-number-105" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">    config_file = "/boot/config-" + os.uname().release
</span><span id="line-number-106" style="box-sizing: inherit; counter-increment: line 1; position: relative; width: 100%;">AttributeError: 'tuple' object has no attribute 'release'</span></pre>
    <p>Full output here: <a class="moz-txt-link-freetext" href="https://pastebin.canonical.com/p/Zr2jjzsNcr/">https://pastebin.canonical.com/p/Zr2jjzsNcr/</a><br>
    </p>
    <p>Unfortunately autotest only supports python2, which is why this
      dumped an Exception, there is no os.uname().release. I think the
      best way to handle this:</p>
    <p>1.) Re-write it all for python2 (no one wants to do that)</p>
    <p>2.) Isolate the function into it's own py3 script and call it
      from ubuntu_boot.py using something like, utils.system('python3
      <my_python3_script>' ).</p>
    <p>This is probably the easiest, any errors that are returned from
      the python3 script can be handled in "ubuntu_boot.py" using the
      autotest.client library.</p>
    <p>-Sean<br>
    </p>
    <br>
    <div class="moz-cite-prefix">On 7/28/21 12:27 PM, Dimitri John
      Ledkov wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:20210728162716.79507-1-dimitri.ledkov@canonical.com">
      <pre class="moz-quote-pre" wrap="">Implement revocation list checks. If kernel supports revocation lists,
check that 2012 canonical signing key is revoked.

Most kernels will skip this test, those kernels that have support for
revocation lists will check that it is correctly configured and
visible at runtime.

Signed-off-by: Dimitri John Ledkov <a class="moz-txt-link-rfc2396E" href="mailto:dimitri.ledkov@canonical.com"><dimitri.ledkov@canonical.com></a>
---

 Note, tested the function in question partially on v5.10 and v5.13
 kernels. I failed at using the test harness directly to partially
 execute this test case alone. Thus I am not sure if it runs with
 python3 or python2, as I was getting exceptions raised from autotest
 itself.

 ubuntu_boot/control.ubuntu |  1 +
 ubuntu_boot/ubuntu_boot.py | 30 +++++++++++++++++++++++++++++-
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/ubuntu_boot/control.ubuntu b/ubuntu_boot/control.ubuntu
index f73d68c2d3..5f4e3a29bd 100644
--- a/ubuntu_boot/control.ubuntu
+++ b/ubuntu_boot/control.ubuntu
@@ -11,3 +11,4 @@ DOC = '''
 job.run_test_detail('ubuntu_boot', test_name='log_check', tag='log_check', timeout=60*5)
 job.run_test_detail('ubuntu_boot', test_name='boot_smoke_test', tag='boot_smoke_test', timeout=60*5)
 job.run_test_detail('ubuntu_boot', test_name='kernel_tainted', tag='kernel_tainted', timeout=60*5)
+job.run_test_detail('ubuntu_boot', test_name='kernel_revocation_list', tag='kernel_revocation_list', timeout=60*5)
diff --git a/ubuntu_boot/ubuntu_boot.py b/ubuntu_boot/ubuntu_boot.py
index a67f21d49f..a986210ad3 100644
--- a/ubuntu_boot/ubuntu_boot.py
+++ b/ubuntu_boot/ubuntu_boot.py
@@ -8,7 +8,7 @@ from autotest.client.shared import error
 class ubuntu_boot(test.test):
     version = 1
     def setup(self):
-        pkgs = [ 'python3' ]
+        pkgs = [ 'python3', 'keyutils' ]
         cmd = 'yes "" | DEBIAN_FRONTEND=noninteractive apt-get install --yes --force-yes ' + ' '.join(pkgs)
         self.results = utils.system_output(cmd, retain_output=True)
 
@@ -58,6 +58,31 @@ class ubuntu_boot(test.test):
         result = utils.system('python3 %s/kernel_taint_test.py' % self.bindir, ignore_status=True)
         return result
 
+    def kernel_revocation_list(self):
+        '''Test for kernel builtin revoked keys'''
+        config_file = "/boot/config-" + os.uname().release
+        revocation_list_available = False
+        for line in open(config_file):
+            if re.search("CONFIG_SYSTEM_REVOCATION_LIST", line):
+                revocation_list_available = True
+                break
+        if not revocation_list_available:
+            print('SKIP: Kernel Revocation List NA.')
+            raise error.TestNAError()
+        revocations = utils.system_output("keyctl list %:.blacklist", retain_output=True)
+        patterns = [
+            b'.* asymmetric: Canonical Ltd. Secure Boot Signing: 61482aa2830d0ab2ad5af10b7250da9033ddcef0',
+        ]
+        missing_patterns = False
+        for pat in patterns:
+            print('Scanning for pattern "{}"'.format(pat))
+            if not re.search(pat, revocations):
+                print('Pattern not found.')
+                missing_patterns = True
+        if missing_patterns:
+            raise error.TestFail()
+        print('GOOD: Kernel Revocation List.')
+
     def run_once(self, test_name, exit_on_error=True):
         if test_name == 'log_check':
             if not self.log_check():
@@ -71,6 +96,9 @@ class ubuntu_boot(test.test):
             else:
                 print('GOOD: Kernel not tainted.')
             return
+        elif test_name == 'kernel_revocation_list':
+            self.kernel_revocation_list()
+            return
 
         cmd = "uname -a"
         utils.system(cmd)
</pre>
    </blockquote>
  </body>
</html>