Linux 6.7-rc7
[linux-modified.git] / tools / crypto / ccp / test_dbc.py
1 #!/usr/bin/python3
2 # SPDX-License-Identifier: GPL-2.0
3 import unittest
4 import os
5 import time
6 import glob
7 import fcntl
8 try:
9     import ioctl_opt as ioctl
10 except ImportError:
11     ioctl = None
12     pass
13 from dbc import *
14
15 # Artificial delay between set commands
16 SET_DELAY = 0.5
17
18
19 class invalid_param(ctypes.Structure):
20     _fields_ = [
21         ("data", ctypes.c_uint8),
22     ]
23
24
25 def system_is_secured() -> bool:
26     fused_part = glob.glob("/sys/bus/pci/drivers/ccp/**/fused_part")[0]
27     if os.path.exists(fused_part):
28         with open(fused_part, "r") as r:
29             return int(r.read()) == 1
30     return True
31
32
33 class DynamicBoostControlTest(unittest.TestCase):
34     def __init__(self, data) -> None:
35         self.d = None
36         self.signature = b"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
37         self.uid = b"1111111111111111"
38         super().__init__(data)
39
40     def setUp(self) -> None:
41         self.d = open(DEVICE_NODE)
42         return super().setUp()
43
44     def tearDown(self) -> None:
45         if self.d:
46             self.d.close()
47         return super().tearDown()
48
49
50 class TestUnsupportedSystem(DynamicBoostControlTest):
51     def setUp(self) -> None:
52         if os.path.exists(DEVICE_NODE):
53             self.skipTest("system is supported")
54         with self.assertRaises(FileNotFoundError) as error:
55             super().setUp()
56         self.assertEqual(error.exception.errno, 2)
57
58     def test_unauthenticated_nonce(self) -> None:
59         """fetch unauthenticated nonce"""
60         with self.assertRaises(ValueError) as error:
61             get_nonce(self.d, None)
62
63
64 class TestInvalidIoctls(DynamicBoostControlTest):
65     def __init__(self, data) -> None:
66         self.data = invalid_param()
67         self.data.data = 1
68         super().__init__(data)
69
70     def setUp(self) -> None:
71         if not os.path.exists(DEVICE_NODE):
72             self.skipTest("system is unsupported")
73         if not ioctl:
74             self.skipTest("unable to test IOCTLs without ioctl_opt")
75
76         return super().setUp()
77
78     def test_invalid_nonce_ioctl(self) -> None:
79         """tries to call get_nonce ioctl with invalid data structures"""
80
81         # 0x1 (get nonce), and invalid data
82         INVALID1 = ioctl.IOWR(ord("D"), 0x01, invalid_param)
83         with self.assertRaises(OSError) as error:
84             fcntl.ioctl(self.d, INVALID1, self.data, True)
85         self.assertEqual(error.exception.errno, 22)
86
87     def test_invalid_setuid_ioctl(self) -> None:
88         """tries to call set_uid ioctl with invalid data structures"""
89
90         # 0x2 (set uid), and invalid data
91         INVALID2 = ioctl.IOW(ord("D"), 0x02, invalid_param)
92         with self.assertRaises(OSError) as error:
93             fcntl.ioctl(self.d, INVALID2, self.data, True)
94         self.assertEqual(error.exception.errno, 22)
95
96     def test_invalid_setuid_rw_ioctl(self) -> None:
97         """tries to call set_uid ioctl with invalid data structures"""
98
99         # 0x2 as RW (set uid), and invalid data
100         INVALID3 = ioctl.IOWR(ord("D"), 0x02, invalid_param)
101         with self.assertRaises(OSError) as error:
102             fcntl.ioctl(self.d, INVALID3, self.data, True)
103         self.assertEqual(error.exception.errno, 22)
104
105     def test_invalid_param_ioctl(self) -> None:
106         """tries to call param ioctl with invalid data structures"""
107         # 0x3 (param), and invalid data
108         INVALID4 = ioctl.IOWR(ord("D"), 0x03, invalid_param)
109         with self.assertRaises(OSError) as error:
110             fcntl.ioctl(self.d, INVALID4, self.data, True)
111         self.assertEqual(error.exception.errno, 22)
112
113     def test_invalid_call_ioctl(self) -> None:
114         """tries to call the DBC ioctl with invalid data structures"""
115         # 0x4, and invalid data
116         INVALID5 = ioctl.IOWR(ord("D"), 0x04, invalid_param)
117         with self.assertRaises(OSError) as error:
118             fcntl.ioctl(self.d, INVALID5, self.data, True)
119         self.assertEqual(error.exception.errno, 22)
120
121
122 class TestInvalidSignature(DynamicBoostControlTest):
123     def setUp(self) -> None:
124         if not os.path.exists(DEVICE_NODE):
125             self.skipTest("system is unsupported")
126         if not system_is_secured():
127             self.skipTest("system is unfused")
128         return super().setUp()
129
130     def test_unauthenticated_nonce(self) -> None:
131         """fetch unauthenticated nonce"""
132         get_nonce(self.d, None)
133
134     def test_multiple_unauthenticated_nonce(self) -> None:
135         """ensure state machine always returns nonce"""
136         for count in range(0, 2):
137             get_nonce(self.d, None)
138
139     def test_authenticated_nonce(self) -> None:
140         """fetch authenticated nonce"""
141         with self.assertRaises(OSError) as error:
142             get_nonce(self.d, self.signature)
143         self.assertEqual(error.exception.errno, 1)
144
145     def test_set_uid(self) -> None:
146         """set uid"""
147         with self.assertRaises(OSError) as error:
148             set_uid(self.d, self.uid, self.signature)
149         self.assertEqual(error.exception.errno, 1)
150
151     def test_get_param(self) -> None:
152         """fetch a parameter"""
153         with self.assertRaises(OSError) as error:
154             process_param(self.d, PARAM_GET_SOC_PWR_CUR, self.signature)
155         self.assertEqual(error.exception.errno, 1)
156
157     def test_set_param(self) -> None:
158         """set a parameter"""
159         with self.assertRaises(OSError) as error:
160             process_param(self.d, PARAM_SET_PWR_CAP, self.signature, 1000)
161         self.assertEqual(error.exception.errno, 1)
162
163
164 class TestUnFusedSystem(DynamicBoostControlTest):
165     def setup_identity(self) -> None:
166         """sets up the identity of the caller"""
167         # if already authenticated these may fail
168         try:
169             get_nonce(self.d, None)
170         except PermissionError:
171             pass
172         try:
173             set_uid(self.d, self.uid, self.signature)
174         except BlockingIOError:
175             pass
176         try:
177             get_nonce(self.d, self.signature)
178         except PermissionError:
179             pass
180
181     def setUp(self) -> None:
182         if not os.path.exists(DEVICE_NODE):
183             self.skipTest("system is unsupported")
184         if system_is_secured():
185             self.skipTest("system is fused")
186         super().setUp()
187         self.setup_identity()
188         time.sleep(SET_DELAY)
189
190     def test_get_valid_param(self) -> None:
191         """fetch all possible parameters"""
192         # SOC power
193         soc_power_max = process_param(self.d, PARAM_GET_SOC_PWR_MAX, self.signature)
194         soc_power_min = process_param(self.d, PARAM_GET_SOC_PWR_MIN, self.signature)
195         self.assertGreater(soc_power_max[0], soc_power_min[0])
196
197         # fmax
198         fmax_max = process_param(self.d, PARAM_GET_FMAX_MAX, self.signature)
199         fmax_min = process_param(self.d, PARAM_GET_FMAX_MIN, self.signature)
200         self.assertGreater(fmax_max[0], fmax_min[0])
201
202         # cap values
203         keys = {
204             "fmax-cap": PARAM_GET_FMAX_CAP,
205             "power-cap": PARAM_GET_PWR_CAP,
206             "current-temp": PARAM_GET_CURR_TEMP,
207             "soc-power-cur": PARAM_GET_SOC_PWR_CUR,
208         }
209         for k in keys:
210             result = process_param(self.d, keys[k], self.signature)
211             self.assertGreater(result[0], 0)
212
213     def test_get_invalid_param(self) -> None:
214         """fetch an invalid parameter"""
215         try:
216             set_uid(self.d, self.uid, self.signature)
217         except OSError:
218             pass
219         with self.assertRaises(OSError) as error:
220             process_param(self.d, (0xF,), self.signature)
221         self.assertEqual(error.exception.errno, 22)
222
223     def test_set_fmax(self) -> None:
224         """get/set fmax limit"""
225         # fetch current
226         original = process_param(self.d, PARAM_GET_FMAX_CAP, self.signature)
227
228         # set the fmax
229         target = original[0] - 100
230         process_param(self.d, PARAM_SET_FMAX_CAP, self.signature, target)
231         time.sleep(SET_DELAY)
232         new = process_param(self.d, PARAM_GET_FMAX_CAP, self.signature)
233         self.assertEqual(new[0], target)
234
235         # revert back to current
236         process_param(self.d, PARAM_SET_FMAX_CAP, self.signature, original[0])
237         time.sleep(SET_DELAY)
238         cur = process_param(self.d, PARAM_GET_FMAX_CAP, self.signature)
239         self.assertEqual(cur[0], original[0])
240
241     def test_set_power_cap(self) -> None:
242         """get/set power cap limit"""
243         # fetch current
244         original = process_param(self.d, PARAM_GET_PWR_CAP, self.signature)
245
246         # set the fmax
247         target = original[0] - 10
248         process_param(self.d, PARAM_SET_PWR_CAP, self.signature, target)
249         time.sleep(SET_DELAY)
250         new = process_param(self.d, PARAM_GET_PWR_CAP, self.signature)
251         self.assertEqual(new[0], target)
252
253         # revert back to current
254         process_param(self.d, PARAM_SET_PWR_CAP, self.signature, original[0])
255         time.sleep(SET_DELAY)
256         cur = process_param(self.d, PARAM_GET_PWR_CAP, self.signature)
257         self.assertEqual(cur[0], original[0])
258
259     def test_set_3d_graphics_mode(self) -> None:
260         """set/get 3d graphics mode"""
261         # these aren't currently implemented but may be some day
262         # they are *expected* to fail
263         with self.assertRaises(OSError) as error:
264             process_param(self.d, PARAM_GET_GFX_MODE, self.signature)
265         self.assertEqual(error.exception.errno, 2)
266
267         time.sleep(SET_DELAY)
268
269         with self.assertRaises(OSError) as error:
270             process_param(self.d, PARAM_SET_GFX_MODE, self.signature, 1)
271         self.assertEqual(error.exception.errno, 2)
272
273
274 if __name__ == "__main__":
275     unittest.main()