Reject channels if the total reserves are larger than the funding

The `full_stack_target` fuzzer managed to find a subtraction
underflow in the new `Channel::get_htlc_maximum` function where we
subtract both sides' reserve values from the channel funding. Such
a channel is obviously completely useless, so we should reject it
during opening instead of integer-underflowing later.

Thanks to Chaincode Labs for providing the fuzzing resources which
found this bug!
This commit is contained in:
Matt Corallo 2022-04-28 19:46:13 +00:00
parent d1b984d864
commit 2826af75a5

View file

@ -1082,14 +1082,13 @@ impl<Signer: Sign> Channel<Signer> {
if msg.channel_reserve_satoshis > msg.funding_satoshis {
return Err(ChannelError::Close(format!("Bogus channel_reserve_satoshis ({}). Must be not greater than funding_satoshis: {}", msg.channel_reserve_satoshis, msg.funding_satoshis)));
}
let funding_value = (msg.funding_satoshis - msg.channel_reserve_satoshis) * 1000;
if msg.push_msat > funding_value {
return Err(ChannelError::Close(format!("push_msat {} was larger than funding value {}", msg.push_msat, funding_value)));
let full_channel_value_msat = (msg.funding_satoshis - msg.channel_reserve_satoshis) * 1000;
if msg.push_msat > full_channel_value_msat {
return Err(ChannelError::Close(format!("push_msat {} was larger than funding value {}", msg.push_msat, full_channel_value_msat)));
}
if msg.dust_limit_satoshis > msg.funding_satoshis {
return Err(ChannelError::Close(format!("dust_limit_satoshis {} was larger than funding_satoshis {}. Peer never wants payout outputs?", msg.dust_limit_satoshis, msg.funding_satoshis)));
}
let full_channel_value_msat = (msg.funding_satoshis - msg.channel_reserve_satoshis) * 1000;
if msg.htlc_minimum_msat >= full_channel_value_msat {
return Err(ChannelError::Close(format!("Minimum htlc value ({}) was larger than full channel value ({})", msg.htlc_minimum_msat, full_channel_value_msat)));
}
@ -1143,6 +1142,9 @@ impl<Signer: Sign> Channel<Signer> {
if holder_selected_channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
return Err(ChannelError::Close(format!("Suitable channel reserve not found. remote_channel_reserve was ({}). dust_limit_satoshis is ({}).", holder_selected_channel_reserve_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
}
if holder_selected_channel_reserve_satoshis * 1000 >= full_channel_value_msat {
return Err(ChannelError::Close(format!("Suitable channel reserve not found. remote_channel_reserve was ({}). Channel value is ({} - {}).", holder_selected_channel_reserve_satoshis, full_channel_value_msat, msg.push_msat)));
}
if msg.channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
log_debug!(logger, "channel_reserve_satoshis ({}) is smaller than our dust limit ({}). We can broadcast stale states without any risk, implying this channel is very insecure for our counterparty.",
msg.channel_reserve_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS);