Skip to content

Commit 63c1fa6

Browse files
authored
Merge pull request #395 from ariard/2019-11-expected-amt-claim-funds
Avoid probing attacks with same hash lower amounts
2 parents ae0ad19 + 5e047cc commit 63c1fa6

6 files changed

+206
-145
lines changed

fuzz/fuzz_targets/chanmon_fail_consistency.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ pub fn do_test(data: &[u8]) {
609609
if $fail {
610610
assert!(nodes[$node].fail_htlc_backwards(&payment_hash));
611611
} else {
612-
assert!(nodes[$node].claim_funds(PaymentPreimage(payment_hash.0)));
612+
assert!(nodes[$node].claim_funds(PaymentPreimage(payment_hash.0), 5_000_000));
613613
}
614614
}
615615
},

fuzz/fuzz_targets/full_stack_target.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ pub fn do_test(data: &[u8], logger: &Arc<Logger>) {
341341
}, our_network_key, &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0], Arc::clone(&logger)));
342342

343343
let mut should_forward = false;
344-
let mut payments_received: Vec<PaymentHash> = Vec::new();
344+
let mut payments_received: Vec<(PaymentHash, u64)> = Vec::new();
345345
let mut payments_sent = 0;
346346
let mut pending_funding_generation: Vec<([u8; 32], u64, Script)> = Vec::new();
347347
let mut pending_funding_signatures = HashMap::new();
@@ -426,7 +426,7 @@ pub fn do_test(data: &[u8], logger: &Arc<Logger>) {
426426
}
427427
},
428428
8 => {
429-
for payment in payments_received.drain(..) {
429+
for (payment, amt) in payments_received.drain(..) {
430430
// SHA256 is defined as XOR of all input bytes placed in the first byte, and 0s
431431
// for the remaining bytes. Thus, if not all remaining bytes are 0s we cannot
432432
// fulfill this HTLC, but if they are, we can just take the first byte and
@@ -436,12 +436,12 @@ pub fn do_test(data: &[u8], logger: &Arc<Logger>) {
436436
} else {
437437
let mut payment_preimage = PaymentPreimage([0; 32]);
438438
payment_preimage.0[0] = payment.0[0];
439-
channelmanager.claim_funds(payment_preimage);
439+
channelmanager.claim_funds(payment_preimage, amt);
440440
}
441441
}
442442
},
443443
9 => {
444-
for payment in payments_received.drain(..) {
444+
for (payment, _) in payments_received.drain(..) {
445445
channelmanager.fail_htlc_backwards(&payment);
446446
}
447447
},
@@ -516,8 +516,9 @@ pub fn do_test(data: &[u8], logger: &Arc<Logger>) {
516516
Event::FundingBroadcastSafe { funding_txo, .. } => {
517517
pending_funding_relay.push(pending_funding_signatures.remove(&funding_txo).unwrap());
518518
},
519-
Event::PaymentReceived { payment_hash, .. } => {
520-
payments_received.push(payment_hash);
519+
Event::PaymentReceived { payment_hash, amt } => {
520+
//TODO: enhance by fetching random amounts from fuzz input?
521+
payments_received.push((payment_hash, amt));
521522
},
522523
Event::PaymentSent {..} => {},
523524
Event::PaymentFailed {..} => {},

src/ln/chanmon_update_fail_tests.rs

+27-27
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ fn do_test_simple_monitor_temporary_update_fail(disconnect: bool) {
9191
_ => panic!("Unexpected event"),
9292
}
9393

94-
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_1);
94+
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_1, 1_000_000);
9595

9696
// Now set it to failed again...
9797
let (_, payment_hash_2) = get_payment_preimage_hash!(nodes[0]);
@@ -166,7 +166,7 @@ fn do_test_monitor_temporary_update_fail(disconnect_count: usize) {
166166

167167
// Claim the previous payment, which will result in a update_fulfill_htlc/CS from nodes[1]
168168
// but nodes[0] won't respond since it is frozen.
169-
assert!(nodes[1].node.claim_funds(payment_preimage_1));
169+
assert!(nodes[1].node.claim_funds(payment_preimage_1, 1_000_000));
170170
check_added_monitors!(nodes[1], 1);
171171
let events_2 = nodes[1].node.get_and_clear_pending_msg_events();
172172
assert_eq!(events_2.len(), 1);
@@ -440,7 +440,7 @@ fn do_test_monitor_temporary_update_fail(disconnect_count: usize) {
440440
_ => panic!("Unexpected event"),
441441
}
442442

443-
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_2);
443+
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_2, 1_000_000);
444444
}
445445

