Skip to content

Commit 3eeedd8

Browse files
author
Chandra Pratap
committed
fuzz-tests: Add a test for peer_init_received()
Changelog-None: `peer_init_received()` in `connectd/peer_exchange_initmsg.{c, h}` is responsible for handling `init` messages defined in BOLT #1. Since it deals with untrusted input, add a test for it.
1 parent ad2dc97 commit 3eeedd8

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed

tests/fuzz/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ FUZZ_COMMON_OBJS := \
3636
common/daemon_conn.o \
3737
common/derive_basepoints.o \
3838
common/descriptor_checksum.o \
39+
common/dev_disconnect.o \
3940
common/features.o \
4041
common/fee_states.o \
4142
common/hash_u5.o \
@@ -58,6 +59,7 @@ FUZZ_COMMON_OBJS := \
5859
common/status_wiregen.o \
5960
common/utils.o \
6061
common/version.o \
62+
common/wire_error.o \
6163
wire/bolt12_wiregen.o \
6264
wire/fromwire.o \
6365
wire/onion_wiregen.o \

tests/fuzz/fuzz-init_received.c

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
#include "config.h"
2+
#include <assert.h>
3+
#include <stdio.h>
4+
#include <fcntl.h>
5+
#include <ccan/ccan/io/io.h>
6+
#include <ccan/ccan/str/hex/hex.h>
7+
#include <common/dev_disconnect.h>
8+
#include <common/setup.h>
9+
#include <common/status.h>
10+
#include <tests/fuzz/libfuzz.h>
11+
12+
static struct io_plan *test_write(struct io_conn *conn, const void *data,
13+
size_t len, struct io_plan *(*next)(struct io_conn *, void *), void *arg);
14+
15+
static struct io_plan *test_read(struct io_conn *conn, void *data, size_t len,
16+
struct io_plan *(*next)(struct io_conn *, void *), void *arg);
17+
18+
#undef io_write
19+
#define io_write(conn, data, len, cb, cb_arg) \
20+
test_write((conn), \
21+
(data), \
22+
(len), \
23+
(struct io_plan *(*)(struct io_conn *, void *))(cb), \
24+
(void *)(cb_arg))
25+
26+
#undef io_read
27+
#define io_read(conn, data, len, cb, cb_arg) \
28+
test_read((conn), \
29+
(data), \
30+
(len), \
31+
(struct io_plan *(*)(struct io_conn *, void *))(cb), \
32+
(void *)(cb_arg))
33+
34+
#include "../../connectd/peer_exchange_initmsg.c"
35+
36+
/* MOCKS START */
37+
bool address_routable(const struct wireaddr *wireaddr UNNEEDED,
38+
bool allow_localhost UNNEEDED)
39+
{ return false; }
40+
struct io_plan *peer_connected(struct io_conn *conn UNNEEDED,
41+
struct daemon *daemon UNNEEDED,
42+
const struct node_id *id UNNEEDED,
43+
const struct wireaddr_internal *addr UNNEEDED,
44+
const struct wireaddr *remote_addr UNNEEDED,
45+
struct crypto_state *cs UNNEEDED,
46+
const u8 *their_features TAKES UNNEEDED,
47+
enum is_websocket is_websocket UNNEEDED,
48+
bool incoming UNNEEDED)
49+
{ return io_close(conn); }
50+
/* MOCKS END */
51+
52+
#define IO_BUFFER_SIZE (1024 * 1024)
53+
static u8 io_buffer[IO_BUFFER_SIZE];
54+
static size_t io_buf_len = 0;
55+
static size_t io_buf_pos = 0;
56+
57+
static struct io_plan *
58+
test_write(struct io_conn *conn, const void *data, size_t len,
59+
struct io_plan *(*next)(struct io_conn *, void *), void *arg)
60+
{
61+
/* append up to available space */
62+
size_t space = IO_BUFFER_SIZE - io_buf_len;
63+
size_t to_copy = len < space ? len : space;
64+
memcpy(io_buffer + io_buf_len, data, to_copy);
65+
io_buf_len += to_copy;
66+
/* simulate as if all bytes were written */
67+
return next(conn, arg);
68+
}
69+
70+
static struct io_plan *
71+
test_read(struct io_conn *conn, void *data, size_t len,
72+
struct io_plan *(*next)(struct io_conn *, void *), void *arg)
73+
{
74+
/* read up to available data */
75+
size_t available = io_buf_len - io_buf_pos;
76+
size_t to_copy = len < available ? len : available;
77+
if (to_copy > 0) {
78+
memcpy(data, io_buffer + io_buf_pos, to_copy);
79+
io_buf_pos += to_copy;
80+
}
81+
/* if buffer is exhausted, reset pointers */
82+
if (io_buf_pos == io_buf_len)
83+
io_buf_pos = io_buf_len = 0;
84+
return next(conn, arg);
85+
}
86+
87+
static struct secret secret_from_hex(const char *hex)
88+
{
89+
struct secret secret;
90+
hex += 2;
91+
if (!hex_decode(hex, strlen(hex), &secret, sizeof(secret)))
92+
abort();
93+
return secret;
94+
}
95+
96+
/* Encodes the given message. Stores the decrypting crypto_state in `cs`. */
97+
static u8 *encode_msg(const tal_t *ctx, const void *message, size_t size, struct crypto_state *cs)
98+
{
99+
struct crypto_state cs_out, cs_in;
100+
struct secret sk, rk, ck;
101+
u16 len;
102+
103+
void *msg = tal_dup_arr(ctx, char, message, size, 0);
104+
105+
ck = secret_from_hex("0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01");
106+
sk = secret_from_hex("0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9");
107+
rk = secret_from_hex("0xbb9020b8965f4df047e07f955f3c4b88418984aadc5cdb35096b9ea8fa5c3442");
108+
109+
cs_out.sn = cs_out.rn = cs_in.sn = cs_in.rn = 0;
110+
cs_out.sk = cs_in.rk = sk;
111+
cs_out.rk = cs_in.sk = rk;
112+
cs_out.s_ck = cs_out.r_ck = cs_in.s_ck = cs_in.r_ck = ck;
113+
114+
u8 *encoded_msg = cryptomsg_encrypt_msg(ctx, &cs_out, msg);
115+
116+
if (!cryptomsg_decrypt_header(&cs_in, encoded_msg, &len))
117+
abort();
118+
119+
/* Trim header */
120+
memmove(encoded_msg, encoded_msg + CRYPTOMSG_HDR_SIZE,
121+
tal_bytelen(encoded_msg) - CRYPTOMSG_HDR_SIZE);
122+
tal_resize(&encoded_msg, tal_bytelen(encoded_msg) - CRYPTOMSG_HDR_SIZE);
123+
124+
*cs = cs_in;
125+
return encoded_msg;
126+
}
127+
128+
static struct io_plan *do_nothing(struct io_conn *conn, void *side)
129+
{
130+
return io_close(conn);
131+
}
132+
133+
void init(int *argc, char ***argv)
134+
{
135+
chainparams = chainparams_for_network("bitcoin");
136+
common_setup("fuzzer");
137+
int devnull = open("/dev/null", O_WRONLY);
138+
status_setup_sync(devnull);
139+
}
140+
141+
void run(const uint8_t *data, size_t size)
142+
{
143+
struct io_conn *conn;
144+
struct crypto_state cs;
145+
struct early_peer *peer;
146+
u8 *encoded_msg;
147+
const tal_t *run_ctx = tal(NULL, void);
148+
149+
encoded_msg = encode_msg(run_ctx, data, size, &cs);
150+
peer = tal(run_ctx, struct early_peer);
151+
peer->cs = cs;
152+
peer->msg = encoded_msg;
153+
peer->incoming = true;
154+
peer->daemon = talz(run_ctx, struct daemon);
155+
peer->timeout = NULL;
156+
157+
conn = io_new_conn(run_ctx, -1, do_nothing, NULL);
158+
peer_init_received(conn, peer);
159+
160+
tal_free(run_ctx);
161+
}

0 commit comments

Comments
 (0)