/src/libcoap/tests/oss-fuzz/persist_target.c
Line | Count | Source |
1 | | #define _POSIX_C_SOURCE 200809L |
2 | | #include "coap3/coap_internal.h" |
3 | | #include <stdint.h> |
4 | | #include <stdio.h> |
5 | | #include <stdlib.h> |
6 | | #include <string.h> |
7 | | #include <unistd.h> |
8 | | |
9 | | static void |
10 | | fuzz_handler(coap_resource_t *resource, coap_session_t *session, |
11 | | const coap_pdu_t *request, const coap_string_t *query, |
12 | 2.52k | coap_pdu_t *response) { |
13 | 2.52k | (void)resource; |
14 | 2.52k | (void)session; |
15 | 2.52k | (void)request; |
16 | 2.52k | (void)query; |
17 | 2.52k | response->code = COAP_RESPONSE_CODE(205); |
18 | 2.52k | } |
19 | | |
20 | | static void |
21 | | fuzz_put_handler(coap_resource_t *resource, coap_session_t *session, |
22 | | const coap_pdu_t *request, const coap_string_t *query, |
23 | 1.44k | coap_pdu_t *response) { |
24 | 1.44k | (void)resource; |
25 | 1.44k | (void)session; |
26 | 1.44k | (void)request; |
27 | 1.44k | (void)query; |
28 | 1.44k | response->code = COAP_RESPONSE_CODE(201); |
29 | 1.44k | } |
30 | | |
31 | | /* Write fuzz data to a temporary file */ |
32 | | static int |
33 | 7.57k | write_fuzz_tmp(char *path_tmpl, const uint8_t *data, size_t size) { |
34 | 7.57k | int fd = mkstemp(path_tmpl); |
35 | 7.57k | if (fd < 0) |
36 | 0 | return -1; |
37 | 7.57k | if (size > 0) { |
38 | 7.57k | ssize_t written = write(fd, data, size); |
39 | 7.57k | (void)written; |
40 | 7.57k | } |
41 | 7.57k | close(fd); |
42 | 7.57k | return 0; |
43 | 7.57k | } |
44 | | |
45 | | /* Remove a file and its working copy */ |
46 | | static void |
47 | 7.57k | remove_tmp_pair(const char *path) { |
48 | 7.57k | char tmp[256]; |
49 | 7.57k | remove(path); |
50 | 7.57k | if (snprintf(tmp, sizeof(tmp), "%s.tmp", path) < (int)sizeof(tmp)) |
51 | 7.57k | remove(tmp); |
52 | 7.57k | } |
53 | | |
54 | | int |
55 | 2.52k | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
56 | 2.52k | if (size < 4) |
57 | 2 | return 0; |
58 | | |
59 | 2.52k | if (!coap_observe_persist_is_supported()) |
60 | 0 | return 0; |
61 | | |
62 | | /* Split fuzz input across the three persist files */ |
63 | 2.52k | size_t obs_len = size / 3; |
64 | 2.52k | size_t cnt_len = size / 3; |
65 | 2.52k | size_t dyn_len = size - obs_len - cnt_len; |
66 | | |
67 | 2.52k | char obs_path[] = "/tmp/fuzz_obs_XXXXXX"; |
68 | 2.52k | char cnt_path[] = "/tmp/fuzz_cnt_XXXXXX"; |
69 | 2.52k | char dyn_path[] = "/tmp/fuzz_dyn_XXXXXX"; |
70 | | |
71 | | /* Write fuzz data to each persist file */ |
72 | 2.52k | if (write_fuzz_tmp(obs_path, data, obs_len) < 0) |
73 | 0 | return 0; |
74 | 2.52k | if (write_fuzz_tmp(cnt_path, data + obs_len, cnt_len) < 0) { |
75 | 0 | remove_tmp_pair(obs_path); |
76 | 0 | return 0; |
77 | 0 | } |
78 | 2.52k | if (write_fuzz_tmp(dyn_path, data + obs_len + cnt_len, dyn_len) < 0) { |
79 | 0 | remove_tmp_pair(obs_path); |
80 | 0 | remove_tmp_pair(cnt_path); |
81 | 0 | return 0; |
82 | 0 | } |
83 | | |
84 | 2.52k | coap_startup(); |
85 | 2.52k | coap_set_log_level(COAP_LOG_EMERG); |
86 | 2.52k | coap_debug_set_packet_loss("100%"); |
87 | | |
88 | 2.52k | coap_context_t *ctx = coap_new_context(NULL); |
89 | 2.52k | if (!ctx) |
90 | 0 | goto cleanup_files; |
91 | | |
92 | | /* Create a UDP endpoint for session lookup */ |
93 | 2.52k | coap_address_t addr; |
94 | 2.52k | coap_address_init(&addr); |
95 | 2.52k | addr.addr.sa.sa_family = AF_INET; |
96 | 2.52k | coap_endpoint_t *ep = coap_new_endpoint(ctx, &addr, COAP_PROTO_UDP); |
97 | 2.52k | if (!ep) |
98 | 0 | goto cleanup_ctx; |
99 | | |
100 | | /* Create an observable resource */ |
101 | 2.52k | coap_resource_t *res = coap_resource_init(coap_make_str_const("obs"), 0); |
102 | 2.52k | if (!res) |
103 | 0 | goto cleanup_ctx; |
104 | 2.52k | res->observable = 1; |
105 | 2.52k | coap_register_request_handler(res, COAP_REQUEST_GET, fuzz_handler); |
106 | 2.52k | coap_add_resource(ctx, res); |
107 | | |
108 | | /* Register an unknown resource handler */ |
109 | 2.52k | coap_resource_t *unknown = coap_resource_unknown_init(fuzz_put_handler); |
110 | 2.52k | if (unknown) |
111 | 2.52k | coap_add_resource(ctx, unknown); |
112 | | |
113 | | /* Load persisted state from the three files */ |
114 | 2.52k | coap_persist_startup(ctx, dyn_path, obs_path, cnt_path, 1); |
115 | | |
116 | | /* Create a client session for write-back callback exercises */ |
117 | 2.52k | coap_session_t *sess = coap_new_client_session(ctx, NULL, &addr, |
118 | 2.52k | COAP_PROTO_UDP); |
119 | 2.52k | if (!sess) |
120 | 0 | goto cleanup_persist; |
121 | 2.52k | sess->endpoint = ep; |
122 | | |
123 | | /* Build a GET+OBSERVE PDU */ |
124 | 2.52k | coap_pdu_t *pdu = coap_pdu_init(COAP_MESSAGE_CON, COAP_REQUEST_CODE_GET, |
125 | 2.52k | coap_new_message_id(sess), 256); |
126 | 2.52k | if (pdu) { |
127 | 2.52k | uint8_t obs_val = 0; |
128 | 2.52k | coap_insert_option(pdu, COAP_OPTION_OBSERVE, 1, &obs_val); |
129 | 2.52k | coap_add_option(pdu, COAP_OPTION_URI_PATH, 3, (const uint8_t *)"obs"); |
130 | | |
131 | 2.52k | size_t tok_len = (data[0] % 8) + 1; |
132 | 2.52k | if (tok_len > size) |
133 | 5 | tok_len = 1; |
134 | 2.52k | coap_add_token(pdu, tok_len, data); |
135 | | |
136 | | /* Register a subscription and trigger the observe added callback */ |
137 | 2.52k | coap_lock_lock(goto cleanup_persist); |
138 | 2.52k | coap_subscription_t *sub = coap_add_observer(res, sess, &pdu->actual_token, |
139 | 2.52k | pdu); |
140 | 2.52k | coap_lock_unlock(); |
141 | 2.52k | if (sub) { |
142 | 2.52k | coap_find_observer(res, sess, &pdu->actual_token); |
143 | 2.52k | coap_touch_observer(ctx, sess, &pdu->actual_token); |
144 | | |
145 | | /* Trigger the counter tracking callback */ |
146 | 2.52k | coap_resource_notify_observers(res, NULL); |
147 | | |
148 | 2.52k | if (data[1] & 0x01) { |
149 | | /* Delete the subscription and trigger the observe deleted callback */ |
150 | 1.03k | coap_lock_lock(return 0); |
151 | 1.03k | coap_delete_observer(res, sess, &pdu->actual_token); |
152 | 1.03k | coap_lock_unlock(); |
153 | 1.03k | } |
154 | 2.52k | } |
155 | | |
156 | | /* Set the observe sequence number */ |
157 | 2.52k | coap_persist_set_observe_num(res, (uint32_t)data[2] << 8 | data[3]); |
158 | | |
159 | 2.52k | coap_delete_pdu(pdu); |
160 | 2.52k | } |
161 | | |
162 | 2.52k | cleanup_persist: |
163 | | /* Stop persist and disable callbacks */ |
164 | 2.52k | coap_persist_stop(ctx); |
165 | | |
166 | | /* Clear the endpoint pointer before context teardown */ |
167 | 2.52k | if (sess) |
168 | 2.52k | sess->endpoint = NULL; |
169 | | |
170 | 2.52k | cleanup_ctx: |
171 | 2.52k | coap_free_context(ctx); |
172 | 2.52k | coap_cleanup(); |
173 | | |
174 | 2.52k | cleanup_files: |
175 | 2.52k | remove_tmp_pair(obs_path); |
176 | 2.52k | remove_tmp_pair(cnt_path); |
177 | 2.52k | remove_tmp_pair(dyn_path); |
178 | | |
179 | 2.52k | return 0; |
180 | 2.52k | } |