446446
#[test]
@@ -544,7 +544,7 @@ fn test_monitor_update_fail_cs() {
544544
_ => panic!("Unexpected event"),
545545
};
546546

547-
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage);
547+
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage, 1_000_000);
548548
}
549549

550550
#[test]
@@ -587,7 +587,7 @@ fn test_monitor_update_fail_no_rebroadcast() {
587587
_ => panic!("Unexpected event"),
588588
}
589589

590-
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_1);
590+
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_1, 1_000_000);
591591
}
592592

593593
#[test]
@@ -597,7 +597,7 @@ fn test_monitor_update_raa_while_paused() {
597597
let mut nodes = create_network(2, &[None, None]);
598598
create_announced_chan_between_nodes(&nodes, 0, 1, LocalFeatures::new(), LocalFeatures::new());
599599

600-
send_payment(&nodes[0], &[&nodes[1]], 5000000);
600+
send_payment(&nodes[0], &[&nodes[1]], 5000000, 5_000_000);
601601

602602
let route = nodes[0].router.get_route(&nodes[1].node.get_our_node_id(), None, &Vec::new(), 1000000, TEST_FINAL_CLTV).unwrap();
603603
let (payment_preimage_1, our_payment_hash_1) = get_payment_preimage_hash!(nodes[0]);
@@ -655,8 +655,8 @@ fn test_monitor_update_raa_while_paused() {
655655
expect_pending_htlcs_forwardable!(nodes[1]);
656656
expect_payment_received!(nodes[1], our_payment_hash_1, 1000000);
657657

658-
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_1);
659-
claim_payment(&nodes[1], &[&nodes[0]], payment_preimage_2);
658+
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_1, 1_000_000);
659+
claim_payment(&nodes[1], &[&nodes[0]], payment_preimage_2, 1_000_000);
660660
}
661661

662662
fn do_test_monitor_update_fail_raa(test_ignore_second_cs: bool) {
@@ -666,7 +666,7 @@ fn do_test_monitor_update_fail_raa(test_ignore_second_cs: bool) {
666666
let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2, LocalFeatures::new(), LocalFeatures::new());
667667

668668
// Rebalance a bit so that we can send backwards from 2 to 1.
669-
send_payment(&nodes[0], &[&nodes[1], &nodes[2]], 5000000);
669+
send_payment(&nodes[0], &[&nodes[1], &nodes[2]], 5000000, 5_000_000);
670670

671671
// Route a first payment that we'll fail backwards
672672
let (_, payment_hash_1) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 1000000);
@@ -897,10 +897,10 @@ fn do_test_monitor_update_fail_raa(test_ignore_second_cs: bool) {
897897
Event::PaymentReceived { payment_hash, .. } => assert_eq!(payment_hash, payment_hash_4.unwrap()),
898898
_ => panic!("Unexpected event"),
899899
};
900-
claim_payment(&nodes[2], &[&nodes[1], &nodes[0]], payment_preimage_4.unwrap());
900+
claim_payment(&nodes[2], &[&nodes[1], &nodes[0]], payment_preimage_4.unwrap(), 1_000_000);
901901
}
902902

903-
claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage_2);
903+
claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage_2, 1_000_000);
904904
}
905905

