xref: /linux/net/handshake/handshake-test.c (revision 204a5efde5ed52932840ee1d15d3b581cfda48e2)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2023 Oracle and/or its affiliates.
4  *
5  * KUnit test of the handshake upcall mechanism.
6  */
7 
8 #include <kunit/test.h>
9 #include <kunit/visibility.h>
10 
11 #include <linux/kernel.h>
12 
13 #include <net/sock.h>
14 #include <net/genetlink.h>
15 #include <net/netns/generic.h>
16 
17 #include <uapi/linux/handshake.h>
18 #include "handshake.h"
19 
20 MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
21 
22 static int test_accept_func(struct handshake_req *req, struct genl_info *info,
23 			    int fd)
24 {
25 	return 0;
26 }
27 
28 static void test_done_func(struct handshake_req *req, int status,
29 			   struct genl_info *info)
30 {
31 }
32 
33 struct handshake_req_alloc_test_param {
34 	const char			*desc;
35 	struct handshake_proto		*proto;
36 	gfp_t				gfp;
37 	bool				expect_success;
38 };
39 
40 static struct handshake_proto handshake_req_alloc_proto_2 = {
41 	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_NONE,
42 };
43 
44 static struct handshake_proto handshake_req_alloc_proto_3 = {
45 	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_MAX,
46 };
47 
48 static struct handshake_proto handshake_req_alloc_proto_4 = {
49 	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_TLSHD,
50 };
51 
52 static struct handshake_proto handshake_req_alloc_proto_5 = {
53 	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_TLSHD,
54 	.hp_accept		= test_accept_func,
55 };
56 
57 static struct handshake_proto handshake_req_alloc_proto_6 = {
58 	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_TLSHD,
59 	.hp_privsize		= UINT_MAX,
60 	.hp_accept		= test_accept_func,
61 	.hp_done		= test_done_func,
62 };
63 
64 static struct handshake_proto handshake_req_alloc_proto_good = {
65 	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_TLSHD,
66 	.hp_accept		= test_accept_func,
67 	.hp_done		= test_done_func,
68 };
69 
70 static const
71 struct handshake_req_alloc_test_param handshake_req_alloc_params[] = {
72 	{
73 		.desc			= "handshake_req_alloc NULL proto",
74 		.proto			= NULL,
75 		.gfp			= GFP_KERNEL,
76 		.expect_success		= false,
77 	},
78 	{
79 		.desc			= "handshake_req_alloc CLASS_NONE",
80 		.proto			= &handshake_req_alloc_proto_2,
81 		.gfp			= GFP_KERNEL,
82 		.expect_success		= false,
83 	},
84 	{
85 		.desc			= "handshake_req_alloc CLASS_MAX",
86 		.proto			= &handshake_req_alloc_proto_3,
87 		.gfp			= GFP_KERNEL,
88 		.expect_success		= false,
89 	},
90 	{
91 		.desc			= "handshake_req_alloc no callbacks",
92 		.proto			= &handshake_req_alloc_proto_4,
93 		.gfp			= GFP_KERNEL,
94 		.expect_success		= false,
95 	},
96 	{
97 		.desc			= "handshake_req_alloc no done callback",
98 		.proto			= &handshake_req_alloc_proto_5,
99 		.gfp			= GFP_KERNEL,
100 		.expect_success		= false,
101 	},
102 	{
103 		.desc			= "handshake_req_alloc excessive privsize",
104 		.proto			= &handshake_req_alloc_proto_6,
105 		.gfp			= GFP_KERNEL | __GFP_NOWARN,
106 		.expect_success		= false,
107 	},
108 	{
109 		.desc			= "handshake_req_alloc all good",
110 		.proto			= &handshake_req_alloc_proto_good,
111 		.gfp			= GFP_KERNEL,
112 		.expect_success		= true,
113 	},
114 };
115 
116 static void
117 handshake_req_alloc_get_desc(const struct handshake_req_alloc_test_param *param,
118 			     char *desc)
119 {
120 	strscpy(desc, param->desc, KUNIT_PARAM_DESC_SIZE);
121 }
122 
123 /* Creates the function handshake_req_alloc_gen_params */
124 KUNIT_ARRAY_PARAM(handshake_req_alloc, handshake_req_alloc_params,
125 		  handshake_req_alloc_get_desc);
126 
127 static void handshake_req_alloc_case(struct kunit *test)
128 {
129 	const struct handshake_req_alloc_test_param *param = test->param_value;
130 	struct handshake_req *result;
131 
132 	/* Arrange */
133 
134 	/* Act */
135 	result = handshake_req_alloc(param->proto, param->gfp);
136 
137 	/* Assert */
138 	if (param->expect_success)
139 		KUNIT_EXPECT_NOT_NULL(test, result);
140 	else
141 		KUNIT_EXPECT_NULL(test, result);
142 
143 	kfree(result);
144 }
145 
146 static void handshake_req_submit_test1(struct kunit *test)
147 {
148 	struct socket *sock;
149 	int err, result;
150 
151 	/* Arrange */
152 	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
153 			    &sock, 1);
154 	KUNIT_ASSERT_EQ(test, err, 0);
155 
156 	/* Act */
157 	result = handshake_req_submit(sock, NULL, GFP_KERNEL);
158 
159 	/* Assert */
160 	KUNIT_EXPECT_EQ(test, result, -EINVAL);
161 
162 	sock_release(sock);
163 }
164 
165 static void handshake_req_submit_test2(struct kunit *test)
166 {
167 	struct handshake_req *req;
168 	int result;
169 
170 	/* Arrange */
171 	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
172 	KUNIT_ASSERT_NOT_NULL(test, req);
173 
174 	/* Act */
175 	result = handshake_req_submit(NULL, req, GFP_KERNEL);
176 
177 	/* Assert */
178 	KUNIT_EXPECT_EQ(test, result, -EINVAL);
179 
180 	/* handshake_req_submit() destroys @req on error */
181 }
182 
183 static void handshake_req_submit_test3(struct kunit *test)
184 {
185 	struct handshake_req *req;
186 	struct socket *sock;
187 	int err, result;
188 
189 	/* Arrange */
190 	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
191 	KUNIT_ASSERT_NOT_NULL(test, req);
192 
193 	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
194 			    &sock, 1);
195 	KUNIT_ASSERT_EQ(test, err, 0);
196 	sock->file = NULL;
197 
198 	/* Act */
199 	result = handshake_req_submit(sock, req, GFP_KERNEL);
200 
201 	/* Assert */
202 	KUNIT_EXPECT_EQ(test, result, -EINVAL);
203 
204 	/* handshake_req_submit() destroys @req on error */
205 	sock_release(sock);
206 }
207 
208 static void handshake_req_submit_test4(struct kunit *test)
209 {
210 	struct handshake_req *req, *result;
211 	unsigned long fcount_before;
212 	struct socket *sock;
213 	struct file *filp;
214 	int err;
215 
216 	/* Arrange */
217 	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
218 	KUNIT_ASSERT_NOT_NULL(test, req);
219 
220 	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
221 			    &sock, 1);
222 	KUNIT_ASSERT_EQ(test, err, 0);
223 	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
224 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
225 	KUNIT_ASSERT_NOT_NULL(test, sock->sk);
226 	sock->file = filp;
227 
228 	fcount_before = file_count(filp);
229 	err = handshake_req_submit(sock, req, GFP_KERNEL);
230 	KUNIT_ASSERT_EQ(test, err, 0);
231 	KUNIT_EXPECT_EQ(test, file_count(filp), fcount_before + 1);
232 
233 	/* Act */
234 	result = handshake_req_hash_lookup(sock->sk);
235 
236 	/* Assert */
237 	KUNIT_EXPECT_NOT_NULL(test, result);
238 	KUNIT_EXPECT_PTR_EQ(test, req, result);
239 
240 	handshake_req_cancel(sock->sk);
241 	KUNIT_EXPECT_EQ(test, file_count(filp), fcount_before);
242 	fput(filp);
243 }
244 
245 static void handshake_req_submit_test5(struct kunit *test)
246 {
247 	unsigned long fcount_before;
248 	struct handshake_req *req;
249 	struct handshake_net *hn;
250 	struct socket *sock;
251 	struct file *filp;
252 	struct net *net;
253 	int saved, err;
254 
255 	/* Arrange */
256 	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
257 	KUNIT_ASSERT_NOT_NULL(test, req);
258 
259 	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
260 			    &sock, 1);
261 	KUNIT_ASSERT_EQ(test, err, 0);
262 	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
263 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
264 	KUNIT_ASSERT_NOT_NULL(test, sock->sk);
265 	sock->file = filp;
266 
267 	net = sock_net(sock->sk);
268 	hn = handshake_pernet(net);
269 	KUNIT_ASSERT_NOT_NULL(test, hn);
270 
271 	saved = hn->hn_pending;
272 	hn->hn_pending = hn->hn_pending_max + 1;
273 	fcount_before = file_count(filp);
274 
275 	/* Act */
276 	err = handshake_req_submit(sock, req, GFP_KERNEL);
277 
278 	/* Assert */
279 	KUNIT_EXPECT_EQ(test, err, -EAGAIN);
280 	KUNIT_EXPECT_EQ(test, file_count(filp), fcount_before);
281 
282 	fput(filp);
283 	hn->hn_pending = saved;
284 }
285 
286 static void handshake_req_submit_test6(struct kunit *test)
287 {
288 	struct handshake_req *req1, *req2;
289 	unsigned long fcount_before;
290 	struct socket *sock;
291 	struct file *filp;
292 	int err;
293 
294 	/* Arrange */
295 	req1 = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
296 	KUNIT_ASSERT_NOT_NULL(test, req1);
297 	req2 = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
298 	KUNIT_ASSERT_NOT_NULL(test, req2);
299 
300 	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
301 			    &sock, 1);
302 	KUNIT_ASSERT_EQ(test, err, 0);
303 	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
304 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
305 	KUNIT_ASSERT_NOT_NULL(test, sock->sk);
306 	sock->file = filp;
307 	fcount_before = file_count(filp);
308 
309 	/* Act */
310 	err = handshake_req_submit(sock, req1, GFP_KERNEL);
311 	KUNIT_ASSERT_EQ(test, err, 0);
312 	KUNIT_EXPECT_EQ(test, file_count(filp), fcount_before + 1);
313 	err = handshake_req_submit(sock, req2, GFP_KERNEL);
314 
315 	/* Assert */
316 	KUNIT_EXPECT_EQ(test, err, -EBUSY);
317 	KUNIT_EXPECT_EQ(test, file_count(filp), fcount_before + 1);
318 
319 	handshake_req_cancel(sock->sk);
320 	KUNIT_EXPECT_EQ(test, file_count(filp), fcount_before);
321 	fput(filp);
322 }
323 
324 static void handshake_req_cancel_test1(struct kunit *test)
325 {
326 	unsigned long fcount_before;
327 	struct handshake_req *req;
328 	struct socket *sock;
329 	struct file *filp;
330 	bool result;
331 	int err;
332 
333 	/* Arrange */
334 	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
335 	KUNIT_ASSERT_NOT_NULL(test, req);
336 
337 	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
338 			    &sock, 1);
339 	KUNIT_ASSERT_EQ(test, err, 0);
340 
341 	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
342 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
343 	sock->file = filp;
344 
345 	fcount_before = file_count(filp);
346 	err = handshake_req_submit(sock, req, GFP_KERNEL);
347 	KUNIT_ASSERT_EQ(test, err, 0);
348 	KUNIT_EXPECT_EQ(test, file_count(filp), fcount_before + 1);
349 
350 	/* NB: handshake_req hasn't been accepted */
351 
352 	/* Act */
353 	result = handshake_req_cancel(sock->sk);
354 
355 	/* Assert */
356 	KUNIT_EXPECT_TRUE(test, result);
357 	KUNIT_EXPECT_EQ(test, file_count(filp), fcount_before);
358 
359 	fput(filp);
360 }
361 
362 static void handshake_req_cancel_test2(struct kunit *test)
363 {
364 	unsigned long fcount_before;
365 	struct handshake_req *req, *next;
366 	struct handshake_net *hn;
367 	struct socket *sock;
368 	struct file *filp;
369 	struct net *net;
370 	bool result;
371 	int err;
372 
373 	/* Arrange */
374 	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
375 	KUNIT_ASSERT_NOT_NULL(test, req);
376 
377 	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
378 			    &sock, 1);
379 	KUNIT_ASSERT_EQ(test, err, 0);
380 
381 	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
382 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
383 	sock->file = filp;
384 
385 	fcount_before = file_count(filp);
386 	err = handshake_req_submit(sock, req, GFP_KERNEL);
387 	KUNIT_ASSERT_EQ(test, err, 0);
388 	KUNIT_EXPECT_EQ(test, file_count(filp), fcount_before + 1);
389 
390 	net = sock_net(sock->sk);
391 	hn = handshake_pernet(net);
392 	KUNIT_ASSERT_NOT_NULL(test, hn);
393 
394 	/* Pretend to accept this request */
395 	next = handshake_req_next(hn, HANDSHAKE_HANDLER_CLASS_TLSHD);
396 	KUNIT_ASSERT_PTR_EQ(test, req, next);
397 	/* Simulate FD_PREPARE() consuming the file reference handed
398 	 * off by handshake_req_next(); see handshake_nl_accept_doit().
399 	 */
400 	fput(filp);
401 
402 	/* Act */
403 	result = handshake_req_cancel(sock->sk);
404 
405 	/* Assert */
406 	KUNIT_EXPECT_TRUE(test, result);
407 	KUNIT_EXPECT_EQ(test, file_count(filp), fcount_before);
408 
409 	fput(filp);
410 }
411 
412 static void handshake_req_cancel_test3(struct kunit *test)
413 {
414 	unsigned long fcount_before;
415 	struct handshake_req *req, *next;
416 	struct handshake_net *hn;
417 	struct socket *sock;
418 	struct file *filp;
419 	struct net *net;
420 	bool result;
421 	int err;
422 
423 	/* Arrange */
424 	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
425 	KUNIT_ASSERT_NOT_NULL(test, req);
426 
427 	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
428 			    &sock, 1);
429 	KUNIT_ASSERT_EQ(test, err, 0);
430 
431 	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
432 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
433 	sock->file = filp;
434 
435 	fcount_before = file_count(filp);
436 	err = handshake_req_submit(sock, req, GFP_KERNEL);
437 	KUNIT_ASSERT_EQ(test, err, 0);
438 	KUNIT_EXPECT_EQ(test, file_count(filp), fcount_before + 1);
439 
440 	net = sock_net(sock->sk);
441 	hn = handshake_pernet(net);
442 	KUNIT_ASSERT_NOT_NULL(test, hn);
443 
444 	/* Pretend to accept this request */
445 	next = handshake_req_next(hn, HANDSHAKE_HANDLER_CLASS_TLSHD);
446 	KUNIT_ASSERT_PTR_EQ(test, req, next);
447 	/* Simulate FD_PREPARE() consuming the file reference handed
448 	 * off by handshake_req_next(); see handshake_nl_accept_doit().
449 	 */
450 	fput(filp);
451 
452 	/* Pretend to complete this request */
453 	handshake_complete(next, -ETIMEDOUT, NULL);
454 	KUNIT_EXPECT_EQ(test, file_count(filp), fcount_before);
455 
456 	/* Act */
457 	result = handshake_req_cancel(sock->sk);
458 
459 	/* Assert */
460 	KUNIT_EXPECT_FALSE(test, result);
461 	KUNIT_EXPECT_EQ(test, file_count(filp), fcount_before);
462 
463 	fput(filp);
464 }
465 
466 static struct handshake_req *handshake_req_destroy_test;
467 
468 static void test_destroy_func(struct handshake_req *req)
469 {
470 	handshake_req_destroy_test = req;
471 }
472 
473 static struct handshake_proto handshake_req_alloc_proto_destroy = {
474 	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_TLSHD,
475 	.hp_accept		= test_accept_func,
476 	.hp_done		= test_done_func,
477 	.hp_destroy		= test_destroy_func,
478 };
479 
480 static void handshake_req_destroy_test1(struct kunit *test)
481 {
482 	unsigned long fcount_before;
483 	struct handshake_req *req;
484 	struct socket *sock;
485 	struct file *filp;
486 	int err;
487 
488 	/* Arrange */
489 	handshake_req_destroy_test = NULL;
490 
491 	req = handshake_req_alloc(&handshake_req_alloc_proto_destroy, GFP_KERNEL);
492 	KUNIT_ASSERT_NOT_NULL(test, req);
493 
494 	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
495 			    &sock, 1);
496 	KUNIT_ASSERT_EQ(test, err, 0);
497 
498 	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
499 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
500 	sock->file = filp;
501 
502 	fcount_before = file_count(filp);
503 	err = handshake_req_submit(sock, req, GFP_KERNEL);
504 	KUNIT_ASSERT_EQ(test, err, 0);
505 
506 	handshake_req_cancel(sock->sk);
507 	KUNIT_EXPECT_EQ(test, file_count(filp), fcount_before);
508 
509 	/* Act */
510 	/* Ensure the close/release/put process has run to
511 	 * completion before checking the result.
512 	 */
513 	__fput_sync(filp);
514 
515 	/* Assert */
516 	KUNIT_EXPECT_PTR_EQ(test, handshake_req_destroy_test, req);
517 }
518 
519 static struct kunit_case handshake_api_test_cases[] = {
520 	{
521 		.name			= "req_alloc API fuzzing",
522 		.run_case		= handshake_req_alloc_case,
523 		.generate_params	= handshake_req_alloc_gen_params,
524 	},
525 	{
526 		.name			= "req_submit NULL req arg",
527 		.run_case		= handshake_req_submit_test1,
528 	},
529 	{
530 		.name			= "req_submit NULL sock arg",
531 		.run_case		= handshake_req_submit_test2,
532 	},
533 	{
534 		.name			= "req_submit NULL sock->file",
535 		.run_case		= handshake_req_submit_test3,
536 	},
537 	{
538 		.name			= "req_lookup works",
539 		.run_case		= handshake_req_submit_test4,
540 	},
541 	{
542 		.name			= "req_submit max pending",
543 		.run_case		= handshake_req_submit_test5,
544 	},
545 	{
546 		.name			= "req_submit multiple",
547 		.run_case		= handshake_req_submit_test6,
548 	},
549 	{
550 		.name			= "req_cancel before accept",
551 		.run_case		= handshake_req_cancel_test1,
552 	},
553 	{
554 		.name			= "req_cancel after accept",
555 		.run_case		= handshake_req_cancel_test2,
556 	},
557 	{
558 		.name			= "req_cancel after done",
559 		.run_case		= handshake_req_cancel_test3,
560 	},
561 	{
562 		.name			= "req_destroy works",
563 		.run_case		= handshake_req_destroy_test1,
564 	},
565 	{}
566 };
567 
568 static struct kunit_suite handshake_api_suite = {
569        .name                   = "Handshake API tests",
570        .test_cases             = handshake_api_test_cases,
571 };
572 
573 kunit_test_suites(&handshake_api_suite);
574 
575 MODULE_DESCRIPTION("Test handshake upcall API functions");
576 MODULE_LICENSE("GPL");
577