Skip to content

Commit 62543a6

Browse files
authored
Merge pull request #88 from TheBlueMatt/2018-07-new-fuzzing
Add Router Fuzz Target
2 parents 29710eb + c45d8eb commit 62543a6

File tree

5 files changed

+359
-114
lines changed

5 files changed

+359
-114
lines changed

fuzz/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ path = "fuzz_targets/channel_target.rs"
4242
name = "full_stack_target"
4343
path = "fuzz_targets/full_stack_target.rs"
4444

45+
[[bin]]
46+
name = "router_target"
47+
path = "fuzz_targets/router_target.rs"
48+
4549
[[bin]]
4650
name = "chanmon_deser_target"
4751
path = "fuzz_targets/chanmon_deser_target.rs"

fuzz/fuzz_targets/channel_target.rs

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use bitcoin::network::serialize::{serialize, BitcoinHash};
1010
use lightning::ln::channel::{Channel, ChannelKeys};
1111
use lightning::ln::channelmanager::{HTLCFailReason, PendingForwardHTLCInfo};
1212
use lightning::ln::msgs;
13-
use lightning::ln::msgs::MsgDecodable;
13+
use lightning::ln::msgs::{MsgDecodable, ErrorAction};
1414
use lightning::chain::chaininterface::{FeeEstimator, ConfirmationTarget};
1515
use lightning::chain::transaction::OutPoint;
1616
use lightning::util::reset_rng_state;
@@ -120,7 +120,8 @@ pub fn do_test(data: &[u8]) {
120120
msgs::DecodeError::BadSignature => return,
121121
msgs::DecodeError::BadText => return,
122122
msgs::DecodeError::ExtraAddressesPerType => return,
123-
msgs::DecodeError::WrongLength => panic!("We picked the length..."),
123+
msgs::DecodeError::BadLengthDescriptor => return,
124+
msgs::DecodeError::ShortRead => panic!("We picked the length..."),
124125
}
125126
}
126127
}
@@ -141,7 +142,8 @@ pub fn do_test(data: &[u8]) {
141142
msgs::DecodeError::BadSignature => return,
142143
msgs::DecodeError::BadText => return,
143144
msgs::DecodeError::ExtraAddressesPerType => return,
144-
msgs::DecodeError::WrongLength => panic!("We picked the length..."),
145+
msgs::DecodeError::BadLengthDescriptor => return,
146+
msgs::DecodeError::ShortRead => panic!("We picked the length..."),
145147
}
146148
}
147149
}
@@ -237,55 +239,71 @@ pub fn do_test(data: &[u8]) {
237239
let funding_locked = decode_msg!(msgs::FundingLocked, 32+33);
238240
return_err!(channel.funding_locked(&funding_locked));
239241

242+
macro_rules! test_err {
243+
($expr: expr) => {
244+
match $expr {
245+
Ok(r) => Some(r),
246+
Err(e) => match e.action {
247+
None => return,
248+
Some(ErrorAction::UpdateFailHTLC {..}) => None,
249+
Some(ErrorAction::DisconnectPeer {..}) => return,
250+
Some(ErrorAction::IgnoreError) => None,
251+
Some(ErrorAction::SendErrorMessage {..}) => None,
252+
},
253+
}
254+
}
255+
}
256+
240257
loop {
241258
match get_slice!(1)[0] {
242259
0 => {
243-
return_err!(channel.send_htlc(slice_to_be64(get_slice!(8)), [42; 32], slice_to_be32(get_slice!(4)), msgs::OnionPacket {
260+
test_err!(channel.send_htlc(slice_to_be64(get_slice!(8)), [42; 32], slice_to_be32(get_slice!(4)), msgs::OnionPacket {
244261
version: get_slice!(1)[0],
245262
public_key: get_pubkey!(),
246263
hop_data: [0; 20*65],
247264
hmac: [0; 32],
248265
}));
249266
},
250267
1 => {
251-
return_err!(channel.send_commitment());
268+
test_err!(channel.send_commitment());
252269
},
253270
2 => {
254271
let update_add_htlc = decode_msg!(msgs::UpdateAddHTLC, 32+8+8+32+4+4+33+20*65+32);
255-
return_err!(channel.update_add_htlc(&update_add_htlc, PendingForwardHTLCInfo::dummy()));
272+
test_err!(channel.update_add_htlc(&update_add_htlc, PendingForwardHTLCInfo::dummy()));
256273
},
257274
3 => {
258275
let update_fulfill_htlc = decode_msg!(msgs::UpdateFulfillHTLC, 32 + 8 + 32);
259-
return_err!(channel.update_fulfill_htlc(&update_fulfill_htlc));
276+
test_err!(channel.update_fulfill_htlc(&update_fulfill_htlc));
260277
},
261278
4 => {
262279
let update_fail_htlc = decode_msg_with_len16!(msgs::UpdateFailHTLC, 32 + 8, 1);
263-
return_err!(channel.update_fail_htlc(&update_fail_htlc, HTLCFailReason::dummy()));
280+
test_err!(channel.update_fail_htlc(&update_fail_htlc, HTLCFailReason::dummy()));
264281
},
265282
5 => {
266283
let update_fail_malformed_htlc = decode_msg!(msgs::UpdateFailMalformedHTLC, 32+8+32+2);
267-
return_err!(channel.update_fail_malformed_htlc(&update_fail_malformed_htlc, HTLCFailReason::dummy()));
284+
test_err!(channel.update_fail_malformed_htlc(&update_fail_malformed_htlc, HTLCFailReason::dummy()));
268285
},
269286
6 => {
270287
let commitment_signed = decode_msg_with_len16!(msgs::CommitmentSigned, 32+64, 64);
271-
return_err!(channel.commitment_signed(&commitment_signed));
288+
test_err!(channel.commitment_signed(&commitment_signed));
272289
},
273290
7 => {
274291
let revoke_and_ack = decode_msg!(msgs::RevokeAndACK, 32+32+33);
275-
return_err!(channel.revoke_and_ack(&revoke_and_ack));
292+
test_err!(channel.revoke_and_ack(&revoke_and_ack));
276293
},
277294
8 => {
278295
let update_fee = decode_msg!(msgs::UpdateFee, 32+4);
279-
return_err!(channel.update_fee(&fee_est, &update_fee));
296+
test_err!(channel.update_fee(&fee_est, &update_fee));
280297
},
281298
9 => {
282299
let shutdown = decode_msg_with_len16!(msgs::Shutdown, 32, 1);
283-
return_err!(channel.shutdown(&fee_est, &shutdown));
300+
test_err!(channel.shutdown(&fee_est, &shutdown));
284301
if channel.is_shutdown() { return; }
285302
},
286303
10 => {
287304
let closing_signed = decode_msg!(msgs::ClosingSigned, 32+8+64);
288-
if return_err!(channel.closing_signed(&fee_est, &closing_signed)).1.is_some() {
305+
let sign_res = test_err!(channel.closing_signed(&fee_est, &closing_signed));
306+
if sign_res.is_some() && sign_res.unwrap().1.is_some() {
289307
assert!(channel.is_shutdown());
290308
return;
291309
}

fuzz/fuzz_targets/router_target.rs

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
extern crate bitcoin;
2+
extern crate lightning;
3+
extern crate secp256k1;
4+
5+
use lightning::ln::channelmanager::ChannelDetails;
6+
use lightning::ln::msgs;
7+
use lightning::ln::msgs::{MsgDecodable, RoutingMessageHandler};
8+
use lightning::ln::router::{Router, RouteHint};
9+
use lightning::util::reset_rng_state;
10+
11+
use secp256k1::key::PublicKey;
12+
use secp256k1::Secp256k1;
13+
14+
#[inline]
15+
pub fn slice_to_be16(v: &[u8]) -> u16 {
16+
((v[0] as u16) << 8*1) |
17+
((v[1] as u16) << 8*0)
18+
}
19+
20+
#[inline]
21+
pub fn slice_to_be32(v: &[u8]) -> u32 {
22+
((v[0] as u32) << 8*3) |
23+
((v[1] as u32) << 8*2) |
24+
((v[2] as u32) << 8*1) |
25+
((v[3] as u32) << 8*0)
26+
}
27+
28+
#[inline]
29+
pub fn slice_to_be64(v: &[u8]) -> u64 {
30+
((v[0] as u64) << 8*7) |
31+
((v[1] as u64) << 8*6) |
32+
((v[2] as u64) << 8*5) |
33+
((v[3] as u64) << 8*4) |
34+
((v[4] as u64) << 8*3) |
35+
((v[5] as u64) << 8*2) |
36+
((v[6] as u64) << 8*1) |
37+
((v[7] as u64) << 8*0)
38+
}
39+
40+
#[inline]
41+
pub fn do_test(data: &[u8]) {
42+
reset_rng_state();
43+
44+
let mut read_pos = 0;
45+
macro_rules! get_slice_nonadvancing {
46+
($len: expr) => {
47+
{
48+
if data.len() < read_pos + $len as usize {
49+
return;
50+
}
51+
&data[read_pos..read_pos + $len as usize]
52+
}
53+
}
54+
}
55+
macro_rules! get_slice {
56+
($len: expr) => {
57+
{
58+
let res = get_slice_nonadvancing!($len);
59+
read_pos += $len;
60+
res
61+
}
62+
}
63+
}
64+
65+
macro_rules! decode_msg {
66+
($MsgType: path, $len: expr) => {
67+
match <($MsgType)>::decode(get_slice!($len)) {
68+
Ok(msg) => msg,
69+
Err(e) => match e {
70+
msgs::DecodeError::UnknownRealmByte => return,
71+
msgs::DecodeError::BadPublicKey => return,
72+
msgs::DecodeError::BadSignature => return,
73+
msgs::DecodeError::BadText => return,
74+
msgs::DecodeError::ExtraAddressesPerType => return,
75+
msgs::DecodeError::BadLengthDescriptor => return,
76+
msgs::DecodeError::ShortRead => panic!("We picked the length..."),
77+
}
78+
}
79+
}
80+
}
81+
82+
macro_rules! decode_msg_with_len16 {
83+
($MsgType: path, $begin_len: expr, $excess: expr) => {
84+
{
85+
let extra_len = slice_to_be16(&get_slice_nonadvancing!($begin_len as usize + 2)[$begin_len..$begin_len + 2]);
86+
decode_msg!($MsgType, $begin_len as usize + 2 + (extra_len as usize) + $excess)
87+
}
88+
}
89+
}
90+
91+
let secp_ctx = Secp256k1::new();
92+
macro_rules! get_pubkey {
93+
() => {
94+
match PublicKey::from_slice(&secp_ctx, get_slice!(33)) {
95+
Ok(key) => key,
96+
Err(_) => return,
97+
}
98+
}
99+
}
100+
101+
let our_pubkey = get_pubkey!();
102+
let router = Router::new(our_pubkey.clone());
103+
104+
loop {
105+
match get_slice!(1)[0] {
106+
0 => {
107+
let start_len = slice_to_be16(&get_slice_nonadvancing!(64 + 2)[64..64 + 2]) as usize;
108+
let addr_len = slice_to_be16(&get_slice_nonadvancing!(64+start_len+2 + 74)[64+start_len+2 + 72..64+start_len+2 + 74]);
109+
if addr_len > (37+1)*4 {
110+
return;
111+
}
112+
let _ = router.handle_node_announcement(&decode_msg_with_len16!(msgs::NodeAnnouncement, 64, 288));
113+
},
114+
1 => {
115+
let _ = router.handle_channel_announcement(&decode_msg_with_len16!(msgs::ChannelAnnouncement, 64*4, 32+8+33*4));
116+
},
117+
2 => {
118+
let _ = router.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 128));
119+
},
120+
3 => {
121+
match get_slice!(1)[0] {
122+
0 => {
123+
router.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 128)});
124+
},
125+
1 => {
126+
let short_channel_id = slice_to_be64(get_slice!(8));
127+
router.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelClosed {short_channel_id});
128+
},
129+
_ => return,
130+
}
131+
},
132+
4 => {
133+
let target = get_pubkey!();
134+
let mut first_hops_vec = Vec::new();
135+
let first_hops = match get_slice!(1)[0] {
136+
0 => None,
137+
1 => {
138+
let count = slice_to_be16(get_slice!(2));
139+
for _ in 0..count {
140+
first_hops_vec.push(ChannelDetails {
141+
channel_id: [0; 32],
142+
short_channel_id: Some(slice_to_be64(get_slice!(8))),
143+
remote_network_id: get_pubkey!(),
144+
channel_value_satoshis: slice_to_be64(get_slice!(8)),
145+
user_id: 0,
146+
});
147+
}
148+
Some(&first_hops_vec[..])
149+
},
150+
_ => return,
151+
};
152+
let mut last_hops_vec = Vec::new();
153+
let last_hops = {
154+
let count = slice_to_be16(get_slice!(2));
155+
for _ in 0..count {
156+
last_hops_vec.push(RouteHint {
157+
src_node_id: get_pubkey!(),
158+
short_channel_id: slice_to_be64(get_slice!(8)),
159+
fee_base_msat: slice_to_be64(get_slice!(8)),
160+
fee_proportional_millionths: slice_to_be32(get_slice!(4)),
161+
cltv_expiry_delta: slice_to_be16(get_slice!(2)),
162+
htlc_minimum_msat: slice_to_be64(get_slice!(8)),
163+
});
164+
}
165+
&last_hops_vec[..]
166+
};
167+
let _ = router.get_route(&target, first_hops, last_hops, slice_to_be64(get_slice!(8)), slice_to_be32(get_slice!(4)));
168+
},
169+
_ => return,
170+
}
171+
}
172+
}
173+
174+
#[cfg(feature = "afl")]
175+
extern crate afl;
176+
#[cfg(feature = "afl")]
177+
fn main() {
178+
afl::read_stdio_bytes(|data| {
179+
do_test(&data);
180+
});
181+
}
182+
183+
#[cfg(feature = "honggfuzz")]
184+
#[macro_use] extern crate honggfuzz;
185+
#[cfg(feature = "honggfuzz")]
186+
fn main() {
187+
loop {
188+
fuzz!(|data| {
189+
do_test(data);
190+
});
191+
}
192+
}
193+
194+
#[cfg(test)]
195+
mod tests {
196+
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
197+
let mut b = 0;
198+
for (idx, c) in hex.as_bytes().iter().enumerate() {
199+
b <<= 4;
200+
match *c {
201+
b'A'...b'F' => b |= c - b'A' + 10,
202+
b'a'...b'f' => b |= c - b'a' + 10,
203+
b'0'...b'9' => b |= c - b'0',
204+
_ => panic!("Bad hex"),
205+
}
206+
if (idx & 1) == 1 {
207+
out.push(b);
208+
b = 0;
209+
}
210+
}
211+
}
212+
213+
#[test]
214+
fn duplicate_crash() {
215+
let mut a = Vec::new();
216+
extend_vec_from_hex("00", &mut a);
217+
super::do_test(&a);
218+
}
219+
}

0 commit comments

Comments
 (0)