906906
#[test]
@@ -923,7 +923,7 @@ fn test_monitor_update_fail_reestablish() {
923923
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
924924
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
925925

926-
assert!(nodes[2].node.claim_funds(our_payment_preimage));
926+
assert!(nodes[2].node.claim_funds(our_payment_preimage, 1_000_000));
927927
check_added_monitors!(nodes[2], 1);
928928
let mut updates = get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id());
929929
assert!(updates.update_add_htlcs.is_empty());
@@ -1092,9 +1092,9 @@ fn raa_no_response_awaiting_raa_state() {
10921092
expect_pending_htlcs_forwardable!(nodes[1]);
10931093
expect_payment_received!(nodes[1], payment_hash_3, 1000000);
10941094

1095-
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_1);
1096-
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_2);
1097-
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_3);
1095+
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_1, 1_000_000);
1096+
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_2, 1_000_000);
1097+
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_3, 1_000_000);
10981098
}
10991099

11001100
#[test]
@@ -1114,7 +1114,7 @@ fn claim_while_disconnected_monitor_update_fail() {
11141114
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
11151115
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
11161116

1117-
assert!(nodes[1].node.claim_funds(payment_preimage_1));
1117+
assert!(nodes[1].node.claim_funds(payment_preimage_1, 1_000_000));
11181118
check_added_monitors!(nodes[1], 1);
11191119

11201120
nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id());
@@ -1211,7 +1211,7 @@ fn claim_while_disconnected_monitor_update_fail() {
12111211
_ => panic!("Unexpected event"),
12121212
}
12131213

1214-
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_2);
1214+
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_2, 1_000_000);
12151215
}
12161216

12171217
#[test]
@@ -1271,7 +1271,7 @@ fn monitor_failed_no_reestablish_response() {
12711271
expect_pending_htlcs_forwardable!(nodes[1]);
12721272
expect_payment_received!(nodes[1], payment_hash_1, 1000000);
12731273

1274-
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_1);
1274+
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_1, 1_000_000);
12751275
}
12761276

12771277
#[test]
@@ -1360,8 +1360,8 @@ fn first_message_on_recv_ordering() {
13601360
expect_pending_htlcs_forwardable!(nodes[1]);
13611361
expect_payment_received!(nodes[1], payment_hash_2, 1000000);
13621362

1363-
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_1);
1364-
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_2);
1363+
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_1, 1_000_000);
1364+
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_2, 1_000_000);
13651365
}
13661366

13671367
#[test]
@@ -1376,12 +1376,12 @@ fn test_monitor_update_fail_claim() {
13761376
create_announced_chan_between_nodes(&nodes, 1, 2, LocalFeatures::new(), LocalFeatures::new());
13771377

13781378
// Rebalance a bit so that we can send backwards from 3 to 2.
1379-
send_payment(&nodes[0], &[&nodes[1], &nodes[2]], 5000000);
1379+
send_payment(&nodes[0], &[&nodes[1], &nodes[2]], 5000000, 5_000_000);
13801380

13811381
let (payment_preimage_1, _) = route_payment(&nodes[0], &[&nodes[1]], 1000000);
13821382

13831383
*nodes[1].chan_monitor.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::TemporaryFailure);
1384-
assert!(nodes[1].node.claim_funds(payment_preimage_1));
1384+
assert!(nodes[1].node.claim_funds(payment_preimage_1, 1_000_000));
13851385
check_added_monitors!(nodes[1], 1);
13861386

