Merge ~rodsmith/plainbox-provider-checkbox:add-kernel-taint-test into plainbox-provider-checkbox:master

Proposed by Rod Smith
Status: Merged
Approved by: Rod Smith
Approved revision: a4f1ad75ed26528c5ebed659d31ee82bde1bce9f
Merged at revision: 2bf46bc0f2eee0aad571d4541a76bf8a4d4eb1ea
Proposed branch: ~rodsmith/plainbox-provider-checkbox:add-kernel-taint-test
Merge into: plainbox-provider-checkbox:master
Diff against target: 132 lines (+104/-0)
3 files modified
bin/kernel_taint_test (+93/-0)
units/miscellanea/jobs.pxu (+10/-0)
units/miscellanea/test-plan.pxu (+1/-0)
Reviewer Review Type Date Requested Status
Sylvain Pineau (community) Approve
Jeff Lane  Pending
Review via email: mp+374249@code.launchpad.net

Commit message

Adds kernel taint test to Checkbox.

Description of the change

This adds the kernel taint test discussed at the Paris sprint. It checks /proc/sys/kernel/tainted and passes (return code 0) if that file contains a "0" value, or fails (return code 1) on any other value or if the file doesn't exist. In case of a failure, it presents information on the nature of the failure, as in:

Kernel taint value is 12289
Taint bit value: 0 (proprietary module was loaded)
Taint bit value: 12 (externally-built ('out-of-tree') module was loaded)
Taint bit value: 13 (unsigned module was loaded)

A passing result is here:

https://certification.canonical.com/hardware/201908-27304/submission/152762/

...specifically:

https://certification.canonical.com/hardware/201908-27304/submission/152762/test/84909/result/11550849/

I've added this as a non-blocking test to the server miscellanea tests.

The kernel_taint_test script requires no options; however, --taint-file may be used to specify a file other than /proc/sys/kernel/tainted from which to read the taint value. This is intended for testing, debugging, and development of the script itself.

To post a comment you must log in.
Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/bin/kernel_taint_test b/bin/kernel_taint_test
2new file mode 100755
3index 0000000..976ccb6
4--- /dev/null
5+++ b/bin/kernel_taint_test
6@@ -0,0 +1,93 @@
7+#!/usr/bin/env python3
8+"""
9+Test that the kernel is not "tainted" by out-of-tree drivers, etc.
10+
11+Copyright (C) 2019 Canonical Ltd.
12+
13+Authors:
14+ Rod Smith <rod.smith@canonical.com>
15+
16+This program is free software: you can redistribute it and/or modify
17+it under the terms of the GNU General Public License version 3,
18+as published by the Free Software Foundation.
19+
20+This program is distributed in the hope that it will be useful,
21+but WITHOUT ANY WARRANTY; without even the implied warranty of
22+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23+GNU General Public License for more details.
24+
25+You should have received a copy of the GNU General Public License
26+along with this program. If not, see <http://www.gnu.org/licenses/>.
27+
28+This script examines the /proc/sys/kernel/tainted file (or a user-specified
29+file, for debugging purposes) and parses the contents to determine if the
30+kernel is tainted. If so, the script reports the nature of the taint and
31+returns a value of 1. The script also returns a value of 1 if
32+# /proc/sys/kernel/tainted cannot be found or opened. If the kernel is NOT
33+# tainted, the script notes this fact and returns 0.
34+"""
35+
36+
37+import sys
38+from argparse import ArgumentParser
39+
40+
41+# Note: If max_taints is increased, add descriptions to taint_meanings in
42+# report_failures()
43+max_taints = 17
44+
45+
46+def find_taints(taint_file):
47+ """Read the kernel-taint file."""
48+ try:
49+ f = open(taint_file, "r")
50+ taints = int(f.read())
51+ except OSError:
52+ taints = 2**(max_taints+1) # Set so we have a non-0 value to return
53+ print("Kernel taint file ({}) not found!".format(taint_file))
54+ print("Kernel taint value is {}".format(taints))
55+ return(taints)
56+
57+
58+def report_failures(taints):
59+ """Report the failure code and its meaning(s)."""
60+ # Below meaning strings are taken from
61+ # https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html
62+ taint_meanings = ["proprietary module was loaded",
63+ "module was force loaded",
64+ "SMP kernel oops on an officially SMP incapable CPU",
65+ "module was force unloaded",
66+ "processor reported a Machine Check Exception (MCE)",
67+ "bad page referenced or some unexpected page flags",
68+ "taint requested by userspace application",
69+ "kernel died recently, i.e. there was an OOPS or BUG",
70+ "ACPI table overridden by user",
71+ "kernel issued warning",
72+ "staging driver was loaded",
73+ "workaround for bug in platform firmware applied",
74+ "externally-built ('out-of-tree') module was loaded",
75+ "unsigned module was loaded",
76+ "soft lockup occurred",
77+ "kernel has been live patched",
78+ "auxiliary taint, defined for and used by distros",
79+ "kernel was built with the struct randomization plugin"]
80+ for i in range(max_taints+1):
81+ if (taints & (2 ** i)):
82+ print("Taint bit value: {} ({})".format(i, taint_meanings[i]))
83+ if taints == 0:
84+ print("No kernel taints detected.")
85+
86+
87+def main():
88+ parser = ArgumentParser()
89+ parser.add_argument('--taint-file',
90+ default="/proc/sys/kernel/tainted",
91+ help='The file that holds the taint information')
92+ args = parser.parse_args()
93+ taints = find_taints(args.taint_file)
94+ report_failures(taints)
95+ return(taints > 0)
96+
97+
98+if __name__ == '__main__':
99+ sys.exit(main())
100diff --git a/units/miscellanea/jobs.pxu b/units/miscellanea/jobs.pxu
101index 41c9253..bbb28bf 100644
102--- a/units/miscellanea/jobs.pxu
103+++ b/units/miscellanea/jobs.pxu
104@@ -190,6 +190,16 @@ command: check-prerelease
105
106 plugin: shell
107 category_id: com.canonical.plainbox::miscellanea
108+estimated_duration: 0.5
109+id: miscellanea/kernel_taint_test
110+_summary: Test that kernel is not tainted
111+_description:
112+ Test to verify that the kernel is not tainted by out-of-tree
113+ drivers, live patches, proprietary modules, etc.
114+command: kernel_taint_test
115+
116+plugin: shell
117+category_id: com.canonical.plainbox::miscellanea
118 id: miscellanea/bmc_info
119 requires:
120 package.name == 'ipmitool' or executable.name == 'ipmitool'
121diff --git a/units/miscellanea/test-plan.pxu b/units/miscellanea/test-plan.pxu
122index 1b119f1..5f7258d 100644
123--- a/units/miscellanea/test-plan.pxu
124+++ b/units/miscellanea/test-plan.pxu
125@@ -67,6 +67,7 @@ mandatory_include:
126 miscellanea/secure_boot_mode
127 miscellanea/efi_pxeboot
128 miscellanea/check_prerelease
129+ miscellanea/kernel_taint_test
130 miscellanea/cpus_are_not_samples
131 miscellanea/ipmi_test certification-status=blocker
132 miscellanea/bmc_info

Subscribers

People subscribed via source and target branches