xref: /linux/net/handshake/handshake-test.c (revision 4ae68b26c3ab5a82aa271e6e9fc9b1a06e1d6b40)
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, unsigned 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 	struct socket *sock;
212 	struct file *filp;
213 	int err;
214 
215 	/* Arrange */
216 	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
217 	KUNIT_ASSERT_NOT_NULL(test, req);
218 
219 	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
220 			    &sock, 1);
221 	KUNIT_ASSERT_EQ(test, err, 0);
222 	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
223 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
224 	KUNIT_ASSERT_NOT_NULL(test, sock->sk);
225 	sock->file = filp;
226 
227 	err = handshake_req_submit(sock, req, GFP_KERNEL);
228 	KUNIT_ASSERT_EQ(test, err, 0);
229 
230 	/* Act */
231 	result = handshake_req_hash_lookup(sock->sk);
232 
233 	/* Assert */
234 	KUNIT_EXPECT_NOT_NULL(test, result);
235 	KUNIT_EXPECT_PTR_EQ(test, req, result);
236 
237 	handshake_req_cancel(sock->sk);
238 	sock_release(sock);
239 }
240 
241 static void handshake_req_submit_test5(struct kunit *test)
242 {
243 	struct handshake_req *req;
244 	struct handshake_net *hn;
245 	struct socket *sock;
246 	struct file *filp;
247 	struct net *net;
248 	int saved, err;
249 
250 	/* Arrange */
251 	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
252 	KUNIT_ASSERT_NOT_NULL(test, req);
253 
254 	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
255 			    &sock, 1);
256 	KUNIT_ASSERT_EQ(test, err, 0);
257 	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
258 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
259 	KUNIT_ASSERT_NOT_NULL(test, sock->sk);
260 	sock->file = filp;
261 
262 	net = sock_net(sock->sk);
263 	hn = handshake_pernet(net);
264 	KUNIT_ASSERT_NOT_NULL(test, hn);
265 
266 	saved = hn->hn_pending;
267 	hn->hn_pending = hn->hn_pending_max + 1;
268 
269 	/* Act */
270 	err = handshake_req_submit(sock, req, GFP_KERNEL);
271 
272 	/* Assert */
273 	KUNIT_EXPECT_EQ(test, err, -EAGAIN);
274 
275 	sock_release(sock);
276 	hn->hn_pending = saved;
277 }
278 
279 static void handshake_req_submit_test6(struct kunit *test)
280 {
281 	struct handshake_req *req1, *req2;
282 	struct socket *sock;
283 	struct file *filp;
284 	int err;
285 
286 	/* Arrange */
287 	req1 = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
288 	KUNIT_ASSERT_NOT_NULL(test, req1);
289 	req2 = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
290 	KUNIT_ASSERT_NOT_NULL(test, req2);
291 
292 	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
293 			    &sock, 1);
294 	KUNIT_ASSERT_EQ(test, err, 0);
295 	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
296 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
297 	KUNIT_ASSERT_NOT_NULL(test, sock->sk);
298 	sock->file = filp;
299 
300 	/* Act */
301 	err = handshake_req_submit(sock, req1, GFP_KERNEL);
302 	KUNIT_ASSERT_EQ(test, err, 0);
303 	err = handshake_req_submit(sock, req2, GFP_KERNEL);
304 
305 	/* Assert */
306 	KUNIT_EXPECT_EQ(test, err, -EBUSY);
307 
308 	handshake_req_cancel(sock->sk);
309 	sock_release(sock);
310 }
311 
312 static void handshake_req_cancel_test1(struct kunit *test)
313 {
314 	struct handshake_req *req;
315 	struct socket *sock;
316 	struct file *filp;
317 	bool result;
318 	int err;
319 
320 	/* Arrange */
321 	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
322 	KUNIT_ASSERT_NOT_NULL(test, req);
323 
324 	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
325 			    &sock, 1);
326 	KUNIT_ASSERT_EQ(test, err, 0);
327 
328 	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
329 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
330 	sock->file = filp;
331 
332 	err = handshake_req_submit(sock, req, GFP_KERNEL);
333 	KUNIT_ASSERT_EQ(test, err, 0);
334 
335 	/* NB: handshake_req hasn't been accepted */
336 
337 	/* Act */
338 	result = handshake_req_cancel(sock->sk);
339 
340 	/* Assert */
341 	KUNIT_EXPECT_TRUE(test, result);
342 
343 	sock_release(sock);
344 }
345 
346 static void handshake_req_cancel_test2(struct kunit *test)
347 {
348 	struct handshake_req *req, *next;
349 	struct handshake_net *hn;
350 	struct socket *sock;
351 	struct file *filp;
352 	struct net *net;
353 	bool result;
354 	int err;
355 
356 	/* Arrange */
357 	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
358 	KUNIT_ASSERT_NOT_NULL(test, req);
359 
360 	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
361 			    &sock, 1);
362 	KUNIT_ASSERT_EQ(test, err, 0);
363 
364 	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
365 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
366 	sock->file = filp;
367 
368 	err = handshake_req_submit(sock, req, GFP_KERNEL);
369 	KUNIT_ASSERT_EQ(test, err, 0);
370 
371 	net = sock_net(sock->sk);
372 	hn = handshake_pernet(net);
373 	KUNIT_ASSERT_NOT_NULL(test, hn);
374 
375 	/* Pretend to accept this request */
376 	next = handshake_req_next(hn, HANDSHAKE_HANDLER_CLASS_TLSHD);
377 	KUNIT_ASSERT_PTR_EQ(test, req, next);
378 
379 	/* Act */
380 	result = handshake_req_cancel(sock->sk);
381 
382 	/* Assert */
383 	KUNIT_EXPECT_TRUE(test, result);
384 
385 	sock_release(sock);
386 }
387 
388 static void handshake_req_cancel_test3(struct kunit *test)
389 {
390 	struct handshake_req *req, *next;
391 	struct handshake_net *hn;
392 	struct socket *sock;
393 	struct file *filp;
394 	struct net *net;
395 	bool result;
396 	int err;
397 
398 	/* Arrange */
399 	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
400 	KUNIT_ASSERT_NOT_NULL(test, req);
401 
402 	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
403 			    &sock, 1);
404 	KUNIT_ASSERT_EQ(test, err, 0);
405 
406 	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
407 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
408 	sock->file = filp;
409 
410 	err = handshake_req_submit(sock, req, GFP_KERNEL);
411 	KUNIT_ASSERT_EQ(test, err, 0);
412 
413 	net = sock_net(sock->sk);
414 	hn = handshake_pernet(net);
415 	KUNIT_ASSERT_NOT_NULL(test, hn);
416 
417 	/* Pretend to accept this request */
418 	next = handshake_req_next(hn, HANDSHAKE_HANDLER_CLASS_TLSHD);
419 	KUNIT_ASSERT_PTR_EQ(test, req, next);
420 
421 	/* Pretend to complete this request */
422 	handshake_complete(next, -ETIMEDOUT, NULL);
423 
424 	/* Act */
425 	result = handshake_req_cancel(sock->sk);
426 
427 	/* Assert */
428 	KUNIT_EXPECT_FALSE(test, result);
429 
430 	sock_release(sock);
431 }
432 
433 static struct handshake_req *handshake_req_destroy_test;
434 
435 static void test_destroy_func(struct handshake_req *req)
436 {
437 	handshake_req_destroy_test = req;
438 }
439 
440 static struct handshake_proto handshake_req_alloc_proto_destroy = {
441 	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_TLSHD,
442 	.hp_accept		= test_accept_func,
443 	.hp_done		= test_done_func,
444 	.hp_destroy		= test_destroy_func,
445 };
446 
447 static void handshake_req_destroy_test1(struct kunit *test)
448 {
449 	struct handshake_req *req;
450 	struct socket *sock;
451 	struct file *filp;
452 	int err;
453 
454 	/* Arrange */
455 	handshake_req_destroy_test = NULL;
456 
457 	req = handshake_req_alloc(&handshake_req_alloc_proto_destroy, GFP_KERNEL);
458 	KUNIT_ASSERT_NOT_NULL(test, req);
459 
460 	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
461 			    &sock, 1);
462 	KUNIT_ASSERT_EQ(test, err, 0);
463 
464 	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
465 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
466 	sock->file = filp;
467 
468 	err = handshake_req_submit(sock, req, GFP_KERNEL);
469 	KUNIT_ASSERT_EQ(test, err, 0);
470 
471 	handshake_req_cancel(sock->sk);
472 
473 	/* Act */
474 	sock_release(sock);
475 
476 	/* Assert */
477 	KUNIT_EXPECT_PTR_EQ(test, handshake_req_destroy_test, req);
478 }
479 
480 static struct kunit_case handshake_api_test_cases[] = {
481 	{
482 		.name			= "req_alloc API fuzzing",
483 		.run_case		= handshake_req_alloc_case,
484 		.generate_params	= handshake_req_alloc_gen_params,
485 	},
486 	{
487 		.name			= "req_submit NULL req arg",
488 		.run_case		= handshake_req_submit_test1,
489 	},
490 	{
491 		.name			= "req_submit NULL sock arg",
492 		.run_case		= handshake_req_submit_test2,
493 	},
494 	{
495 		.name			= "req_submit NULL sock->file",
496 		.run_case		= handshake_req_submit_test3,
497 	},
498 	{
499 		.name			= "req_lookup works",
500 		.run_case		= handshake_req_submit_test4,
501 	},
502 	{
503 		.name			= "req_submit max pending",
504 		.run_case		= handshake_req_submit_test5,
505 	},
506 	{
507 		.name			= "req_submit multiple",
508 		.run_case		= handshake_req_submit_test6,
509 	},
510 	{
511 		.name			= "req_cancel before accept",
512 		.run_case		= handshake_req_cancel_test1,
513 	},
514 	{
515 		.name			= "req_cancel after accept",
516 		.run_case		= handshake_req_cancel_test2,
517 	},
518 	{
519 		.name			= "req_cancel after done",
520 		.run_case		= handshake_req_cancel_test3,
521 	},
522 	{
523 		.name			= "req_destroy works",
524 		.run_case		= handshake_req_destroy_test1,
525 	},
526 	{}
527 };
528 
529 static struct kunit_suite handshake_api_suite = {
530        .name                   = "Handshake API tests",
531        .test_cases             = handshake_api_test_cases,
532 };
533 
534 kunit_test_suites(&handshake_api_suite);
535 
536 MODULE_DESCRIPTION("Test handshake upcall API functions");
537 MODULE_LICENSE("GPL");
538