Merge branch 'js/coverity-fixes' into seen

Assorted fixes for code paths that are not careful with boundary and
error conditions.

* js/coverity-fixes:
  test-read-midx: check midx_fill_entry() result
  oss-fuzz: handle reftable iterator initialization failures
  t/unit-tests: check reftable iterator initialization
  rerere: do not record failed conflict resolution data
  midx: validate incremental MIDX pack IDs
  gpg-interface: make signature-prefix matching length-aware
  wrapper: guard writev_in_full() against signed overflow
Junio C Hamano 2026-09-17 12:54:48 -07:00
commit 085e805e35
7 changed files with 61 additions and 23 deletions

View File

@ -133,20 +133,20 @@ static struct gpg_format *get_format_by_name(const char *str)
return NULL;
}

static struct gpg_format *get_format_by_sig(const char *sig)
static struct gpg_format *get_format_by_sig(const char *sig, size_t len)
{
int j;

for (size_t i = 0; i < ARRAY_SIZE(gpg_format); i++)
for (j = 0; gpg_format[i].sigs[j]; j++)
if (starts_with(sig, gpg_format[i].sigs[j]))
if (starts_with_mem(sig, len, gpg_format[i].sigs[j]))
return gpg_format + i;
return NULL;
}

const char *get_signature_format(const char *buf)
{
struct gpg_format *format = get_format_by_sig(buf);
struct gpg_format *format = get_format_by_sig(buf, strlen(buf));
return format ? format->name : "unknown";
}

@ -669,7 +669,7 @@ int check_signature(struct signature_check *sigc,
sigc->result = 'N';
sigc->trust_level = TRUST_UNDEFINED;

fmt = get_format_by_sig(signature);
fmt = get_format_by_sig(signature, slen);
if (!fmt)
die(_("bad/incompatible signature '%s'"), signature);

@ -706,7 +706,7 @@ size_t parse_signed_buffer(const char *buf, size_t size)
while (len < size) {
const char *eol;

if (get_format_by_sig(buf + len))
if (get_format_by_sig(buf + len, size - len))
match = len;

eol = memchr(buf + len, '\n', size - len);

14
midx.c
View File

@ -583,10 +583,16 @@ off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos)

uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos)
{
pos = midx_for_object(&m, pos);
uint32_t pack_int_id;

return m->num_packs_in_base + get_be32(m->chunk_object_offsets +
(off_t)pos * MIDX_CHUNK_OFFSET_WIDTH);
pos = midx_for_object(&m, pos);
pack_int_id = get_be32(m->chunk_object_offsets +
(off_t)pos * MIDX_CHUNK_OFFSET_WIDTH);
if (pack_int_id >= m->num_packs)
die(_("bad pack-int-id: %"PRIu32" (%"PRIu32" total packs)"),
pack_int_id, m->num_packs);

return m->num_packs_in_base + pack_int_id;
}

enum midx_fill_result midx_fill_entry(struct multi_pack_index *m,
@ -606,7 +612,7 @@ enum midx_fill_result midx_fill_entry(struct multi_pack_index *m,

if (prepare_midx_pack(m, pack_int_id))
return MIDX_FILL_OWNER_UNAVAILABLE;
p = m->packs[pack_int_id - m->num_packs_in_base];
p = nth_midxed_pack(m, pack_int_id);

/*
* We are about to tell the caller where they can locate the

View File

@ -33,10 +33,11 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
struct reftable_ref_record ref = { 0 };
struct reftable_iterator it = { 0 };

reftable_table_init_ref_iterator(table, &it);
if (!reftable_iterator_seek_ref(&it, ""))
while (!reftable_iterator_next_ref(&it, &ref))
;
if (!reftable_table_init_ref_iterator(table, &it)) {
if (!reftable_iterator_seek_ref(&it, ""))
while (!reftable_iterator_next_ref(&it, &ref))
;
}

reftable_ref_record_release(&ref);
reftable_iterator_destroy(&it);
@ -46,10 +47,11 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
struct reftable_log_record log = { 0 };
struct reftable_iterator it = { 0 };

reftable_table_init_log_iterator(table, &it);
if (!reftable_iterator_seek_log(&it, ""))
while (!reftable_iterator_next_log(&it, &log))
;
if (!reftable_table_init_log_iterator(table, &it)) {
if (!reftable_iterator_seek_log(&it, ""))
while (!reftable_iterator_next_log(&it, &log))
;
}

reftable_log_record_release(&log);
reftable_iterator_destroy(&it);

View File

@ -480,8 +480,11 @@ static int handle_file(struct index_state *istate,
unlink_or_warn(output);
return error(_("could not parse conflict hunks in '%s'"), path);
}
if (io.io.wrerror)
if (io.io.wrerror) {
if (output)
unlink_or_warn(output);
return -1;
}
return has_conflicts;
}

@ -733,8 +736,25 @@ static void do_rerere_one_path(struct index_state *istate,

/* Has the user resolved it already? */
if (variant >= 0) {
if (!handle_file(istate, path, NULL, NULL)) {
copy_file(the_repository, rerere_path(&buf, id, "postimage"), path, 0666);
int ret = handle_file(istate, path, NULL, NULL);

if (ret < 0)
goto out;
if (!ret) {
const int had_postimage =
id->collection->status[variant] & RR_HAS_POSTIMAGE;
const char *postimage =
rerere_path(&buf, id, "postimage");

if (copy_file(the_repository,
postimage,
path, 0666)) {
if (!had_postimage)
unlink_or_warn(postimage);
error_errno(_("could not copy resolution for '%s'"),
path);
goto out;
}
id->collection->status[variant] |= RR_HAS_POSTIMAGE;
fprintf_ln(stderr, _("Recorded resolution for '%s'."), path);
free_rerere_id(rr_item);
@ -782,7 +802,9 @@ static void do_rerere_one_path(struct index_state *istate,
assign_variant(id);

variant = id->variant;
handle_file(istate, path, NULL, rerere_path(&buf, id, "preimage"));
if (handle_file(istate, path, NULL,
rerere_path(&buf, id, "preimage")) < 0)
goto out;
if (id->collection->status[variant] & RR_HAS_POSTIMAGE) {
const char *path = rerere_path(&buf, id, "postimage");
if (unlink(path))

View File

@ -90,7 +90,11 @@ static int read_midx_file(const char *object_dir, const char *checksum,
for (i = 0; i < m->num_objects; i++) {
nth_midxed_object_oid(&oid, m,
i + m->num_objects_in_base);
midx_fill_entry(m, &oid, &e, NULL);
if (midx_fill_entry(m, &oid, &e, NULL) !=
MIDX_FILL_HIT) {
ret = error(_("failed to load pack entry"));
goto out;
}

printf("%s %"PRIu64"\t%s\n",
oid_to_hex(&oid), e.offset, e.p->pack_name);

View File

@ -257,7 +257,7 @@ void test_reftable_table__seek_invalid_log_offset(void)
* know that the table is corrupt, so the seek must report a format
* error instead of pretending that the section is empty.
*/
reftable_table_init_log_iterator(table, &it);
cl_assert_equal_i(reftable_table_init_log_iterator(table, &it), 0);
cl_assert_equal_i(reftable_iterator_seek_log(&it, ""),
REFTABLE_FORMAT_ERROR);


View File

@ -376,6 +376,10 @@ ssize_t writev_in_full(int fd, struct iovec *iov, int iovcnt)
return -1;
}

if (signed_add_overflows(total_written, bytes_written)) {
errno = EOVERFLOW;
return -1;
}
total_written += bytes_written;

/*