/src/libcoap/tests/oss-fuzz/cache_key_target.c
Line | Count | Source |
1 | | /* Cache-key derivation fuzzer for libcoap. |
2 | | * |
3 | | * src/coap_cache.c is at ~21% line coverage. The cache layer derives a |
4 | | * stable key from a CoAP PDU by hashing a canonicalised view of the |
5 | | * options (with per-context "ignore" lists and the Block options handled |
6 | | * specially). The exposed entrypoints — coap_cache_derive_key / |
7 | | * coap_cache_derive_key_w_ignore / coap_cache_get_by_pdu — all consume an |
8 | | * attacker-influenced PDU. |
9 | | * |
10 | | * Strategy: parse a fuzz-supplied byte string as a CoAP UDP PDU, then |
11 | | * call every cache-key derivation entrypoint against it, varying the |
12 | | * "ignore options" set. coap_new_cache_entry is also driven on the |
13 | | * happy path so the cache-entry hash insertion (utlist macros over |
14 | | * attacker-controlled key bytes) is exercised. |
15 | | */ |
16 | | |
17 | | #include "coap3/coap_internal.h" |
18 | | #include "coap3/coap_cache.h" |
19 | | |
20 | | #include <stdint.h> |
21 | | #include <stdlib.h> |
22 | | #include <string.h> |
23 | | |
24 | | int |
25 | 60 | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
26 | 60 | if (size < 5 || size > 4096) |
27 | 24 | return 0; |
28 | | |
29 | 36 | coap_context_t *ctx = NULL; |
30 | 36 | coap_session_t *session = NULL; |
31 | 36 | coap_pdu_t *pdu = NULL; |
32 | 36 | coap_address_t addr; |
33 | | |
34 | 36 | coap_startup(); |
35 | 36 | coap_set_log_level(COAP_LOG_EMERG); |
36 | | |
37 | 36 | ctx = coap_new_context(NULL); |
38 | 36 | if (!ctx) |
39 | 0 | goto cleanup; |
40 | | |
41 | 36 | coap_address_init(&addr); |
42 | 36 | addr.addr.sa.sa_family = AF_INET; |
43 | 36 | session = coap_new_client_session(ctx, NULL, &addr, COAP_PROTO_UDP); |
44 | 36 | if (!session) |
45 | 0 | goto cleanup; |
46 | 36 | session->state = COAP_SESSION_STATE_ESTABLISHED; |
47 | | |
48 | | /* First byte selects ignore-set + session-based flag. Remaining bytes |
49 | | * are parsed as a UDP PDU. */ |
50 | 36 | uint8_t selector = data[0]; |
51 | 36 | const uint8_t *pdu_bytes = data + 1; |
52 | 36 | size_t pdu_len = size - 1; |
53 | | |
54 | 36 | pdu = coap_pdu_init(COAP_MESSAGE_CON, COAP_REQUEST_CODE_GET, 0, |
55 | 36 | coap_session_max_pdu_size(session)); |
56 | 36 | if (!pdu) |
57 | 0 | goto cleanup; |
58 | 36 | if (!coap_pdu_parse(COAP_PROTO_UDP, pdu_bytes, pdu_len, pdu)) |
59 | 34 | goto cleanup; |
60 | | |
61 | 2 | coap_cache_session_based_t sb = (selector & 0x01) |
62 | 2 | ? COAP_CACHE_IS_SESSION_BASED |
63 | 2 | : COAP_CACHE_NOT_SESSION_BASED; |
64 | | |
65 | | /* Plain derive_key. */ |
66 | 2 | { |
67 | 2 | coap_cache_key_t *k = coap_cache_derive_key(session, pdu, sb); |
68 | 2 | coap_delete_cache_key(k); |
69 | 2 | } |
70 | | |
71 | | /* derive_key_w_ignore with a small ignore list — exercises the |
72 | | * is_cache_key() option filter that walks the (option_num, ignore_count) |
73 | | * tuples. */ |
74 | 2 | { |
75 | 2 | static const uint16_t ignore_set[] = { |
76 | 2 | COAP_OPTION_ETAG, COAP_OPTION_OBSERVE, COAP_OPTION_BLOCK1, |
77 | 2 | COAP_OPTION_BLOCK2, COAP_OPTION_URI_HOST, |
78 | 2 | }; |
79 | 2 | size_t n = (selector >> 1) % (sizeof(ignore_set) / sizeof(ignore_set[0]) + 1); |
80 | 2 | coap_cache_key_t *k = coap_cache_derive_key_w_ignore(session, pdu, sb, |
81 | 2 | ignore_set, n); |
82 | 2 | coap_delete_cache_key(k); |
83 | 2 | } |
84 | | |
85 | | /* Drive coap_cache_get_by_pdu (lookup) and coap_new_cache_entry |
86 | | * (insertion + hash chain walk). */ |
87 | 2 | { |
88 | 2 | coap_cache_entry_t *entry = |
89 | 2 | coap_new_cache_entry(session, pdu, |
90 | 2 | (selector & 0x10) ? COAP_CACHE_RECORD_PDU |
91 | 2 | : COAP_CACHE_NOT_RECORD_PDU, |
92 | 2 | sb, 0); |
93 | 2 | (void)coap_cache_get_by_pdu(session, pdu, sb); |
94 | 2 | if (entry) |
95 | 2 | coap_delete_cache_entry(ctx, entry); |
96 | 2 | } |
97 | | |
98 | 36 | cleanup: |
99 | 36 | if (pdu) |
100 | 36 | coap_delete_pdu(pdu); |
101 | 36 | if (session) |
102 | 36 | coap_session_release(session); |
103 | 36 | if (ctx) |
104 | 36 | coap_free_context(ctx); |
105 | 36 | coap_cleanup(); |
106 | 36 | return 0; |
107 | 2 | } |