aboutsummaryrefslogtreecommitdiffstats
path: root/refs
diff options
context:
space:
mode:
authorKarthik Nayak <karthik.188@gmail.com>2025-01-22 06:35:49 +0100
committerJunio C Hamano <gitster@pobox.com>2025-01-22 09:51:36 -0800
commit017bd8923986acd4992fd21f3451fdd15ec6edce (patch)
tree12458bf0bb55eaab7322ff7f72e6c7d2471d914a /refs
parentrefs: use 'uint64_t' for 'ref_update.index' (diff)
downloadgit-017bd8923986acd4992fd21f3451fdd15ec6edce.tar.gz
git-017bd8923986acd4992fd21f3451fdd15ec6edce.zip
reftable: prevent 'update_index' changes after adding records
The function `reftable_writer_set_limits()` allows updating the 'min_update_index' and 'max_update_index' of a reftable writer. These values are written to both the writer's header and footer. Since the header is written during the first block write, any subsequent changes to the update index would create a mismatch between the header and footer values. The footer would contain the newer values while the header retained the original ones. To protect against this bug, prevent callers from updating these values after any record is written. To do this, modify the function to return an error whenever the limits are modified after any record adds. Check for record adds within `reftable_writer_set_limits()` by checking the `last_key` and `next` variable. The former is updated after each record added, but is reset at certain points. The latter is set after writing the first block. Modify all callers of the function to anticipate a return type and handle it accordingly. Add a unit test to also ensure the function returns the error as expected. Helped-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Karthik Nayak <karthik.188@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'refs')
-rw-r--r--refs/reftable-backend.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index 6814c87bc6..9cfb0cb267 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -1443,7 +1443,9 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
* multiple entries. Each entry will contain a different update_index,
* so set the limits accordingly.
*/
- reftable_writer_set_limits(writer, ts, ts + arg->max_index);
+ ret = reftable_writer_set_limits(writer, ts, ts + arg->max_index);
+ if (ret < 0)
+ goto done;
for (i = 0; i < arg->updates_nr; i++) {
struct reftable_transaction_update *tx_update = &arg->updates[i];
@@ -1766,7 +1768,9 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
deletion_ts = creation_ts = reftable_stack_next_update_index(arg->be->stack);
if (arg->delete_old)
creation_ts++;
- reftable_writer_set_limits(writer, deletion_ts, creation_ts);
+ ret = reftable_writer_set_limits(writer, deletion_ts, creation_ts);
+ if (ret < 0)
+ goto done;
/*
* Add the new reference. If this is a rename then we also delete the
@@ -2298,7 +2302,9 @@ static int write_reflog_existence_table(struct reftable_writer *writer,
if (ret <= 0)
goto done;
- reftable_writer_set_limits(writer, ts, ts);
+ ret = reftable_writer_set_limits(writer, ts, ts);
+ if (ret < 0)
+ goto done;
/*
* The existence entry has both old and new object ID set to the
@@ -2357,7 +2363,9 @@ static int write_reflog_delete_table(struct reftable_writer *writer, void *cb_da
uint64_t ts = reftable_stack_next_update_index(arg->stack);
int ret;
- reftable_writer_set_limits(writer, ts, ts);
+ ret = reftable_writer_set_limits(writer, ts, ts);
+ if (ret < 0)
+ goto out;
ret = reftable_stack_init_log_iterator(arg->stack, &it);
if (ret < 0)
@@ -2434,7 +2442,9 @@ static int write_reflog_expiry_table(struct reftable_writer *writer, void *cb_da
if (arg->records[i].value_type == REFTABLE_LOG_UPDATE)
live_records++;
- reftable_writer_set_limits(writer, ts, ts);
+ ret = reftable_writer_set_limits(writer, ts, ts);
+ if (ret < 0)
+ return ret;
if (!is_null_oid(&arg->update_oid)) {
struct reftable_ref_record ref = {0};