1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2023 Oracle and/or its affiliates.
5 * KUnit test of the handshake upcall mechanism.
8 #include <kunit/test.h>
9 #include <kunit/visibility.h>
11 #include <linux/kernel.h>
14 #include <net/genetlink.h>
15 #include <net/netns/generic.h>
17 #include <uapi/linux/handshake.h>
18 #include "handshake.h"
20 MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING);
22 static int test_accept_func(struct handshake_req *req, struct genl_info *info,
28 static void test_done_func(struct handshake_req *req, unsigned int status,
29 struct genl_info *info)
33 struct handshake_req_alloc_test_param {
35 struct handshake_proto *proto;
40 static struct handshake_proto handshake_req_alloc_proto_2 = {
41 .hp_handler_class = HANDSHAKE_HANDLER_CLASS_NONE,
44 static struct handshake_proto handshake_req_alloc_proto_3 = {
45 .hp_handler_class = HANDSHAKE_HANDLER_CLASS_MAX,
48 static struct handshake_proto handshake_req_alloc_proto_4 = {
49 .hp_handler_class = HANDSHAKE_HANDLER_CLASS_TLSHD,
52 static struct handshake_proto handshake_req_alloc_proto_5 = {
53 .hp_handler_class = HANDSHAKE_HANDLER_CLASS_TLSHD,
54 .hp_accept = test_accept_func,
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,
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,
71 struct handshake_req_alloc_test_param handshake_req_alloc_params[] = {
73 .desc = "handshake_req_alloc NULL proto",
76 .expect_success = false,
79 .desc = "handshake_req_alloc CLASS_NONE",
80 .proto = &handshake_req_alloc_proto_2,
82 .expect_success = false,
85 .desc = "handshake_req_alloc CLASS_MAX",
86 .proto = &handshake_req_alloc_proto_3,
88 .expect_success = false,
91 .desc = "handshake_req_alloc no callbacks",
92 .proto = &handshake_req_alloc_proto_4,
94 .expect_success = false,
97 .desc = "handshake_req_alloc no done callback",
98 .proto = &handshake_req_alloc_proto_5,
100 .expect_success = false,
103 .desc = "handshake_req_alloc excessive privsize",
104 .proto = &handshake_req_alloc_proto_6,
106 .expect_success = false,
109 .desc = "handshake_req_alloc all good",
110 .proto = &handshake_req_alloc_proto_good,
112 .expect_success = true,
117 handshake_req_alloc_get_desc(const struct handshake_req_alloc_test_param *param,
120 strscpy(desc, param->desc, KUNIT_PARAM_DESC_SIZE);
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);
127 static void handshake_req_alloc_case(struct kunit *test)
129 const struct handshake_req_alloc_test_param *param = test->param_value;
130 struct handshake_req *result;
135 result = handshake_req_alloc(param->proto, param->gfp);
138 if (param->expect_success)
139 KUNIT_EXPECT_NOT_NULL(test, result);
141 KUNIT_EXPECT_NULL(test, result);
146 static void handshake_req_submit_test1(struct kunit *test)
152 err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
154 KUNIT_ASSERT_EQ(test, err, 0);
157 result = handshake_req_submit(sock, NULL, GFP_KERNEL);
160 KUNIT_EXPECT_EQ(test, result, -EINVAL);
165 static void handshake_req_submit_test2(struct kunit *test)
167 struct handshake_req *req;
171 req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
172 KUNIT_ASSERT_NOT_NULL(test, req);
175 result = handshake_req_submit(NULL, req, GFP_KERNEL);
178 KUNIT_EXPECT_EQ(test, result, -EINVAL);
180 /* handshake_req_submit() destroys @req on error */
183 static void handshake_req_submit_test3(struct kunit *test)
185 struct handshake_req *req;
190 req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
191 KUNIT_ASSERT_NOT_NULL(test, req);
193 err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
195 KUNIT_ASSERT_EQ(test, err, 0);
199 result = handshake_req_submit(sock, req, GFP_KERNEL);
202 KUNIT_EXPECT_EQ(test, result, -EINVAL);
204 /* handshake_req_submit() destroys @req on error */
208 static void handshake_req_submit_test4(struct kunit *test)
210 struct handshake_req *req, *result;
215 req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
216 KUNIT_ASSERT_NOT_NULL(test, req);
218 err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
220 KUNIT_ASSERT_EQ(test, err, 0);
221 sock->file = sock_alloc_file(sock, O_NONBLOCK, NULL);
222 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sock->file);
223 KUNIT_ASSERT_NOT_NULL(test, sock->sk);
225 err = handshake_req_submit(sock, req, GFP_KERNEL);
226 KUNIT_ASSERT_EQ(test, err, 0);
229 result = handshake_req_hash_lookup(sock->sk);
232 KUNIT_EXPECT_NOT_NULL(test, result);
233 KUNIT_EXPECT_PTR_EQ(test, req, result);
235 handshake_req_cancel(sock->sk);
239 static void handshake_req_submit_test5(struct kunit *test)
241 struct handshake_req *req;
242 struct handshake_net *hn;
248 req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
249 KUNIT_ASSERT_NOT_NULL(test, req);
251 err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
253 KUNIT_ASSERT_EQ(test, err, 0);
254 sock->file = sock_alloc_file(sock, O_NONBLOCK, NULL);
255 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sock->file);
256 KUNIT_ASSERT_NOT_NULL(test, sock->sk);
258 net = sock_net(sock->sk);
259 hn = handshake_pernet(net);
260 KUNIT_ASSERT_NOT_NULL(test, hn);
262 saved = hn->hn_pending;
263 hn->hn_pending = hn->hn_pending_max + 1;
266 err = handshake_req_submit(sock, req, GFP_KERNEL);
269 KUNIT_EXPECT_EQ(test, err, -EAGAIN);
272 hn->hn_pending = saved;
275 static void handshake_req_submit_test6(struct kunit *test)
277 struct handshake_req *req1, *req2;
282 req1 = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
283 KUNIT_ASSERT_NOT_NULL(test, req1);
284 req2 = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
285 KUNIT_ASSERT_NOT_NULL(test, req2);
287 err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
289 KUNIT_ASSERT_EQ(test, err, 0);
290 sock->file = sock_alloc_file(sock, O_NONBLOCK, NULL);
291 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sock->file);
292 KUNIT_ASSERT_NOT_NULL(test, sock->sk);
295 err = handshake_req_submit(sock, req1, GFP_KERNEL);
296 KUNIT_ASSERT_EQ(test, err, 0);
297 err = handshake_req_submit(sock, req2, GFP_KERNEL);
300 KUNIT_EXPECT_EQ(test, err, -EBUSY);
302 handshake_req_cancel(sock->sk);
306 static void handshake_req_cancel_test1(struct kunit *test)
308 struct handshake_req *req;
314 req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
315 KUNIT_ASSERT_NOT_NULL(test, req);
317 err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
319 KUNIT_ASSERT_EQ(test, err, 0);
321 sock->file = sock_alloc_file(sock, O_NONBLOCK, NULL);
322 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sock->file);
324 err = handshake_req_submit(sock, req, GFP_KERNEL);
325 KUNIT_ASSERT_EQ(test, err, 0);
327 /* NB: handshake_req hasn't been accepted */
330 result = handshake_req_cancel(sock->sk);
333 KUNIT_EXPECT_TRUE(test, result);
338 static void handshake_req_cancel_test2(struct kunit *test)
340 struct handshake_req *req, *next;
341 struct handshake_net *hn;
348 req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
349 KUNIT_ASSERT_NOT_NULL(test, req);
351 err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
353 KUNIT_ASSERT_EQ(test, err, 0);
355 sock->file = sock_alloc_file(sock, O_NONBLOCK, NULL);
356 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sock->file);
358 err = handshake_req_submit(sock, req, GFP_KERNEL);
359 KUNIT_ASSERT_EQ(test, err, 0);
361 net = sock_net(sock->sk);
362 hn = handshake_pernet(net);
363 KUNIT_ASSERT_NOT_NULL(test, hn);
365 /* Pretend to accept this request */
366 next = handshake_req_next(hn, HANDSHAKE_HANDLER_CLASS_TLSHD);
367 KUNIT_ASSERT_PTR_EQ(test, req, next);
370 result = handshake_req_cancel(sock->sk);
373 KUNIT_EXPECT_TRUE(test, result);
378 static void handshake_req_cancel_test3(struct kunit *test)
380 struct handshake_req *req, *next;
381 struct handshake_net *hn;
388 req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
389 KUNIT_ASSERT_NOT_NULL(test, req);
391 err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
393 KUNIT_ASSERT_EQ(test, err, 0);
395 sock->file = sock_alloc_file(sock, O_NONBLOCK, NULL);
396 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sock->file);
398 err = handshake_req_submit(sock, req, GFP_KERNEL);
399 KUNIT_ASSERT_EQ(test, err, 0);
401 net = sock_net(sock->sk);
402 hn = handshake_pernet(net);
403 KUNIT_ASSERT_NOT_NULL(test, hn);
405 /* Pretend to accept this request */
406 next = handshake_req_next(hn, HANDSHAKE_HANDLER_CLASS_TLSHD);
407 KUNIT_ASSERT_PTR_EQ(test, req, next);
409 /* Pretend to complete this request */
410 handshake_complete(next, -ETIMEDOUT, NULL);
413 result = handshake_req_cancel(sock->sk);
416 KUNIT_EXPECT_FALSE(test, result);
421 static struct handshake_req *handshake_req_destroy_test;
423 static void test_destroy_func(struct handshake_req *req)
425 handshake_req_destroy_test = req;
428 static struct handshake_proto handshake_req_alloc_proto_destroy = {
429 .hp_handler_class = HANDSHAKE_HANDLER_CLASS_TLSHD,
430 .hp_accept = test_accept_func,
431 .hp_done = test_done_func,
432 .hp_destroy = test_destroy_func,
435 static void handshake_req_destroy_test1(struct kunit *test)
437 struct handshake_req *req;
442 handshake_req_destroy_test = NULL;
444 req = handshake_req_alloc(&handshake_req_alloc_proto_destroy, GFP_KERNEL);
445 KUNIT_ASSERT_NOT_NULL(test, req);
447 err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
449 KUNIT_ASSERT_EQ(test, err, 0);
451 sock->file = sock_alloc_file(sock, O_NONBLOCK, NULL);
452 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sock->file);
454 err = handshake_req_submit(sock, req, GFP_KERNEL);
455 KUNIT_ASSERT_EQ(test, err, 0);
457 handshake_req_cancel(sock->sk);
463 KUNIT_EXPECT_PTR_EQ(test, handshake_req_destroy_test, req);
466 static struct kunit_case handshake_api_test_cases[] = {
468 .name = "req_alloc API fuzzing",
469 .run_case = handshake_req_alloc_case,
470 .generate_params = handshake_req_alloc_gen_params,
473 .name = "req_submit NULL req arg",
474 .run_case = handshake_req_submit_test1,
477 .name = "req_submit NULL sock arg",
478 .run_case = handshake_req_submit_test2,
481 .name = "req_submit NULL sock->file",
482 .run_case = handshake_req_submit_test3,
485 .name = "req_lookup works",
486 .run_case = handshake_req_submit_test4,
489 .name = "req_submit max pending",
490 .run_case = handshake_req_submit_test5,
493 .name = "req_submit multiple",
494 .run_case = handshake_req_submit_test6,
497 .name = "req_cancel before accept",
498 .run_case = handshake_req_cancel_test1,
501 .name = "req_cancel after accept",
502 .run_case = handshake_req_cancel_test2,
505 .name = "req_cancel after done",
506 .run_case = handshake_req_cancel_test3,
509 .name = "req_destroy works",
510 .run_case = handshake_req_destroy_test1,
515 static struct kunit_suite handshake_api_suite = {
516 .name = "Handshake API tests",
517 .test_cases = handshake_api_test_cases,
520 kunit_test_suites(&handshake_api_suite);
522 MODULE_DESCRIPTION("Test handshake upcall API functions");
523 MODULE_LICENSE("GPL");