Browse Source

pull_length: Take structure size into account when checking max

When a serialized length refers to an array of structures, the trivial
DOS prevention can be out by a factor of sizeof(serialized struct). Use
the size of the serialized structure as a multiplier to prevent this.

Transaction inputs are the motivating example, where the check is out by
a factor of ~40.
ppa-0.6.1
Jon Griffiths 7 years ago
committed by Rusty Russell
parent
commit
4b38696613
  1. 22
      bitcoin/tx.c

22
bitcoin/tx.c

@ -317,12 +317,12 @@ static u64 pull_value(const u8 **cursor, size_t *max)
return amount; return amount;
} }
/* Pulls a varint which specifies a data length: ensures basic sanity to /* Pulls a varint which specifies n items of mult size: ensures basic
* avoid trivial OOM */ * sanity to avoid trivial OOM */
static u64 pull_length(const u8 **cursor, size_t *max) static u64 pull_length(const u8 **cursor, size_t *max, size_t mult)
{ {
u64 v = pull_varint(cursor, max); u64 v = pull_varint(cursor, max);
if (v > *max) { if (v * mult > *max) {
*cursor = NULL; *cursor = NULL;
*max = 0; *max = 0;
return 0; return 0;
@ -336,7 +336,7 @@ static void pull_input(const tal_t *ctx, const u8 **cursor, size_t *max,
u64 script_len; u64 script_len;
pull_sha256_double(cursor, max, &input->txid.shad); pull_sha256_double(cursor, max, &input->txid.shad);
input->index = pull_le32(cursor, max); input->index = pull_le32(cursor, max);
script_len = pull_length(cursor, max); script_len = pull_length(cursor, max, 1);
if (script_len) if (script_len)
input->script = tal_arr(ctx, u8, script_len); input->script = tal_arr(ctx, u8, script_len);
else else
@ -349,13 +349,13 @@ static void pull_output(const tal_t *ctx, const u8 **cursor, size_t *max,
struct bitcoin_tx_output *output) struct bitcoin_tx_output *output)
{ {
output->amount = pull_value(cursor, max); output->amount = pull_value(cursor, max);
output->script = tal_arr(ctx, u8, pull_length(cursor, max)); output->script = tal_arr(ctx, u8, pull_length(cursor, max, 1));
pull(cursor, max, output->script, tal_len(output->script)); pull(cursor, max, output->script, tal_len(output->script));
} }
static u8 *pull_witness_item(const tal_t *ctx, const u8 **cursor, size_t *max) static u8 *pull_witness_item(const tal_t *ctx, const u8 **cursor, size_t *max)
{ {
uint64_t len = pull_length(cursor, max); uint64_t len = pull_length(cursor, max, 1);
u8 *item; u8 *item;
item = tal_arr(ctx, u8, len); item = tal_arr(ctx, u8, len);
@ -366,7 +366,7 @@ static u8 *pull_witness_item(const tal_t *ctx, const u8 **cursor, size_t *max)
static void pull_witness(struct bitcoin_tx_input *inputs, size_t i, static void pull_witness(struct bitcoin_tx_input *inputs, size_t i,
const u8 **cursor, size_t *max) const u8 **cursor, size_t *max)
{ {
uint64_t j, num = pull_length(cursor, max); uint64_t j, num = pull_length(cursor, max, 1);
/* 0 means not using witness. */ /* 0 means not using witness. */
if (num == 0) { if (num == 0) {
@ -389,20 +389,20 @@ struct bitcoin_tx *pull_bitcoin_tx_onto(const tal_t *ctx, const u8 **cursor,
u8 flag = 0; u8 flag = 0;
tx->version = pull_le32(cursor, max); tx->version = pull_le32(cursor, max);
count = pull_length(cursor, max); count = pull_length(cursor, max, 32 + 4 + 4 + 1);
/* BIP 144 marker is 0 (impossible to have tx with 0 inputs) */ /* BIP 144 marker is 0 (impossible to have tx with 0 inputs) */
if (count == 0) { if (count == 0) {
pull(cursor, max, &flag, 1); pull(cursor, max, &flag, 1);
if (flag != SEGREGATED_WITNESS_FLAG) if (flag != SEGREGATED_WITNESS_FLAG)
return tal_free(tx); return tal_free(tx);
count = pull_length(cursor, max); count = pull_length(cursor, max, 32 + 4 + 4 + 1);
} }
tx->input = tal_arr(tx, struct bitcoin_tx_input, count); tx->input = tal_arr(tx, struct bitcoin_tx_input, count);
for (i = 0; i < tal_count(tx->input); i++) for (i = 0; i < tal_count(tx->input); i++)
pull_input(tx, cursor, max, tx->input + i); pull_input(tx, cursor, max, tx->input + i);
count = pull_length(cursor, max); count = pull_length(cursor, max, 8 + 1);
tx->output = tal_arr(tx, struct bitcoin_tx_output, count); tx->output = tal_arr(tx, struct bitcoin_tx_output, count);
for (i = 0; i < tal_count(tx->output); i++) for (i = 0; i < tal_count(tx->output); i++)
pull_output(tx, cursor, max, tx->output + i); pull_output(tx, cursor, max, tx->output + i);

Loading…
Cancel
Save