|
| 1 | +// FUZZER COMMANDS: |
| 2 | +// RUSTFLAGS="--cfg hashes_fuzz --cfg=secp256k1_fuzz" cargo +nightly fuzz run --features "libfuzzer_fuzz" process_onion_failure_target |
| 3 | +// RUSTFLAGS="--cfg hashes_fuzz --cfg=secp256k1_fuzz" cargo +nightly fuzz coverage -v --features "libfuzzer_fuzz" process_onion_failure_target |
| 4 | +// llvm-cov show target/aarch64-apple-darwin/coverage/aarch64-apple-darwin/release/process_onion_failure_target --instr-profile=/Users/joost/repo/rust-lightning/fuzz/coverage/process_onion_failure_target/coverage.profdata --format=html --output-dir=reports |
| 5 | + |
| 6 | +use std::sync::Arc; |
| 7 | + |
| 8 | +use bitcoin::{ |
| 9 | + key::Secp256k1, |
| 10 | + secp256k1::{PublicKey, SecretKey}, |
| 11 | +}; |
| 12 | +use lightning::{ |
| 13 | + blinded_path::BlindedHop, |
| 14 | + ln::{ |
| 15 | + channelmanager::{HTLCSource, PaymentId}, |
| 16 | + msgs::OnionErrorPacket, |
| 17 | + }, |
| 18 | + routing::router::{BlindedTail, Path, RouteHop, TrampolineHop}, |
| 19 | + types::features::{ChannelFeatures, NodeFeatures}, |
| 20 | + util::logger::Logger, |
| 21 | +}; |
| 22 | + |
| 23 | +// Imports that need to be added manually |
| 24 | +use crate::utils::test_logger::{self}; |
| 25 | + |
| 26 | +/// Actual fuzz test, method signature and name are fixed |
| 27 | +fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) { |
| 28 | + let mut read_pos = 0; |
| 29 | + macro_rules! get_slice { |
| 30 | + ($len: expr) => {{ |
| 31 | + let slice_len = $len as usize; |
| 32 | + if data.len() < read_pos + slice_len { |
| 33 | + return; |
| 34 | + } |
| 35 | + read_pos += slice_len; |
| 36 | + &data[read_pos - slice_len..read_pos] |
| 37 | + }}; |
| 38 | + } |
| 39 | + |
| 40 | + macro_rules! get_u8 { |
| 41 | + () => { |
| 42 | + get_slice!(1)[0] |
| 43 | + }; |
| 44 | + } |
| 45 | + |
| 46 | + macro_rules! get_u16 { |
| 47 | + () => { |
| 48 | + match get_slice!(2).try_into() { |
| 49 | + Ok(val) => u16::from_be_bytes(val), |
| 50 | + Err(_) => return, |
| 51 | + } |
| 52 | + }; |
| 53 | + } |
| 54 | + |
| 55 | + macro_rules! get_u32 { |
| 56 | + () => { |
| 57 | + match get_slice!(4).try_into() { |
| 58 | + Ok(val) => u32::from_be_bytes(val), |
| 59 | + Err(_) => return, |
| 60 | + } |
| 61 | + }; |
| 62 | + } |
| 63 | + |
| 64 | + macro_rules! get_u64 { |
| 65 | + () => { |
| 66 | + match get_slice!(8).try_into() { |
| 67 | + Ok(val) => u64::from_be_bytes(val), |
| 68 | + Err(_) => return, |
| 69 | + } |
| 70 | + }; |
| 71 | + } |
| 72 | + |
| 73 | + macro_rules! get_bool { |
| 74 | + () => { |
| 75 | + get_slice!(1)[0] != 0 |
| 76 | + }; |
| 77 | + } |
| 78 | + |
| 79 | + macro_rules! get_pubkey { |
| 80 | + () => { |
| 81 | + match PublicKey::from_slice(get_slice!(33)) { |
| 82 | + Ok(val) => val, |
| 83 | + Err(_) => return, |
| 84 | + } |
| 85 | + }; |
| 86 | + } |
| 87 | + |
| 88 | + let secp_ctx = Secp256k1::new(); |
| 89 | + let logger: Arc<dyn Logger> = Arc::new(test_logger::TestLogger::new("".to_owned(), out)); |
| 90 | + |
| 91 | + let session_priv = match SecretKey::from_slice(get_slice!(32)) { |
| 92 | + Ok(val) => val, |
| 93 | + Err(_) => return, |
| 94 | + }; |
| 95 | + |
| 96 | + let payment_id = match get_slice!(32).try_into() { |
| 97 | + Ok(val) => PaymentId(val), |
| 98 | + Err(_) => return, |
| 99 | + }; |
| 100 | + |
| 101 | + let mut hops = Vec::<RouteHop>::new(); |
| 102 | + let hop_count = get_slice!(1)[0] as usize; |
| 103 | + for _ in 0..hop_count { |
| 104 | + hops.push(RouteHop { |
| 105 | + pubkey: get_pubkey!(), |
| 106 | + node_features: NodeFeatures::empty(), |
| 107 | + short_channel_id: get_u64!(), |
| 108 | + channel_features: ChannelFeatures::empty(), |
| 109 | + fee_msat: get_u64!(), |
| 110 | + cltv_expiry_delta: get_u32!(), |
| 111 | + maybe_announced_channel: get_bool!(), |
| 112 | + }); |
| 113 | + } |
| 114 | + |
| 115 | + let blinded_tail = match get_bool!() { |
| 116 | + true => { |
| 117 | + let mut trampoline_hops = Vec::<TrampolineHop>::new(); |
| 118 | + let trampoline_hop_count = get_slice!(1)[0] as usize; |
| 119 | + for _ in 0..trampoline_hop_count { |
| 120 | + trampoline_hops.push(TrampolineHop { |
| 121 | + pubkey: get_pubkey!(), |
| 122 | + node_features: NodeFeatures::empty(), |
| 123 | + fee_msat: get_u64!(), |
| 124 | + cltv_expiry_delta: get_u32!(), |
| 125 | + }); |
| 126 | + } |
| 127 | + let mut blinded_hops = Vec::<BlindedHop>::new(); |
| 128 | + let blinded_hop_count = get_slice!(1)[0] as usize; |
| 129 | + for _ in 0..blinded_hop_count { |
| 130 | + blinded_hops.push(BlindedHop { |
| 131 | + blinded_node_id: get_pubkey!(), |
| 132 | + encrypted_payload: get_slice!(get_u8!()).to_vec(), |
| 133 | + }); |
| 134 | + } |
| 135 | + Some(BlindedTail { |
| 136 | + trampoline_hops, |
| 137 | + hops: blinded_hops, |
| 138 | + blinding_point: get_pubkey!(), |
| 139 | + excess_final_cltv_expiry_delta: get_u32!(), |
| 140 | + final_value_msat: get_u64!(), |
| 141 | + }) |
| 142 | + }, |
| 143 | + false => None, |
| 144 | + }; |
| 145 | + |
| 146 | + let path = Path { hops, blinded_tail }; |
| 147 | + |
| 148 | + let htlc_source = HTLCSource::OutboundRoute { |
| 149 | + path, |
| 150 | + session_priv, |
| 151 | + first_hop_htlc_msat: get_u64!(), |
| 152 | + payment_id, |
| 153 | + }; |
| 154 | + |
| 155 | + let failure_len = get_u16!(); |
| 156 | + let encrypted_packet = OnionErrorPacket { data: get_slice!(failure_len).into() }; |
| 157 | + |
| 158 | + lightning::ln::process_onion_failure(&secp_ctx, &logger, &htlc_source, encrypted_packet); |
| 159 | +} |
| 160 | + |
| 161 | +/// Method that needs to be added manually, {name}_test |
| 162 | +pub fn process_onion_failure_test<Out: test_logger::Output>(data: &[u8], out: Out) { |
| 163 | + do_test(data, out); |
| 164 | +} |
| 165 | + |
| 166 | +/// Method that needs to be added manually, {name}_run |
| 167 | +#[no_mangle] |
| 168 | +pub extern "C" fn process_onion_failure_run(data: *const u8, datalen: usize) { |
| 169 | + do_test(unsafe { std::slice::from_raw_parts(data, datalen) }, test_logger::DevNull {}); |
| 170 | +} |
0 commit comments