reftable/record: don't abort when decoding invalid ref value type
When decoding a ref record we read its value type from the block. In case the type itself is invalid we call `abort()`. This is rather heavy-handed though: the data we're reading is untrusted, so we should treat the issue as a normal and not as a programming error. Fix this by handling the error gracefully. Note that this also requires us to set the value type later, as otherwise we might store an invalid type in the record. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Patrick Steinhardt committed
Jul 3, 2026 at 14:58 UTC
ed103ab7f89075c8cb98196b4a2577611f009def
2 files changed
+27
-3
reftable/record.c
+3
-3
@@ -388,7 +388,6 @@ static int reftable_ref_record_decode(void *rec, struct reftable_buf key,
388
r->refname[key.len] = 0;
389
390
r->update_index = update_index;
391
- r->value_type = val_type;
391
switch (val_type) {
392
case REFTABLE_REF_VAL1:
393
if (in.len < hash_size) {
@@ -426,9 +425,10 @@ static int reftable_ref_record_decode(void *rec, struct reftable_buf key,
425
case REFTABLE_REF_DELETION:
426
break;
427
default:
429
- abort();
430
- break;
428
+ err = REFTABLE_FORMAT_ERROR;
429
+ goto done;
430
}
431
+ r->value_type = val_type;
432
433
return start.len - in.len;
434
t/unit-tests/u-reftable-record.c
+24
@@ -11,6 +11,7 @@
11
#include "reftable/basics.h"
12
#include "reftable/constants.h"
13
#include "reftable/record.h"
14
+#include "reftable/reftable-error.h"
15
16
static void t_copy(struct reftable_record *rec)
17
{
@@ -202,6 +203,29 @@ void test_reftable_record__ref_record_roundtrip(void)
203
reftable_buf_release(&scratch);
204
}
205
206
+void test_reftable_record__ref_record_decode_invalid_value_type(void)
207
+{
208
+ struct reftable_buf scratch = REFTABLE_BUF_INIT;
209
+ struct reftable_record out = {
210
+ .type = REFTABLE_BLOCK_TYPE_REF,
211
+ };
212
+ struct reftable_buf key = REFTABLE_BUF_INIT;
213
+ uint8_t buffer[1024] = { 0 };
214
+ struct string_view dest = {
215
+ .buf = buffer,
216
+ .len = sizeof(buffer),
217
+ };
218
+
219
+ cl_must_pass(reftable_buf_addstr(&key, "refs/heads/master"));
220
+ cl_assert_equal_i(reftable_record_decode(&out, key, REFTABLE_NR_REF_VALUETYPES,
221
+ dest, REFTABLE_HASH_SIZE_SHA1, &scratch),
222
+ REFTABLE_FORMAT_ERROR);
223
+
224
+ reftable_record_release(&out);
225
+ reftable_buf_release(&key);
226
+ reftable_buf_release(&scratch);
227
+}
228
+
229
void test_reftable_record__log_record_comparison(void)
230
{
231
struct reftable_record in[3] = {