Coverage Report

Created: 2026-08-08 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libcoap/tests/oss-fuzz/uri_extended_target.c
Line
Count
Source
1
/* Extended URI parsing fuzzer for libcoap.
2
 *
3
 * The existing split_uri_target only calls coap_split_uri(). coap_uri.c is
4
 * sitting at ~41% line coverage in the public report, so this harness
5
 * additionally exercises:
6
 *   - coap_split_proxy_uri()      (proxy-uri scheme path)
7
 *   - coap_split_path() / coap_path_into_optlist()
8
 *   - coap_split_query() / coap_query_into_optlist()
9
 *   - coap_check_dots() (segment dot handling)
10
 *   - coap_uri_into_optlist() and coap_uri_into_optlist_abbrev()
11
 *   - coap_new_uri() / coap_clone_uri() / coap_delete_uri()
12
 *
13
 * All of these consume untrusted byte strings (a URI received over the wire
14
 * or via the CoAP Proxy-Uri option) and produce option lists used during
15
 * request processing — exactly the kind of code path an attacker controls.
16
 */
17
18
#include "coap3/coap_internal.h"
19
20
#include <stdint.h>
21
#include <stdlib.h>
22
#include <string.h>
23
24
int
25
1.75k
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
26
1.75k
  if (size < 2 || size > 4096)
27
20
    return 0;
28
29
1.73k
  coap_startup();
30
1.73k
  coap_set_log_level(COAP_LOG_EMERG);
31
32
  /* Use the first byte as a selector so a single corpus entry exercises
33
   * multiple entrypoints across iterations. */
34
1.73k
  uint8_t mode = data[0];
35
1.73k
  const uint8_t *buf = data + 1;
36
1.73k
  size_t buf_len = size - 1;
37
38
  /* coap_split_proxy_uri — different validation rules than split_uri. */
39
1.73k
  {
40
1.73k
    coap_uri_t uri;
41
1.73k
    memset(&uri, 0, sizeof(uri));
42
1.73k
    coap_split_proxy_uri(buf, buf_len, &uri);
43
1.73k
  }
44
45
  /* coap_split_uri + downstream usage. */
46
1.73k
  coap_uri_t parsed_uri;
47
1.73k
  memset(&parsed_uri, 0, sizeof(parsed_uri));
48
1.73k
  int split_ok = coap_split_uri(buf, buf_len, &parsed_uri);
49
50
  /* coap_check_dots on small windows across the buffer to drive its
51
   * percent-encoded "." / ".." special cases. */
52
13.3k
  for (size_t i = 0; i + 1 < buf_len && i < 8; i++) {
53
11.6k
    size_t window = buf_len - i;
54
11.6k
    if (window > 6)
55
9.12k
      window = 6;
56
11.6k
    coap_check_dots(buf + i, window);
57
11.6k
  }
58
59
  /* coap_split_path: writes serialised options into a caller buffer. */
60
1.73k
  {
61
1.73k
    unsigned char out[256];
62
1.73k
    size_t out_len = sizeof(out);
63
1.73k
    coap_split_path(buf, buf_len, out, &out_len);
64
1.73k
  }
65
66
  /* coap_split_query. */
67
1.73k
  {
68
1.73k
    unsigned char out[256];
69
1.73k
    size_t out_len = sizeof(out);
70
1.73k
    coap_split_query(buf, buf_len, out, &out_len);
71
1.73k
  }
72
73
  /* coap_path_into_optlist / coap_query_into_optlist — populate an
74
   * optlist chain that we must release. */
75
1.73k
  if (mode & 0x01) {
76
1.50k
    coap_optlist_t *chain = NULL;
77
1.50k
    coap_path_into_optlist(buf, buf_len, COAP_OPTION_URI_PATH, &chain);
78
1.50k
    coap_query_into_optlist(buf, buf_len, COAP_OPTION_URI_QUERY, &chain);
79
1.50k
    coap_delete_optlist(chain);
80
1.50k
  }
81
82
  /* coap_new_uri / coap_clone_uri exercise the heap-allocated URI path. */
83
1.73k
  if (mode & 0x02) {
84
1.03k
    coap_uri_t *u = coap_new_uri(buf, (unsigned int)buf_len);
85
1.03k
    if (u) {
86
416
      coap_uri_t *clone = coap_clone_uri(u);
87
416
      coap_delete_uri(clone);
88
416
      coap_delete_uri(u);
89
416
    }
90
1.03k
  }
91
92
  /* coap_uri_into_optlist: only meaningful if the URI parsed cleanly. */
93
1.73k
  if ((mode & 0x04) && split_ok == 0) {
94
645
    coap_optlist_t *chain = NULL;
95
645
    coap_uri_into_optlist(&parsed_uri, NULL, &chain, mode & 0x08 ? 1 : 0);
96
645
    coap_delete_optlist(chain);
97
645
  }
98
99
1.73k
  coap_cleanup();
100
1.73k
  return 0;
101
1.75k
}