Skip to content

Commit 7e5cf41

Browse files
Lagrang3rustyrussell
authored andcommitted
htlc_wire: fix crash when adding an HTLC
In line channeld/channeld_wiregen.c:832 `*added+i` is not a tal object hence the instruction in common/htlc_wire.c:200 `tal_arr(ctx, struct tlv_field, 0);` crashes CLN. This is fixed by stating that added_htlc is a a varsize_type. Logs: 2025-08-16T02:25:28.640Z **BROKEN** lightningd: FATAL SIGNAL 6 (version v25.05-200-g79b959b)V ... 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: ccan/ccan/tal/tal.c:95 (call_error) 0x54f6bc 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: ccan/ccan/tal/tal.c:169 (check_bounds) 0x54f75a 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: ccan/ccan/tal/tal.c:178 (to_tal_hdr) 0x54f782 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: ccan/ccan/tal/tal.c:193 (to_tal_hdr_or_null) 0x54f7c7 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: ccan/ccan/tal/tal.c:471 (tal_alloc_) 0x54ffe4 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: ccan/ccan/tal/tal.c:517 (tal_alloc_arr_) 0x5500c4 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: common/htlc_wire.c:200 (fromwire_len_and_tlvstream) 0x48d63d 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: common/htlc_wire.c:234 (fromwire_added_htlc) 0x48dd23 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: channeld/channeld_wiregen.c:832 (fromwire_channeld_got_commitsig) 0x4c61fa 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: lightningd/peer_htlcs.c:2377 (peer_got_commitsig) 0x4549cb 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: lightningd/channel_control.c:1552 (channel_msg) 0x4140fe 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: lightningd/subd.c:560 (sd_msg_read) 0x461513 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: ccan/ccan/io/io.c:60 (next_plan) 0x544885 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: ccan/ccan/io/io.c:422 (do_plan) 0x544cea 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: ccan/ccan/io/io.c:439 (io_ready) 0x544d9d 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: ccan/ccan/io/poll.c:455 (io_loop) 0x54665d 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: lightningd/io_loop_with_timers.c:22 (io_loop_with_timers) 0x42d220 2025-08-16T02:25:28.640Z **BROKEN** lightningd: backtrace: lightningd/lightningd.c:1487 (main) 0x43280f gdb inspection: 830 *added = num_added ? tal_arr(ctx, struct added_htlc, num_added) : NULL; 831 for (size_t i = 0; i < num_added; i++) 832 fromwire_added_htlc(&cursor, &plen, *added + i); (gdb) p i $3 = 1 Changelog-None: crash introduced this release. Signed-off-by: Lagrang3 <[email protected]> [ Added test, removed Changelog --RR ]
1 parent 6c7c78e commit 7e5cf41

File tree

7 files changed

+27
-23
lines changed

7 files changed

+27
-23
lines changed

