Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lightningd/pay.c
Original file line number Diff line number Diff line change
Expand Up @@ -1259,6 +1259,9 @@ send_payment(struct lightningd *ld,
channels[i] = route[i].scid;

packet = create_onionpacket(tmpctx, path, ROUTING_INFO_SIZE, &path_secrets);
if (!packet)
return command_fail(cmd, LIGHTNINGD,
"Could not create onion packet");
return send_payment_core(ld, cmd, rhash, partid, group, &route[0],
msat, total_msat,
label, invstring, description,
Expand Down
27 changes: 27 additions & 0 deletions tests/test_pay.py
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,33 @@ def test_wait_sendpay(node_factory, executor):
l1.rpc.waitsendpay(inv['payment_hash'])['payment_preimage']


def test_sendpay_onion_overflow(node_factory):
"""A route whose per-hop payloads exceed the 1300-byte onion must
fail cleanly: create_onionpacket returns NULL and send_payment
used it unchecked, crashing lightningd (SIGSEGV in
serialize_onionpacket)."""
l1, l2 = node_factory.line_graph(2, fundamount=10**6)

amt = 1000
inv = l2.rpc.invoice(amt, 'onionoverflow', 'desc')

# Each TLV hop costs ~50 onion bytes at these amounts; 30 hops
# cannot fit in the 1300-byte onion no matter how small the
# encodings. Only the first hop must be a live channel: the
# onion is built before anything is sent.
hop = {
'amount_msat': amt,
'id': l2.info['id'],
'delay': 5,
'channel': first_scid(l1, l2)
}
route = [copy.deepcopy(hop) for _ in range(30)]

with pytest.raises(RpcError, match='Could not create onion packet'):
l1.rpc.sendpay(route, inv['payment_hash'],
payment_secret=inv['payment_secret'])


@unittest.skipIf(TEST_NETWORK != 'regtest', "The reserve computation is bitcoin specific")
@pytest.mark.parametrize("anchors", [False, True])
def test_sendpay_cant_afford(node_factory, anchors):
Expand Down
Loading