1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2018 Michael Moese <mmoese@suse.com>
4 * Copyright (c) Linux Test Project, 2020
5 */
6
7 #define TST_NO_DEFAULT_MAIN
8
9 #include "tst_test.h"
10 #include "tst_taint.h"
11 #include "tst_safe_stdio.h"
12
13 #define TAINT_FILE "/proc/sys/kernel/tainted"
14
15 static unsigned int taint_mask = -1;
16
tst_taint_read(void)17 static unsigned int tst_taint_read(void)
18 {
19 unsigned int val;
20
21 SAFE_FILE_SCANF(TAINT_FILE, "%u", &val);
22
23 return val;
24 }
25
tst_taint_check_kver(unsigned int mask)26 static int tst_taint_check_kver(unsigned int mask)
27 {
28 int r1;
29 int r2;
30 int r3 = 0;
31
32 if (mask & TST_TAINT_X) {
33 r1 = 4;
34 r2 = 15;
35 } else if (mask & TST_TAINT_K) {
36 r1 = 4;
37 r2 = 0;
38 } else if (mask & TST_TAINT_L) {
39 r1 = 3;
40 r2 = 17;
41 } else if (mask & TST_TAINT_E) {
42 r1 = 3;
43 r2 = 15;
44 } else if (mask & TST_TAINT_O) {
45 r1 = 3;
46 r2 = 2;
47 } else if (mask & TST_TAINT_I) {
48 r1 = 2;
49 r2 = 6;
50 r3 = 35;
51 } else if (mask & TST_TAINT_C) {
52 r1 = 2;
53 r2 = 6;
54 r3 = 28;
55 } else if (mask & TST_TAINT_W) {
56 r1 = 2;
57 r2 = 6;
58 r3 = 26;
59 } else if (mask & TST_TAINT_A) {
60 r1 = 2;
61 r2 = 6;
62 r3 = 25;
63 } else if (mask & TST_TAINT_D) {
64 r1 = 2;
65 r2 = 6;
66 r3 = 23;
67 } else if (mask & TST_TAINT_U) {
68 r1 = 2;
69 r2 = 6;
70 r3 = 21;
71 } else {
72 r1 = 2;
73 r2 = 6;
74 r3 = 16;
75 }
76
77 return tst_kvercmp(r1, r2, r3);
78 }
79
tst_taint_init(unsigned int mask)80 void tst_taint_init(unsigned int mask)
81 {
82 unsigned int taint = -1;
83
84 if (mask == 0)
85 tst_brk(TBROK, "mask is not allowed to be 0");
86
87 if (tst_taint_check_kver(mask) < 0)
88 tst_res(TCONF, "Kernel is too old for requested mask");
89
90 taint_mask = mask;
91 taint = tst_taint_read();
92
93 if (taint & TST_TAINT_W) {
94 tst_res(TCONF, "Ignoring already set kernel warning taint");
95 taint_mask &= ~TST_TAINT_W;
96 }
97
98 if ((taint & taint_mask) != 0)
99 tst_brk(TBROK, "Kernel is already tainted: %u", taint);
100 }
101
102
tst_taint_check(void)103 unsigned int tst_taint_check(void)
104 {
105 unsigned int taint = -1;
106
107 if (taint_mask == (unsigned int) -1)
108 tst_brk(TBROK, "need to call tst_taint_init() first");
109
110 taint = tst_taint_read();
111
112 return (taint & taint_mask);
113 }
114