]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/fuzz-dhcp6-client.c
tree-wide: use -EBADF also in pipe initializers
[thirdparty/systemd.git] / src / libsystemd-network / fuzz-dhcp6-client.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <unistd.h>
4
5 #include "sd-dhcp6-client.h"
6 #include "sd-event.h"
7
8 #include "dhcp6-internal.h"
9 #include "event-util.h"
10 #include "fd-util.h"
11 #include "fuzz.h"
12
13 static int test_dhcp_fd[2] = { -EBADF, -EBADF };
14
15 int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address, const void *packet, size_t len) {
16 return len;
17 }
18
19 int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
20 assert_se(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_dhcp_fd) >= 0);
21 return TAKE_FD(test_dhcp_fd[0]);
22 }
23
24 static void fuzz_client(sd_dhcp6_client *client, const uint8_t *data, size_t size, DHCP6State state) {
25 assert_se(sd_dhcp6_client_set_information_request(client, state == DHCP6_STATE_INFORMATION_REQUEST) >= 0);
26 assert_se(sd_dhcp6_client_start(client) >= 0);
27
28 client->state = state;
29
30 if (size >= sizeof(DHCP6Message))
31 assert_se(dhcp6_client_set_transaction_id(client, ((const DHCP6Message *) data)->transaction_id) == 0);
32
33 /* These states does not require lease to send message. */
34 if (IN_SET(client->state, DHCP6_STATE_INFORMATION_REQUEST, DHCP6_STATE_SOLICITATION))
35 assert_se(dhcp6_client_send_message(client) >= 0);
36
37 assert_se(write(test_dhcp_fd[1], data, size) == (ssize_t) size);
38
39 assert_se(sd_event_run(sd_dhcp6_client_get_event(client), UINT64_MAX) > 0);
40
41 /* Check the state transition. */
42 if (client->state != state)
43 switch (state) {
44 case DHCP6_STATE_INFORMATION_REQUEST:
45 assert_se(client->state == DHCP6_STATE_STOPPED);
46 break;
47 case DHCP6_STATE_SOLICITATION:
48 assert_se(IN_SET(client->state, DHCP6_STATE_REQUEST, DHCP6_STATE_BOUND));
49 break;
50 case DHCP6_STATE_REQUEST:
51 assert_se(IN_SET(client->state, DHCP6_STATE_BOUND, DHCP6_STATE_SOLICITATION));
52 break;
53 default:
54 assert_not_reached();
55 }
56
57 /* Send message if the client has a lease. */
58 if (state != DHCP6_STATE_INFORMATION_REQUEST && sd_dhcp6_client_get_lease(client, NULL) >= 0) {
59 client->state = DHCP6_STATE_REQUEST;
60 dhcp6_client_send_message(client);
61 }
62
63 assert_se(sd_dhcp6_client_stop(client) >= 0);
64
65 test_dhcp_fd[1] = safe_close(test_dhcp_fd[1]);
66 }
67
68 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
69 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
70 _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
71 _cleanup_(sd_dhcp6_option_unrefp) sd_dhcp6_option *v1 = NULL, *v2 = NULL;
72 struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
73 struct in6_addr hint = { { { 0x3f, 0xfe, 0x05, 0x01, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } };
74 static const char *v1_data = "hogehoge", *v2_data = "foobar";
75
76 if (outside_size_range(size, 0, 65536))
77 return 0;
78
79 assert_se(sd_event_new(&e) >= 0);
80 assert_se(sd_dhcp6_client_new(&client) >= 0);
81 assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
82 assert_se(sd_dhcp6_client_set_ifindex(client, 42) >= 0);
83 assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0);
84 dhcp6_client_set_test_mode(client, true);
85
86 /* Used when sending message. */
87 assert_se(sd_dhcp6_client_set_fqdn(client, "example.com") == 1);
88 assert_se(sd_dhcp6_client_set_request_mud_url(client, "https://www.example.com/mudfile.json") >= 0);
89 assert_se(sd_dhcp6_client_set_request_user_class(client, STRV_MAKE("u1", "u2", "u3")) >= 0);
90 assert_se(sd_dhcp6_client_set_request_vendor_class(client, STRV_MAKE("v1", "v2", "v3")) >= 0);
91 assert_se(sd_dhcp6_client_set_prefix_delegation_hint(client, 48, &hint) >= 0);
92 assert_se(sd_dhcp6_option_new(123, v1_data, strlen(v1_data), 12345, &v1) >= 0);
93 assert_se(sd_dhcp6_option_new(456, v2_data, strlen(v2_data), 45678, &v2) >= 0);
94 assert_se(sd_dhcp6_client_add_vendor_option(client, v1) >= 0);
95 assert_se(sd_dhcp6_client_add_vendor_option(client, v2) >= 0);
96
97 fuzz_client(client, data, size, DHCP6_STATE_INFORMATION_REQUEST);
98 fuzz_client(client, data, size, DHCP6_STATE_SOLICITATION);
99
100 /* If size is zero, then the resend timer will be triggered at first,
101 * but in the REQUEST state the client must have a lease. */
102 if (size == 0)
103 return 0;
104
105 fuzz_client(client, data, size, DHCP6_STATE_REQUEST);
106
107 return 0;
108 }