diff --git a/reftable/table.c b/reftable/table.c index f4bc86a29d..b4d3f9e211 100644 --- a/reftable/table.c +++ b/reftable/table.c @@ -562,6 +562,11 @@ int reftable_table_new(struct reftable_table **out, goto done; } + if (file_size < header_size(t->version) + footer_size(t->version)) { + err = REFTABLE_FORMAT_ERROR; + goto done; + } + t->size = file_size - footer_size(t->version); t->source = *source; t->name = reftable_strdup(name); diff --git a/t/unit-tests/u-reftable-table.c b/t/unit-tests/u-reftable-table.c index c7dca45e70..28b0ef5258 100644 --- a/t/unit-tests/u-reftable-table.c +++ b/t/unit-tests/u-reftable-table.c @@ -262,3 +262,31 @@ void test_reftable_table__seek_invalid_log_offset(void) reftable_table_decref(table); reftable_buf_release(&buf); } + +void test_reftable_table__new_with_truncated_table(void) +{ + struct reftable_ref_record refs[] = { + { + .refname = (char *) "refs/heads/main", + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 42 }, + }, + }; + struct reftable_block_source source = { 0 }; + struct reftable_table *table; + struct reftable_buf buf = REFTABLE_BUF_INIT; + + cl_reftable_write_to_buf(&buf, refs, ARRAY_SIZE(refs), NULL, 0, NULL); + + /* + * Truncate the table so that it is large enough to read the header, but + * too small to also contain the footer. + */ + buf.len = footer_size(1) - 1; + block_source_from_buf(&source, &buf); + + cl_assert_equal_i(reftable_table_new(&table, &source, "name"), + REFTABLE_FORMAT_ERROR); + + reftable_buf_release(&buf); +}