channeld/channeld.c

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,28 +1571,30 @@ static void marshall_htlc_info(const tal_t *ctx,
15711571
struct changed_htlc **changed,
15721572
struct fulfilled_htlc **fulfilled,
15731573
const struct failed_htlc ***failed,
1574-
struct added_htlc **added)
1574+
const struct added_htlc ***added)
15751575
{
15761576
*changed = tal_arr(ctx, struct changed_htlc, 0);
1577-
*added = tal_arr(ctx, struct added_htlc, 0);
1577+
*added = tal_arr(ctx, const struct added_htlc *, 0);
15781578
*failed = tal_arr(ctx, const struct failed_htlc *, 0);
15791579
*fulfilled = tal_arr(ctx, struct fulfilled_htlc, 0);
15801580

15811581
for (size_t i = 0; i < tal_count(changed_htlcs); i++) {
15821582
const struct htlc *htlc = changed_htlcs[i];
15831583
if (htlc->state == RCVD_ADD_COMMIT) {
1584-
struct added_htlc a;
1584+
struct added_htlc *a = tal(*added, struct added_htlc);
15851585

1586-
a.id = htlc->id;
1587-
a.amount = htlc->amount;
1588-
a.payment_hash = htlc->rhash;
1589-
a.cltv_expiry = abs_locktime_to_blocks(&htlc->expiry);
1590-
memcpy(a.onion_routing_packet,
1586+
a->id = htlc->id;
1587+
a->amount = htlc->amount;
1588+
a->payment_hash = htlc->rhash;
1589+
a->cltv_expiry = abs_locktime_to_blocks(&htlc->expiry);
1590+
memcpy(a->onion_routing_packet,
15911591
htlc->routing,
1592-
sizeof(a.onion_routing_packet));
1593-
a.path_key = htlc->path_key;
1594-
a.extra_tlvs = htlc->extra_tlvs;
1595-
a.fail_immediate = htlc->fail_immediate;
1592+
sizeof(a->onion_routing_packet));
1593+
/* Note: we assume htlc's lifetime is greater than ours,
1594+
* so we just share pointers and don't bother copying */
1595+
a->path_key = htlc->path_key;
1596+
a->extra_tlvs = htlc->extra_tlvs;
1597+
a->fail_immediate = htlc->fail_immediate;
15961598
tal_arr_expand(added, a);
15971599
} else if (htlc->state == RCVD_REMOVE_COMMIT) {
15981600
if (htlc->r) {
@@ -1629,7 +1631,7 @@ static void send_revocation(struct peer *peer,
16291631
struct changed_htlc *changed;
16301632
struct fulfilled_htlc *fulfilled;
16311633
const struct failed_htlc **failed;
1632-
struct added_htlc *added;
1634+
const struct added_htlc **added;
16331635
const u8 *msg;
16341636
const u8 *msg_for_master;
16351637

common/htlc_wire.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,10 @@ static struct tlv_field *fromwire_len_and_tlvstream(const tal_t *ctx,
216216
return tlvs;
217217
}
218218

219-
void fromwire_added_htlc(const u8 **cursor, size_t *max,
220-
struct added_htlc *added)
219+
struct added_htlc *fromwire_added_htlc(const tal_t *ctx, const u8 **cursor,
220+
size_t *max)
221221
{
222+
struct added_htlc *added = tal(ctx, struct added_htlc);
222223
added->id = fromwire_u64(cursor, max);
223224
added->amount = fromwire_amount_msat(cursor, max);
224225
fromwire_sha256(cursor, max, &added->payment_hash);
@@ -235,6 +236,7 @@ void fromwire_added_htlc(const u8 **cursor, size_t *max,
235236
} else
236237
added->extra_tlvs = NULL;
237238
added->fail_immediate = fromwire_bool(cursor, max);
239+
return added;
238240
}
239241

240242
struct existing_htlc *fromwire_existing_htlc(const tal_t *ctx,

common/htlc_wire.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ void towire_changed_htlc(u8 **pptr, const struct changed_htlc *changed);
8686
void towire_side(u8 **pptr, const enum side side);
8787
void towire_shachain(u8 **pptr, const struct shachain *shachain);
8888

89-
void fromwire_added_htlc(const u8 **cursor, size_t *max,
90-
struct added_htlc *added);
89+
struct added_htlc *fromwire_added_htlc(const tal_t *ctx, const u8 **cursor,
90+
size_t *max);
9191
struct existing_htlc *fromwire_existing_htlc(const tal_t *ctx,
9292
const u8 **cursor, size_t *max);
9393
void fromwire_fulfilled_htlc(const u8 **cursor, size_t *max,

lightningd/peer_htlcs.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2309,15 +2309,15 @@ static bool channel_added_their_htlc(struct channel *channel,
23092309
/* The peer doesn't tell us this separately, but logically it's a separate
23102310
* step to receiving commitsig */
23112311
static bool peer_sending_revocation(struct channel *channel,
2312-
struct added_htlc *added,
2312+
struct added_htlc **added,
23132313
struct fulfilled_htlc *fulfilled,
23142314
struct failed_htlc **failed,
23152315
struct changed_htlc *changed)
23162316
{
23172317
size_t i;
23182318

23192319
for (i = 0; i < tal_count(added); i++) {
2320-
if (!update_in_htlc(channel, added[i].id, SENT_ADD_REVOCATION))
2320+
if (!update_in_htlc(channel, added[i]->id, SENT_ADD_REVOCATION))
23212321
return false;
23222322
}
23232323
for (i = 0; i < tal_count(fulfilled); i++) {
@@ -2364,7 +2364,7 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg)
23642364
struct fee_states *fee_states;
23652365
struct height_states *blockheight_states;
23662366
struct bitcoin_signature commit_sig, *htlc_sigs;
2367-
struct added_htlc *added;
2367+
struct added_htlc **added;
23682368
struct fulfilled_htlc *fulfilled;
23692369
struct failed_htlc **failed;
23702370
struct changed_htlc *changed;
@@ -2439,7 +2439,7 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg)
24392439

24402440
/* New HTLCs */
24412441
for (i = 0; i < tal_count(added); i++) {
2442-
if (!channel_added_their_htlc(channel, &added[i]))
2442+
if (!channel_added_their_htlc(channel, added[i]))
24432443
return;
24442444
}
24452445

tests/test_pay.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7016,7 +7016,6 @@ def pay_with_sendonion(invoice, route, groupid, partid):
70167016
assert invoice["amount_received_msat"] == Millisatoshi(total_amount)
70177017

70187018

7019-
@pytest.mark.xfail(strict=True)
70207019
def test_htlc_tlv_crash(node_factory):
70217020
"""Marshalling code treated an array of htlc_added as if they were tal objects, but only the head is a tal object so if we have more than one, BOOM!"""
70227021
plugin = os.path.join(os.path.dirname(__file__), 'plugins/htlc_accepted-customtlv.py')

tools/generate-wire.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ class Type(FieldSet):
230230
'gossip_getnodes_entry',
231231
'gossip_getchannels_entry',
232232
'failed_htlc',
233+
'added_htlc',
233234
'existing_htlc',
234235
'inflight',
235236
'hsm_utxo',

wallet/test/run-wallet.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ struct channel_type *fromwire_channel_type(const tal_t *ctx UNNEEDED, const u8 *
300300
bool fromwire_channeld_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED)
301301
{ fprintf(stderr, "fromwire_channeld_dev_memleak_reply called!\n"); abort(); }
302302
/* Generated stub for fromwire_channeld_got_commitsig */
303-
bool fromwire_channeld_got_commitsig(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *commitnum UNNEEDED, struct fee_states **fee_states UNNEEDED, struct height_states **blockheight_states UNNEEDED, struct bitcoin_signature *signature UNNEEDED, struct bitcoin_signature **htlc_signature UNNEEDED, struct added_htlc **added UNNEEDED, struct fulfilled_htlc **fulfilled UNNEEDED, struct failed_htlc ***failed UNNEEDED, struct changed_htlc **changed UNNEEDED, struct bitcoin_tx **tx UNNEEDED, struct commitsig ***inflight_commitsigs UNNEEDED)
303+
bool fromwire_channeld_got_commitsig(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *commitnum UNNEEDED, struct fee_states **fee_states UNNEEDED, struct height_states **blockheight_states UNNEEDED, struct bitcoin_signature *signature UNNEEDED, struct bitcoin_signature **htlc_signature UNNEEDED, struct added_htlc ***added UNNEEDED, struct fulfilled_htlc **fulfilled UNNEEDED, struct failed_htlc ***failed UNNEEDED, struct changed_htlc **changed UNNEEDED, struct bitcoin_tx **tx UNNEEDED, struct commitsig ***inflight_commitsigs UNNEEDED)
304304
{ fprintf(stderr, "fromwire_channeld_got_commitsig called!\n"); abort(); }
305305
/* Generated stub for fromwire_channeld_got_revoke */
306306
bool fromwire_channeld_got_revoke(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *revokenum UNNEEDED, struct secret *per_commitment_secret UNNEEDED, struct pubkey *next_per_commit_point UNNEEDED, struct fee_states **fee_states UNNEEDED, struct height_states **blockheight_states UNNEEDED, struct changed_htlc **changed UNNEEDED, struct penalty_base **pbase UNNEEDED, struct bitcoin_tx **penalty_tx UNNEEDED)

0 commit comments

Comments
 (0)