Revision 447ac906e189535e77dcb1f4bbe3f1bc917d4c12 authored by Patrick Steinhardt on 01 December 2022, 14:45:31 UTC, committed by Junio C Hamano on 05 December 2022, 06:14:16 UTC
The `struct attr_stack` tracks the stack of all patterns together with
their attributes. When parsing a gitattributes file that has more than
2^31 such patterns though we may trigger multiple out-of-bounds reads on
64 bit platforms. This is because while the `num_matches` variable is an
unsigned integer, we always use a signed integer to iterate over them.

I have not been able to reproduce this issue due to memory constraints
on my systems. But despite the out-of-bounds reads, the worst thing that
can seemingly happen is to call free(3P) with a garbage pointer when
calling `attr_stack_free()`.

Fix this bug by using unsigned integers to iterate over the array. While
this makes the iteration somewhat awkward when iterating in reverse, it
is at least better than knowingly running into an out-of-bounds read.
While at it, convert the call to `ALLOC_GROW` to use `ALLOC_GROW_BY`
instead.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 34ace8b
Raw File
fetch-pack.h
#ifndef FETCH_PACK_H
#define FETCH_PACK_H

#include "string-list.h"
#include "run-command.h"
#include "protocol.h"
#include "list-objects-filter-options.h"

struct oid_array;

struct fetch_pack_args {
	const char *uploadpack;
	int unpacklimit;
	int depth;
	const char *deepen_since;
	const struct string_list *deepen_not;
	struct list_objects_filter_options filter_options;
	const struct string_list *server_options;

	/*
	 * If not NULL, during packfile negotiation, fetch-pack will send "have"
	 * lines only with these tips and their ancestors.
	 */
	const struct oid_array *negotiation_tips;

	unsigned deepen_relative:1;
	unsigned quiet:1;
	unsigned keep_pack:1;
	unsigned lock_pack:1;
	unsigned use_thin_pack:1;
	unsigned fetch_all:1;
	unsigned stdin_refs:1;
	unsigned diag_url:1;
	unsigned verbose:1;
	unsigned no_progress:1;
	unsigned include_tag:1;
	unsigned stateless_rpc:1;
	unsigned check_self_contained_and_connected:1;
	unsigned self_contained_and_connected:1;
	unsigned cloning:1;
	unsigned update_shallow:1;
	unsigned deepen:1;

	/*
	 * Indicate that the remote of this request is a promisor remote. The
	 * pack received does not need all referred-to objects to be present in
	 * the local object store, and fetch-pack will store the pack received
	 * together with a ".promisor" file indicating that the aforementioned
	 * pack is a promisor pack.
	 */
	unsigned from_promisor:1;

	/*
	 * Because fetch_pack() overwrites the shallow file upon a
	 * successful deepening non-clone fetch, if this struct
	 * specifies such a fetch, fetch_pack() needs to perform a
	 * connectivity check before deciding if a fetch is successful
	 * (and overwriting the shallow file). fetch_pack() sets this
	 * field to 1 if such a connectivity check was performed.
	 *
	 * This is different from check_self_contained_and_connected
	 * in that the former allows existing objects in the
	 * repository to satisfy connectivity needs, whereas the
	 * latter doesn't.
	 */
	unsigned connectivity_checked:1;
};

/*
 * sought represents remote references that should be updated from.
 * On return, the names that were found on the remote will have been
 * marked as such.
 */
struct ref *fetch_pack(struct fetch_pack_args *args,
		       int fd[],
		       const struct ref *ref,
		       struct ref **sought,
		       int nr_sought,
		       struct oid_array *shallow,
		       struct string_list *pack_lockfiles,
		       enum protocol_version version);

/*
 * Print an appropriate error message for each sought ref that wasn't
 * matched.  Return 0 if all sought refs were matched, otherwise 1.
 */
int report_unmatched_refs(struct ref **sought, int nr_sought);

#endif
back to top