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
test_accept_func(struct handshake_req * req,struct genl_info * info,int fd)22 static int test_accept_func(struct handshake_req *req, struct genl_info *info,
23 int fd)
24 {
25 return 0;
26 }
27
test_done_func(struct handshake_req * req,int status,struct genl_info * info)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
handshake_req_alloc_get_desc(const struct handshake_req_alloc_test_param * param,char * desc)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
handshake_req_alloc_case(struct kunit * test)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
handshake_req_submit_test1(struct kunit * test)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
handshake_req_submit_test2(struct kunit * test)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
handshake_req_submit_test3(struct kunit * test)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
handshake_req_submit_test4(struct kunit * test)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
handshake_req_submit_test5(struct kunit * test)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
handshake_req_submit_test6(struct kunit * test)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
handshake_req_cancel_test1(struct kunit * test)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
handshake_req_cancel_test2(struct kunit * test)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
handshake_req_cancel_test3(struct kunit * test)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
test_destroy_func(struct handshake_req * req)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
handshake_req_destroy_test1(struct kunit * test)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