core-lightning/common/psbt_internal.c
niftynei 7717f6e4df psbt-fix: set to NULL, which will cleanup dangling pointer
On July 18th, @jgriffiths wrote:

> You need to set this to NULL after freeing it, otherwise if line 72 returns you have a dangling pointer and potential later use-after-free here. Alternately use wally_psbt_set_input_final_witness(NULL) which will free any existing witness and set the value to NULL.

Reported-By: @jgriffiths
2023-12-15 10:20:19 +10:30

168 lines
4.2 KiB
C

#include "config.h"
#include <assert.h>
#include <bitcoin/psbt.h>
#include <bitcoin/script.h>
#include <bitcoin/varint.h>
#include <common/psbt_internal.h>
#include <common/psbt_open.h>
#include <wire/peer_wire.h>
static bool next_size(const u8 **cursor, size_t *max, size_t *size)
{
size_t len;
varint_t varint;
if (*max < 1)
return false;
len = varint_get(*cursor, *max, &varint);
if (len < 1)
return false;
if (*max < len) {
*max = 0;
return false;
}
*cursor += len;
*max -= len;
*size = varint;
return true;
}
static u8 *next_script(const tal_t *ctx, const u8 **cursor, size_t *max)
{
const u8 *p;
size_t size;
u8 *ret;
if (!next_size(cursor, max, &size))
return NULL;
if (*max < size) {
*max = 0;
return NULL;
}
p = *cursor;
*max -= size;
*cursor += size;
ret = tal_arr(ctx, u8, size);
memcpy(ret, p, size);
return ret;
}
static void
psbt_input_set_final_witness_stack(const tal_t *ctx,
struct wally_psbt_input *in,
const struct witness *witness)
{
u8 *script, *sctx;
const u8 *data = witness->witness_data;
size_t size, max = tal_count(data);
bool ok;
wally_psbt_input_set_final_witness(in, NULL);
/* FIXME: return an error?? */
if (!next_size(&data, &max, &size))
return;
tal_wally_start();
sctx = tal(NULL, u8);
wally_tx_witness_stack_init_alloc(size, &in->final_witness);
while ((script = next_script(sctx, &data, &max)) && script != NULL) {
ok = (wally_tx_witness_stack_add(in->final_witness,
script, tal_count(script)) == WALLY_OK);
assert(ok);
}
tal_wally_end(ctx);
tal_free(sctx);
}
void psbt_finalize_input(const tal_t *ctx,
struct wally_psbt_input *in,
const struct witness *witness)
{
const struct wally_map_item *redeem_script;
psbt_input_set_final_witness_stack(ctx, in, witness);
/* There's this horrible edgecase where we set the final_witnesses
* directly onto the PSBT, but the input is a P2SH-wrapped input
* (which has redeemscripts that belong in the scriptsig). Because
* of how the internal libwally stuff works calling 'finalize'
* on these just .. ignores it!? Murder. Anyway, here we do a final
* scriptsig check -- if there's a redeemscript field still around we
* just go ahead and mush it into the final_scriptsig field. */
redeem_script = wally_map_get_integer(&in->psbt_fields, /* PSBT_IN_REDEEM_SCRIPT */ 0x04);
if (redeem_script) {
u8 *redeemscript = tal_dup_arr(NULL, u8,
redeem_script->value,
redeem_script->value_len, 0);
u8 *final_scriptsig =
bitcoin_scriptsig_redeem(NULL,
take(redeemscript));
wally_psbt_input_set_final_scriptsig(in, final_scriptsig, tal_bytelen(final_scriptsig));
wally_psbt_input_set_redeem_script(in, tal_arr(NULL, u8, 0), 0);
}
}
const struct witness **
psbt_to_witnesses(const tal_t *ctx,
const struct wally_psbt *psbt,
enum tx_role side_to_stack,
int input_index_to_ignore)
{
u64 serial_id;
const struct witness **witnesses =
tal_arr(ctx, const struct witness *, 0);
for (size_t i = 0; i < psbt->num_inputs; i++) {
struct wally_tx_witness_stack *wtx_s =
psbt->inputs[i].final_witness;
if (!psbt_get_serial_id(&psbt->inputs[i].unknowns,
&serial_id))
/* FIXME: throw an error ? */
return tal_free(witnesses);
if (input_index_to_ignore == i)
continue;
/* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2:
* - if is the *initiator*:
* - MUST send even `serial_id`s
*/
if (wtx_s && serial_id % 2 == side_to_stack) {
/* BOLT-e299850cb5ebd8bd9c55763bbc498fcdf94a9567 #2:
*
* The `witness_data` is encoded as per bitcoin's
* wire protocol (a CompactSize number of elements,
* with each element a CompactSize length and that
* many bytes following. Each `witness_data` field
* contains all of the witness elements for a single input,
* including the leading counter of elements.
*/
struct witness *wit = tal(witnesses, struct witness);
wit->witness_data = tal_arr(wit, u8, 0);
add_varint(&wit->witness_data, wtx_s->num_items);
for (size_t j = 0; j < wtx_s->num_items; j++) {
add_varint(&wit->witness_data, wtx_s->items[j].witness_len);
tal_expand(&wit->witness_data, wtx_s->items[j].witness,
wtx_s->items[j].witness_len);
}
tal_arr_expand(&witnesses, wit);
}
}
return witnesses;
}