Skip to content

Commit c97f96a

Browse files
committed
fix: harden PSBT signing against integer UB on malformed input
1 parent 530a0ff commit c97f96a

5 files changed

Lines changed: 26 additions & 17 deletions

File tree

src/handler/lib/check_merkle_tree_sorted.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ int call_check_merkle_tree_sorted_with_callback(dispatcher_context_t *dispatcher
2424

2525
for (size_t cur_el_idx = 0; cur_el_idx < size; cur_el_idx++) {
2626
uint8_t cur_el[MAX_CHECK_MERKLE_TREE_SORTED_PREIMAGE_SIZE];
27+
// tree size and leaf index are bounded well below 2^32 in practice;
28+
// cast to the callee's uint32_t parameters explicitly.
2729
int cur_el_len = call_get_merkle_leaf_element(dispatcher_context,
2830
root,
29-
size,
30-
cur_el_idx,
31+
(uint32_t) size,
32+
(uint32_t) cur_el_idx,
3133
cur_el,
3234
sizeof(cur_el));
3335

src/handler/lib/policy.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1956,7 +1956,7 @@ static int check_older_node_cb(const policy_node_t *node, void *callback_state)
19561956
(void) callback_state;
19571957
if (node->type == TOKEN_OLDER) {
19581958
const policy_node_with_uint32_t *older = (const policy_node_with_uint32_t *) node;
1959-
uint32_t n = older->n & ~SEQUENCE_LOCKTIME_TYPE_FLAG;
1959+
uint32_t n = older->n & ~(uint32_t) SEQUENCE_LOCKTIME_TYPE_FLAG;
19601960
if (n < 1 || n > 65535) {
19611961
return -1;
19621962
}

src/handler/sign_psbt.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ typedef struct {
3434
// matched with the current key expression in the signing flow
3535

3636
bool is_change;
37-
int address_index;
37+
uint32_t address_index;
3838

3939
// For an output, its scriptPubKey
4040
// for an input, the prevout's scriptPubKey (either from the non-witness-utxo, or from the

src/handler/sign_psbt/musig_signing.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -368,12 +368,14 @@ bool __attribute__((noinline)) sign_sighash_musig_and_yield(dispatcher_context_t
368368
memcpy(musig_my_psbt_id + 33 + 33, keyexpr_info->tapleaf_hash, 32);
369369
}
370370
musig_pubnonce_t my_pubnonce;
371-
if (sizeof(musig_pubnonce_t) != call_get_merkleized_map_value(dc,
372-
&input->in_out.map,
373-
musig_my_psbt_id_key,
374-
1 + psbt_id_len,
375-
my_pubnonce.raw,
376-
sizeof(musig_pubnonce_t))) {
371+
// call_get_merkleized_map_value returns int (negative on error); cast the
372+
// unsigned sizeof so the comparison doesn't trip UBSan's sign-change check.
373+
if ((int) sizeof(musig_pubnonce_t) != call_get_merkleized_map_value(dc,
374+
&input->in_out.map,
375+
musig_my_psbt_id_key,
376+
1 + psbt_id_len,
377+
my_pubnonce.raw,
378+
sizeof(musig_pubnonce_t))) {
377379
PRINTF("Missing or erroneous pubnonce in PSBT\n");
378380
SEND_SW(dc, SW_INCORRECT_DATA);
379381
return false;

src/handler/sign_psbt/preprocess_inputs.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,12 @@ bool __attribute__((noinline)) preprocess_inputs(
178178
return false;
179179
}
180180

181+
// sanity check before accumulating, to avoid overflowing the total
182+
if (input.prevout_amount > BITCOIN_TOTAL_SUPPLY) {
183+
PRINTF("Input amount exceeds Bitcoin total supply!\n");
184+
SEND_SW(dc, SW_INCORRECT_DATA);
185+
return false;
186+
}
181187
st->inputs_total_amount += input.prevout_amount;
182188
}
183189

@@ -212,6 +218,12 @@ bool __attribute__((noinline)) preprocess_inputs(
212218
}
213219
} else {
214220
// we extract the scriptPubKey and prevout amount from the witness utxo
221+
// sanity check before accumulating, to avoid overflowing the total
222+
if (wit_utxo_prevout_amount > BITCOIN_TOTAL_SUPPLY) {
223+
PRINTF("Input amount exceeds Bitcoin total supply!\n");
224+
SEND_SW(dc, SW_INCORRECT_DATA);
225+
return false;
226+
}
215227
st->inputs_total_amount += wit_utxo_prevout_amount;
216228

217229
input.prevout_amount = wit_utxo_prevout_amount;
@@ -220,13 +232,6 @@ bool __attribute__((noinline)) preprocess_inputs(
220232
}
221233
}
222234

223-
if (input.prevout_amount > BITCOIN_TOTAL_SUPPLY) {
224-
// sanity check to avoid overflows in amounts
225-
PRINTF("Input amount exceed Bitcoin total supply!\n");
226-
SEND_SW(dc, SW_INCORRECT_DATA);
227-
return false;
228-
}
229-
230235
// check if the input is internal; if not, continue
231236

232237
int is_internal = is_in_out_internal(dc, st, sign_psbt_cache, &input.in_out, true);

0 commit comments

Comments
 (0)