13871387
let route = nodes[2].router.get_route(&nodes[0].node.get_our_node_id(), None, &Vec::new(), 1000000, TEST_FINAL_CLTV).unwrap();
@@ -1446,7 +1446,7 @@ fn test_monitor_update_on_pending_forwards() {
14461446
create_announced_chan_between_nodes(&nodes, 1, 2, LocalFeatures::new(), LocalFeatures::new());
14471447

14481448
// Rebalance a bit so that we can send backwards from 3 to 1.
1449-
send_payment(&nodes[0], &[&nodes[1], &nodes[2]], 5000000);
1449+
send_payment(&nodes[0], &[&nodes[1], &nodes[2]], 5000000, 5_000_000);
14501450

14511451
let (_, payment_hash_1) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 1000000);
14521452
assert!(nodes[2].node.fail_htlc_backwards(&payment_hash_1));
@@ -1496,7 +1496,7 @@ fn test_monitor_update_on_pending_forwards() {
14961496
nodes[0].node.process_pending_htlc_forwards();
14971497
expect_payment_received!(nodes[0], payment_hash_2, 1000000);
14981498

1499-
claim_payment(&nodes[2], &[&nodes[1], &nodes[0]], payment_preimage_2);
1499+
claim_payment(&nodes[2], &[&nodes[1], &nodes[0]], payment_preimage_2, 1_000_000);
15001500
}
15011501

15021502
#[test]
@@ -1524,7 +1524,7 @@ fn monitor_update_claim_fail_no_response() {
15241524
let as_raa = commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false, true, false, true);
15251525

15261526
*nodes[1].chan_monitor.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::TemporaryFailure);
1527-
assert!(nodes[1].node.claim_funds(payment_preimage_1));
1527+
assert!(nodes[1].node.claim_funds(payment_preimage_1, 1_000_000));
15281528
check_added_monitors!(nodes[1], 1);
15291529
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
15301530

@@ -1551,7 +1551,7 @@ fn monitor_update_claim_fail_no_response() {
15511551
_ => panic!("Unexpected event"),
15521552
}
15531553

1554-
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_2);
1554+
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_2, 1_000_000);
15551555
}
15561556

15571557
// Note that restore_between_fails with !fail_on_generate is useless
@@ -1671,7 +1671,7 @@ fn do_during_funding_monitor_fail(fail_on_generate: bool, restore_between_fails:
16711671
node.router.handle_channel_update(&bs_update).unwrap();
16721672
}
16731673

1674-
send_payment(&nodes[0], &[&nodes[1]], 8000000);
1674+
send_payment(&nodes[0], &[&nodes[1]], 8000000, 8_000_000);
16751675
close_channel(&nodes[0], &nodes[1], &channel_id, funding_tx, true);
16761676
}
16771677

src/ln/channelmanager.rs

