Skip to content

Commit 10ca05a

Browse files
bowerscd-corppcmoore
authored andcommitted
ipe: kunit test for parser
Add various happy/unhappy unit tests for both IPE's policy parser. Besides, a test suite for IPE functionality is available at https://github.com/microsoft/ipe/tree/test-suite Signed-off-by: Deven Bowers <[email protected]> Signed-off-by: Fan Wu <[email protected]> Signed-off-by: Paul Moore <[email protected]>
1 parent ba199dc commit 10ca05a

File tree

3 files changed

+316
-0
lines changed

3 files changed

+316
-0
lines changed

security/ipe/Kconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,21 @@ config IPE_PROP_FS_VERITY_BUILTIN_SIG
7777

7878
endmenu
7979

80+
config SECURITY_IPE_KUNIT_TEST
81+
bool "Build KUnit tests for IPE" if !KUNIT_ALL_TESTS
82+
depends on KUNIT=y
83+
default KUNIT_ALL_TESTS
84+
help
85+
This builds the IPE KUnit tests.
86+
87+
KUnit tests run during boot and output the results to the debug log
88+
in TAP format (https://testanything.org/). Only useful for kernel devs
89+
running KUnit test harness and are not for inclusion into a
90+
production build.
91+
92+
For more information on KUnit and unit tests in general please refer
93+
to the KUnit documentation in Documentation/dev-tools/kunit/.
94+
95+
If unsure, say N.
96+
8097
endif

security/ipe/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,6 @@ obj-$(CONFIG_SECURITY_IPE) += \
2626
audit.o \
2727

2828
clean-files := boot_policy.c \
29+
30+
obj-$(CONFIG_SECURITY_IPE_KUNIT_TEST) += \
31+
policy_tests.o \

security/ipe/policy_tests.c

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.
4+
*/
5+
6+
#include <linux/slab.h>
7+
#include <linux/types.h>
8+
#include <linux/list.h>
9+
#include <kunit/test.h>
10+
#include "policy.h"
11+
struct policy_case {
12+
const char *const policy;
13+
int errno;
14+
const char *const desc;
15+
};
16+
17+
static const struct policy_case policy_cases[] = {
18+
{
19+
"policy_name=allowall policy_version=0.0.0\n"
20+
"DEFAULT action=ALLOW",
21+
0,
22+
"basic",
23+
},
24+
{
25+
"policy_name=trailing_comment policy_version=152.0.0 #This is comment\n"
26+
"DEFAULT action=ALLOW",
27+
0,
28+
"trailing comment",
29+
},
30+
{
31+
"policy_name=allowallnewline policy_version=0.2.0\n"
32+
"DEFAULT action=ALLOW\n"
33+
"\n",
34+
0,
35+
"trailing newline",
36+
},
37+
{
38+
"policy_name=carriagereturnlinefeed policy_version=0.0.1\n"
39+
"DEFAULT action=ALLOW\n"
40+
"\r\n",
41+
0,
42+
"clrf newline",
43+
},
44+
{
45+
"policy_name=whitespace policy_version=0.0.0\n"
46+
"DEFAULT\taction=ALLOW\n"
47+
" \t DEFAULT \t op=EXECUTE action=DENY\n"
48+
"op=EXECUTE boot_verified=TRUE action=ALLOW\n"
49+
"# this is a\tcomment\t\t\t\t\n"
50+
"DEFAULT \t op=KMODULE\t\t\t action=DENY\r\n"
51+
"op=KMODULE boot_verified=TRUE action=ALLOW\n",
52+
0,
53+
"various whitespaces and nested default",
54+
},
55+
{
56+
"policy_name=boot_verified policy_version=-1236.0.0\n"
57+
"DEFAULT\taction=ALLOW\n",
58+
-EINVAL,
59+
"negative version",
60+
},
61+
{
62+
"policy_name=$@!*&^%%\\:;{}() policy_version=0.0.0\n"
63+
"DEFAULT action=ALLOW",
64+
0,
65+
"special characters",
66+
},
67+
{
68+
"policy_name=test policy_version=999999.0.0\n"
69+
"DEFAULT action=ALLOW",
70+
-ERANGE,
71+
"overflow version",
72+
},
73+
{
74+
"policy_name=test policy_version=255.0\n"
75+
"DEFAULT action=ALLOW",
76+
-EBADMSG,
77+
"incomplete version",
78+
},
79+
{
80+
"policy_name=test policy_version=111.0.0.0\n"
81+
"DEFAULT action=ALLOW",
82+
-EBADMSG,
83+
"extra version",
84+
},
85+
{
86+
"",
87+
-EBADMSG,
88+
"0-length policy",
89+
},
90+
{
91+
"policy_name=test\0policy_version=0.0.0\n"
92+
"DEFAULT action=ALLOW",
93+
-EBADMSG,
94+
"random null in header",
95+
},
96+
{
97+
"policy_name=test policy_version=0.0.0\n"
98+
"\0DEFAULT action=ALLOW",
99+
-EBADMSG,
100+
"incomplete policy from NULL",
101+
},
102+
{
103+
"policy_name=test policy_version=0.0.0\n"
104+
"DEFAULT action=DENY\n\0"
105+
"op=EXECUTE dmverity_signature=TRUE action=ALLOW\n",
106+
0,
107+
"NULL truncates policy",
108+
},
109+
{
110+
"policy_name=test policy_version=0.0.0\n"
111+
"DEFAULT action=ALLOW\n"
112+
"op=EXECUTE dmverity_signature=abc action=ALLOW",
113+
-EBADMSG,
114+
"invalid property type",
115+
},
116+
{
117+
"DEFAULT action=ALLOW",
118+
-EBADMSG,
119+
"missing policy header",
120+
},
121+
{
122+
"policy_name=test policy_version=0.0.0\n",
123+
-EBADMSG,
124+
"missing default definition",
125+
},
126+
{
127+
"policy_name=test policy_version=0.0.0\n"
128+
"DEFAULT action=ALLOW\n"
129+
"dmverity_signature=TRUE op=EXECUTE action=ALLOW",
130+
-EBADMSG,
131+
"invalid rule ordering"
132+
},
133+
{
134+
"policy_name=test policy_version=0.0.0\n"
135+
"DEFAULT action=ALLOW\n"
136+
"action=ALLOW op=EXECUTE dmverity_signature=TRUE",
137+
-EBADMSG,
138+
"invalid rule ordering (2)",
139+
},
140+
{
141+
"policy_name=test policy_version=0.0\n"
142+
"DEFAULT action=ALLOW\n"
143+
"op=EXECUTE dmverity_signature=TRUE action=ALLOW",
144+
-EBADMSG,
145+
"invalid version",
146+
},
147+
{
148+
"policy_name=test policy_version=0.0.0\n"
149+
"DEFAULT action=ALLOW\n"
150+
"op=UNKNOWN dmverity_signature=TRUE action=ALLOW",
151+
-EBADMSG,
152+
"unknown operation",
153+
},
154+
{
155+
"policy_name=asdvpolicy_version=0.0.0\n"
156+
"DEFAULT action=ALLOW\n",
157+
-EBADMSG,
158+
"missing space after policy name",
159+
},
160+
{
161+
"policy_name=test\xFF\xEF policy_version=0.0.0\n"
162+
"DEFAULT action=ALLOW\n"
163+
"op=EXECUTE dmverity_signature=TRUE action=ALLOW",
164+
0,
165+
"expanded ascii",
166+
},
167+
{
168+
"policy_name=test\xFF\xEF policy_version=0.0.0\n"
169+
"DEFAULT action=ALLOW\n"
170+
"op=EXECUTE dmverity_roothash=GOOD_DOG action=ALLOW",
171+
-EBADMSG,
172+
"invalid property value (2)",
173+
},
174+
{
175+
"policy_name=test policy_version=0.0.0\n"
176+
"policy_name=test policy_version=0.1.0\n"
177+
"DEFAULT action=ALLOW",
178+
-EBADMSG,
179+
"double header"
180+
},
181+
{
182+
"policy_name=test policy_version=0.0.0\n"
183+
"DEFAULT action=ALLOW\n"
184+
"DEFAULT action=ALLOW\n",
185+
-EBADMSG,
186+
"double default"
187+
},
188+
{
189+
"policy_name=test policy_version=0.0.0\n"
190+
"DEFAULT action=ALLOW\n"
191+
"DEFAULT op=EXECUTE action=DENY\n"
192+
"DEFAULT op=EXECUTE action=ALLOW\n",
193+
-EBADMSG,
194+
"double operation default"
195+
},
196+
{
197+
"policy_name=test policy_version=0.0.0\n"
198+
"DEFAULT action=ALLOW\n"
199+
"DEFAULT op=EXECUTE action=DEN\n",
200+
-EBADMSG,
201+
"invalid action value"
202+
},
203+
{
204+
"policy_name=test policy_version=0.0.0\n"
205+
"DEFAULT action=ALLOW\n"
206+
"DEFAULT op=EXECUTE action\n",
207+
-EBADMSG,
208+
"invalid action value (2)"
209+
},
210+
{
211+
"policy_name=test policy_version=0.0.0\n"
212+
"DEFAULT action=ALLOW\n"
213+
"UNKNOWN value=true\n",
214+
-EBADMSG,
215+
"unrecognized statement"
216+
},
217+
{
218+
"policy_name=test policy_version=0.0.0\n"
219+
"DEFAULT action=ALLOW\n"
220+
"op=EXECUTE dmverity_roothash=1c0d7ee1f8343b7fbe418378e8eb22c061d7dec7 action=DENY\n",
221+
-EBADMSG,
222+
"old-style digest"
223+
},
224+
{
225+
"policy_name=test policy_version=0.0.0\n"
226+
"DEFAULT action=ALLOW\n"
227+
"op=EXECUTE fsverity_digest=1c0d7ee1f8343b7fbe418378e8eb22c061d7dec7 action=DENY\n",
228+
-EBADMSG,
229+
"old-style digest"
230+
}
231+
};
232+
233+
static void pol_to_desc(const struct policy_case *c, char *desc)
234+
{
235+
strscpy(desc, c->desc, KUNIT_PARAM_DESC_SIZE);
236+
}
237+
238+
KUNIT_ARRAY_PARAM(ipe_policies, policy_cases, pol_to_desc);
239+
240+
/**
241+
* ipe_parser_unsigned_test - Test the parser by passing unsigned policies.
242+
* @test: Supplies a pointer to a kunit structure.
243+
*
244+
* This is called by the kunit harness. This test does not check the correctness
245+
* of the policy, but ensures that errors are handled correctly.
246+
*/
247+
static void ipe_parser_unsigned_test(struct kunit *test)
248+
{
249+
const struct policy_case *p = test->param_value;
250+
struct ipe_policy *pol;
251+
252+
pol = ipe_new_policy(p->policy, strlen(p->policy), NULL, 0);
253+
254+
if (p->errno) {
255+
KUNIT_EXPECT_EQ(test, PTR_ERR(pol), p->errno);
256+
return;
257+
}
258+
259+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pol);
260+
KUNIT_EXPECT_NOT_ERR_OR_NULL(test, pol->parsed);
261+
KUNIT_EXPECT_STREQ(test, pol->text, p->policy);
262+
KUNIT_EXPECT_PTR_EQ(test, NULL, pol->pkcs7);
263+
KUNIT_EXPECT_EQ(test, 0, pol->pkcs7len);
264+
265+
ipe_free_policy(pol);
266+
}
267+
268+
/**
269+
* ipe_parser_widestring_test - Ensure parser fail on a wide string policy.
270+
* @test: Supplies a pointer to a kunit structure.
271+
*
272+
* This is called by the kunit harness.
273+
*/
274+
static void ipe_parser_widestring_test(struct kunit *test)
275+
{
276+
const unsigned short policy[] = L"policy_name=Test policy_version=0.0.0\n"
277+
L"DEFAULT action=ALLOW";
278+
struct ipe_policy *pol = NULL;
279+
280+
pol = ipe_new_policy((const char *)policy, (ARRAY_SIZE(policy) - 1) * 2, NULL, 0);
281+
KUNIT_EXPECT_TRUE(test, IS_ERR_OR_NULL(pol));
282+
283+
ipe_free_policy(pol);
284+
}
285+
286+
static struct kunit_case ipe_parser_test_cases[] = {
287+
KUNIT_CASE_PARAM(ipe_parser_unsigned_test, ipe_policies_gen_params),
288+
KUNIT_CASE(ipe_parser_widestring_test),
289+
};
290+
291+
static struct kunit_suite ipe_parser_test_suite = {
292+
.name = "ipe-parser",
293+
.test_cases = ipe_parser_test_cases,
294+
};
295+
296+
kunit_test_suite(ipe_parser_test_suite);

0 commit comments

Comments
 (0)