Coverage Report

Created: 2026-08-14 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}