+19-6
Original file line numberDiff line numberDiff line change
@@ -1606,21 +1606,34 @@ impl ChannelManager {
16061606
/// generating message events for the net layer to claim the payment, if possible. Thus, you
16071607
/// should probably kick the net layer to go send messages if this returns true!
16081608
///
1609+
/// You must specify the expected amounts for this HTLC, and we will only claim HTLCs
1610+
/// available within a few percent of the expected amount. This is critical for several
1611+
/// reasons : a) it avoids providing senders with `proof-of-payment` (in the form of the
1612+
/// payment_preimage without having provided the full value and b) it avoids certain
1613+
/// privacy-breaking recipient-probing attacks which may reveal payment activity to
1614+
/// motivated attackers.
1615+
///
16091616
/// May panic if called except in response to a PaymentReceived event.
1610-
pub fn claim_funds(&self, payment_preimage: PaymentPreimage) -> bool {
1617+
pub fn claim_funds(&self, payment_preimage: PaymentPreimage, expected_amount: u64) -> bool {
16111618
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
16121619

16131620
let _ = self.total_consistency_lock.read().unwrap();
16141621

16151622
let mut channel_state = Some(self.channel_state.lock().unwrap());
16161623
let removed_source = channel_state.as_mut().unwrap().claimable_htlcs.remove(&payment_hash);
16171624
if let Some(mut sources) = removed_source {
1618-
// TODO: We should require the user specify the expected amount so that we can claim
1619-
// only payments for the correct amount, and reject payments for incorrect amounts
1620-
// (which are probably middle nodes probing to break our privacy).
1621-
for (_, htlc_with_hash) in sources.drain(..) {
1625+
for (received_amount, htlc_with_hash) in sources.drain(..) {
16221626
if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap()); }
1623-
self.claim_funds_internal(channel_state.take().unwrap(), HTLCSource::PreviousHopData(htlc_with_hash), payment_preimage);
1627+
if received_amount < expected_amount || received_amount > expected_amount * 2 {
1628+
let mut htlc_msat_data = byte_utils::be64_to_array(received_amount).to_vec();
1629+
let mut height_data = byte_utils::be32_to_array(self.latest_block_height.load(Ordering::Acquire) as u32).to_vec();
1630+
htlc_msat_data.append(&mut height_data);
1631+
self.fail_htlc_backwards_internal(channel_state.take().unwrap(),
1632+
HTLCSource::PreviousHopData(htlc_with_hash), &payment_hash,
1633+
HTLCFailReason::Reason { failure_code: 0x4000|15, data: htlc_msat_data });
1634+
} else {
1635+
self.claim_funds_internal(channel_state.take().unwrap(), HTLCSource::PreviousHopData(htlc_with_hash), payment_preimage);
1636+
}
16241637
}
16251638
true
16261639
} else { false }

src/ln/functional_test_utils.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -636,8 +636,8 @@ pub fn send_along_route(origin_node: &Node, route: Route, expected_route: &[&Nod
636636
(our_payment_preimage, our_payment_hash)
637637
}
638638

639-
pub fn claim_payment_along_route(origin_node: &Node, expected_route: &[&Node], skip_last: bool, our_payment_preimage: PaymentPreimage) {
640-
assert!(expected_route.last().unwrap().node.claim_funds(our_payment_preimage));
639+
pub fn claim_payment_along_route(origin_node: &Node, expected_route: &[&Node], skip_last: bool, our_payment_preimage: PaymentPreimage, expected_amount: u64) {
640+
assert!(expected_route.last().unwrap().node.claim_funds(our_payment_preimage, expected_amount));
641641
check_added_monitors!(expected_route.last().unwrap(), 1);
642642

643643
let mut next_msgs: Option<(msgs::UpdateFulfillHTLC, msgs::CommitmentSigned)> = None;
@@ -714,8 +714,8 @@ pub fn claim_payment_along_route(origin_node: &Node, expected_route: &[&Node], s
714714
}
715715
}
716716

717-
pub fn claim_payment(origin_node: &Node, expected_route: &[&Node], our_payment_preimage: PaymentPreimage) {
718-
claim_payment_along_route(origin_node, expected_route, false, our_payment_preimage);
717+
pub fn claim_payment(origin_node: &Node, expected_route: &[&Node], our_payment_preimage: PaymentPreimage, expected_amount: u64) {
718+
claim_payment_along_route(origin_node, expected_route, false, our_payment_preimage, expected_amount);
719719
}
720720

721721
pub const TEST_FINAL_CLTV: u32 = 32;
@@ -746,9 +746,9 @@ pub fn route_over_limit(origin_node: &Node, expected_route: &[&Node], recv_value
746746
};
747747
}
748748

749-
pub fn send_payment(origin: &Node, expected_route: &[&Node], recv_value: u64) {
749+
pub fn send_payment(origin: &Node, expected_route: &[&Node], recv_value: u64, expected_value: u64) {
750750
let our_payment_preimage = route_payment(&origin, expected_route, recv_value).0;
751-
claim_payment(&origin, expected_route, our_payment_preimage);
751+
claim_payment(&origin, expected_route, our_payment_preimage, expected_value);
752752
}
753753

754754
pub fn fail_payment_along_route(origin_node: &Node, expected_route: &[&Node], skip_last: bool, our_payment_hash: PaymentHash) {

0 commit comments

Comments
 (0)