| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -11,7 +11,7 @@ static const u8 *pull(const u8 **cursor, size_t *max, void *copy, size_t n) | |||
| 11 | 11 | { | |
| 12 | 12 | const u8 *p = *cursor; | |
| 13 | 13 | ||
| 14 | - if (*max < n) { | ||
| 14 | + if (!p || *max < n) { | ||
| 15 | 15 | *cursor = NULL; | |
| 16 | 16 | *max = 0; | |
| 17 | 17 | /* Just make sure we don't leak uninitialized mem! */ | |
@@ -60,6 +60,15 @@ static void sha256_varint(struct sha256_ctx *ctx, u64 val) | |||
| 60 | 60 | sha256_update(ctx, vt, vtlen); | |
| 61 | 61 | } | |
| 62 | 62 | ||
| 63 | + /* Only hashes the bytes if they were actually there */ | ||
| 64 | + static void pull_and_hash(const u8 **cursor, size_t *max, | ||
| 65 | + struct sha256_ctx *shactx, size_t n) | ||
| 66 | + { | ||
| 67 | + const u8 *p = pull(cursor, max, NULL, n); | ||
| 68 | + if (p) | ||
| 69 | + sha256_update(shactx, p, n); | ||
| 70 | + } | ||
| 71 | + | ||
| 63 | 72 | static void bitcoin_block_pull_dynafed_params(const u8 **cursor, size_t *len, struct sha256_ctx *shactx) | |
| 64 | 73 | { | |
| 65 | 74 | u8 type; | |
@@ -73,49 +82,41 @@ static void bitcoin_block_pull_dynafed_params(const u8 **cursor, size_t *len, st | |||
| 73 | 82 | /* "scriptPubKey" used for block signing */ | |
| 74 | 83 | l1 = pull_varint(cursor, len); | |
| 75 | 84 | sha256_varint(shactx, l1); | |
| 76 | - sha256_update(shactx, *cursor, l1); | ||
| 77 | - pull(cursor, len, NULL, l1); | ||
| 85 | + pull_and_hash(cursor, len, shactx, l1); | ||
| 78 | 86 | ||
| 79 | 87 | /* signblock_witness_limit */ | |
| 80 | - sha256_update(shactx, *cursor, 4); | ||
| 81 | - pull(cursor, len, NULL, 4); | ||
| 88 | + pull_and_hash(cursor, len, shactx, 4); | ||
| 82 | 89 | ||
| 83 | 90 | /* Skip elided_root */ | |
| 84 | - sha256_update(shactx, *cursor, 32); | ||
| 85 | - pull(cursor, len, NULL, 32); | ||
| 91 | + pull_and_hash(cursor, len, shactx, 32); | ||
| 86 | 92 | break; | |
| 87 | 93 | ||
| 88 | 94 | case DYNAFED_PARAMS_FULL: | |
| 89 | 95 | /* "scriptPubKey" used for block signing */ | |
| 90 | 96 | l1 = pull_varint(cursor, len); | |
| 91 | 97 | sha256_varint(shactx, l1); | |
| 92 | - sha256_update(shactx, *cursor, l1); | ||
| 93 | - pull(cursor, len, NULL, l1); | ||
| 98 | + pull_and_hash(cursor, len, shactx, l1); | ||
| 94 | 99 | ||
| 95 | 100 | /* signblock_witness_limit */ | |
| 96 | - sha256_update(shactx, *cursor, 4); | ||
| 97 | - pull(cursor, len, NULL, 4); | ||
| 101 | + pull_and_hash(cursor, len, shactx, 4); | ||
| 98 | 102 | ||
| 99 | 103 | /* fedpeg_program */ | |
| 100 | 104 | l1 = pull_varint(cursor, len); | |
| 101 | 105 | sha256_varint(shactx, l1); | |
| 102 | - sha256_update(shactx, *cursor, l1); | ||
| 103 | - pull(cursor, len, NULL, l1); | ||
| 106 | + pull_and_hash(cursor, len, shactx, l1); | ||
| 104 | 107 | ||
| 105 | 108 | /* fedpegscript */ | |
| 106 | 109 | l1 = pull_varint(cursor, len); | |
| 107 | 110 | sha256_varint(shactx, l1); | |
| 108 | - sha256_update(shactx, *cursor, l1); | ||
| 109 | - pull(cursor, len, NULL, l1); | ||
| 111 | + pull_and_hash(cursor, len, shactx, l1); | ||
| 110 | 112 | ||
| 111 | - /* extension space */ | ||
| 113 | + /* extension space: stop once we've run out of data. */ | ||
| 112 | 114 | l2 = pull_varint(cursor, len); | |
| 113 | 115 | sha256_varint(shactx, l2); | |
| 114 | - for (size_t i = 0; i < l2; i++) { | ||
| 116 | + for (size_t i = 0; i < l2 && *cursor; i++) { | ||
| 115 | 117 | l1 = pull_varint(cursor, len); | |
| 116 | 118 | sha256_varint(shactx, l1); | |
| 117 | - sha256_update(shactx, *cursor, l1); | ||
| 118 | - pull(cursor, len, NULL, l1); | ||
| 119 | + pull_and_hash(cursor, len, shactx, l1); | ||
| 119 | 120 | } | |
| 120 | 121 | break; | |
| 121 | 122 | } | |
@@ -128,7 +129,7 @@ static void bitcoin_block_pull_dynafed_details(const u8 **cursor, size_t *len, s | |||
| 128 | 129 | ||
| 129 | 130 | /* Consume the signblock_witness */ | |
| 130 | 131 | u64 numwitnesses = pull_varint(cursor, len); | |
| 131 | - for (size_t i=0; i<numwitnesses; i++) { | ||
| 132 | + for (size_t i=0; i<numwitnesses && *cursor; i++) { | ||
| 132 | 133 | u64 witsize = pull_varint(cursor, len); | |
| 133 | 134 | pull(cursor, len, NULL, witsize); | |
| 134 | 135 | } | |
@@ -187,8 +188,7 @@ bitcoin_block_from_hex(const tal_t *ctx, const struct chainparams *chainparams, | |||
| 187 | 188 | /* elemens_header.challenge */ | |
| 188 | 189 | templen = pull_varint(&p, &len); | |
| 189 | 190 | sha256_varint(&shactx, templen); | |
| 190 | - sha256_update(&shactx, p, templen); | ||
| 191 | - pull(&p, &len, NULL, templen); | ||
| 191 | + pull_and_hash(&p, &len, &shactx, templen); | ||
| 192 | 192 | ||
| 193 | 193 | /* elements_header.solution. Not hashed since it'd be | |
| 194 | 194 | * a circular dependency. */ | |
@@ -206,6 +206,9 @@ bitcoin_block_from_hex(const tal_t *ctx, const struct chainparams *chainparams, | |||
| 206 | 206 | sha256_double_done(&shactx, &b->hdr.hash.shad); | |
| 207 | 207 | ||
| 208 | 208 | num = pull_varint(&p, &len); | |
| 209 | + /* Every tx takes at least one byte - dont let a bogus count make us allocate a huge array */ | ||
| 210 | + if (num > len) | ||
| 211 | + return tal_free(b); | ||
| 209 | 212 | b->tx = tal_arr(b, struct bitcoin_tx *, num); | |
| 210 | 213 | b->txids = tal_arr(b, struct bitcoin_txid, num); | |
| 211 | 214 | for (i = 0; i < num; i++) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -62,12 +62,117 @@ static const char block[] = | |||
| 62 | 62 | ||
| 63 | 63 | STRUCTEQ_DEF(sha256_double, 0, sha); | |
| 64 | 64 | ||
| 65 | + static void add_bytes(u8 **buf, u8 byte, size_t n) | ||
| 66 | + { | ||
| 67 | + size_t off = tal_count(*buf); | ||
| 68 | + tal_resize(buf, off + n); | ||
| 69 | + memset(*buf + off, byte, n); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + /* Elements header up to (and including) the version, hashes, timestamp | ||
| 73 | + * and height. */ | ||
| 74 | + static u8 *elements_header_start(bool dynafed) | ||
| 75 | + { | ||
| 76 | + u8 *buf = tal_arr(tmpctx, u8, 0); | ||
| 77 | + | ||
| 78 | + /* version: the MSB signals dynafed */ | ||
| 79 | + add_bytes(&buf, 0, 3); | ||
| 80 | + add_bytes(&buf, dynafed ? 0x80 : 0, 1); | ||
| 81 | + /* prev_hash, merkle_hash, timestamp, height */ | ||
| 82 | + add_bytes(&buf, 0, 32 + 32 + 4 + 4); | ||
| 83 | + return buf; | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + /* Dynafed header up to (and including) the current params' fedpegscript. */ | ||
| 87 | + static u8 *dynafed_header_to_fedpegscript(void) | ||
| 88 | + { | ||
| 89 | + u8 *buf = elements_header_start(true); | ||
| 90 | + | ||
| 91 | + add_bytes(&buf, DYNAFED_PARAMS_FULL, 1); | ||
| 92 | + /* signblockscript */ | ||
| 93 | + add_varint(&buf, 2); | ||
| 94 | + add_bytes(&buf, 0x51, 2); | ||
| 95 | + /* signblock_witness_limit */ | ||
| 96 | + add_bytes(&buf, 0, 4); | ||
| 97 | + /* fedpeg_program */ | ||
| 98 | + add_varint(&buf, 1); | ||
| 99 | + add_bytes(&buf, 0x51, 1); | ||
| 100 | + /* fedpegscript */ | ||
| 101 | + add_varint(&buf, 1); | ||
| 102 | + add_bytes(&buf, 0x51, 1); | ||
| 103 | + return buf; | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + static struct bitcoin_block *parse(const struct chainparams *cp, | ||
| 107 | + const u8 *buf, size_t len) | ||
| 108 | + { | ||
| 109 | + const char *hex = tal_hexstr(tmpctx, buf, len); | ||
| 110 | + return bitcoin_block_from_hex(tmpctx, cp, hex, strlen(hex)); | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + /* A valid empty block must parse; every truncation of it must be refused. */ | ||
| 114 | + static void check_truncations(const struct chainparams *cp, const u8 *buf) | ||
| 115 | + { | ||
| 116 | + struct bitcoin_block *b = parse(cp, buf, tal_bytelen(buf)); | ||
| 117 | + assert(b); | ||
| 118 | + assert(tal_count(b->tx) == 0); | ||
| 119 | + | ||
| 120 | + for (size_t i = 0; i < tal_bytelen(buf); i++) | ||
| 121 | + assert(!parse(cp, buf, i)); | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + static void test_elements(void) | ||
| 125 | + { | ||
| 126 | + const struct chainparams *cp = chainparams_for_network("liquid-regtest"); | ||
| 127 | + u8 *buf; | ||
| 128 | + | ||
| 129 | + /* Non-dynafed: challenge, solution, then no txs. */ | ||
| 130 | + buf = elements_header_start(false); | ||
| 131 | + add_varint(&buf, 1); | ||
| 132 | + add_bytes(&buf, 0x51, 1); | ||
| 133 | + add_varint(&buf, 1); | ||
| 134 | + add_bytes(&buf, 0, 1); | ||
| 135 | + add_varint(&buf, 0); | ||
| 136 | + check_truncations(cp, buf); | ||
| 137 | + | ||
| 138 | + /* Dynafed: full current params, compact proposed params, | ||
| 139 | + * one signblock witness, then no txs. */ | ||
| 140 | + buf = dynafed_header_to_fedpegscript(); | ||
| 141 | + /* extension space */ | ||
| 142 | + add_varint(&buf, 1); | ||
| 143 | + add_varint(&buf, 1); | ||
| 144 | + add_bytes(&buf, 0x51, 1); | ||
| 145 | + /* proposed params: signblockscript, witness limit, elided_root */ | ||
| 146 | + add_bytes(&buf, DYNAFED_PARAMS_COMPACT, 1); | ||
| 147 | + add_varint(&buf, 1); | ||
| 148 | + add_bytes(&buf, 0x51, 1); | ||
| 149 | + add_bytes(&buf, 0, 4 + 32); | ||
| 150 | + /* signblock_witness */ | ||
| 151 | + add_varint(&buf, 1); | ||
| 152 | + add_varint(&buf, 1); | ||
| 153 | + add_bytes(&buf, 0, 1); | ||
| 154 | + add_varint(&buf, 0); | ||
| 155 | + check_truncations(cp, buf); | ||
| 156 | + | ||
| 157 | + /* A huge extension space count with no data must not spin. */ | ||
| 158 | + buf = dynafed_header_to_fedpegscript(); | ||
| 159 | + add_varint(&buf, SIZE_MAX); | ||
| 160 | + assert(!parse(cp, buf, tal_bytelen(buf))); | ||
| 161 | + | ||
| 162 | + /* Same for a huge signblock_witness count. */ | ||
| 163 | + buf = elements_header_start(true); | ||
| 164 | + add_bytes(&buf, DYNAFED_PARAMS_NULL, 2); | ||
| 165 | + add_varint(&buf, SIZE_MAX); | ||
| 166 | + assert(!parse(cp, buf, tal_bytelen(buf))); | ||
| 167 | + } | ||
| 168 | + | ||
| 65 | 169 | int main(int argc, const char *argv[]) | |
| 66 | 170 | { | |
| 67 | 171 | struct bitcoin_blkid prev; | |
| 68 | 172 | struct sha256_double merkle; | |
| 69 | 173 | struct bitcoin_txid txid, expected_txid; | |
| 70 | 174 | struct bitcoin_block *b; | |
| 175 | + const char *hex; | ||
| 71 | 176 | ||
| 72 | 177 | common_setup(argv[0]); | |
| 73 | 178 | chainparams = chainparams_for_network("bitcoin"); | |
@@ -103,6 +208,14 @@ int main(int argc, const char *argv[]) | |||
| 103 | 208 | assert(bitcoin_txid_eq(&txid, &expected_txid)); | |
| 104 | 209 | ||
| 105 | 210 | tal_free(b); | |
| 211 | + | ||
| 212 | + /* The 80-byte header followed by a huge tx count must be refused, | ||
| 213 | + * not abort trying to allocate the tx array. */ | ||
| 214 | + hex = tal_fmt(tmpctx, "%.160sffffffffffffffffff", block); | ||
| 215 | + assert(!bitcoin_block_from_hex(tmpctx, chainparams, hex, strlen(hex))); | ||
| 216 | + | ||
| 217 | + test_elements(); | ||
| 218 | + | ||
| 106 | 219 | common_shutdown(); | |
| 107 | 220 | return 0; | |
| 108 | 221 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments