Skip to content

Commit b2f69fa

Browse files
pabloosabaterrgitster
authored andcommitted
cat-file: validate remote atoms with an allow-list
strstr() is not enough to validate the format placeholders in remote-object-info causing two errors: 1. Atoms recognized by expand_atom() but the remote doesn't returns 1, but data->type contains garbage causing segfault. 2. expand_atom() returns 0 for unknown atoms, calling strbuf_expand_bad_format() which ends up dying, blocking local queries if the same format is shared. Add an allow-list with the supported atoms at the top of expand_atom(). In remote mode, unsupported atoms return 1 leaving the buffer empty, honoring how for-each-ref handles known but inapplicable atoms. As extra safety, initialize data->type to OBJ_BAD and add a NULL check for type_name() so uninitialized data doesn't cause segfault. Update tests that expect previous die() behavior to expect an empty string and add an explicit test for empty string return on unknown placeholder. Update cat-file command documentation regarding remote-object-info. Mentored-by: Karthik Nayak <karthik.188@gmail.com> Mentored-by: Chandra Pratap <chandrapratap3519@gmail.com> Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 1efc301 commit b2f69fa

3 files changed

Lines changed: 57 additions & 13 deletions

File tree

Documentation/git-cat-file.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ CAVEATS
451451
452452
Note that since only `%(objectname)` and `%(objectsize)` are currently
453453
supported by the `remote-object-info` command. Using any other placeholder in
454-
the format string will raise an error.
454+
the format string will return an empty string in its position.
455455
456456
Note that the sizes of objects on disk are reported accurately, but care
457457
should be taken in drawing conclusions about which refs or objects are

builtin/cat-file.c

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,18 @@ struct expand_data {
336336
* optimized out.
337337
*/
338338
unsigned skip_object_info : 1;
339+
340+
/*
341+
* Flags about when an object info is being fetched from remote.
342+
*/
343+
unsigned is_remote:1;
344+
};
345+
#define EXPAND_DATA_INIT { .mode = S_IFINVALID, .type = OBJ_BAD }
346+
347+
static const char *remote_object_info_atoms[] = {
348+
"objectname",
349+
"objectsize",
339350
};
340-
#define EXPAND_DATA_INIT { .mode = S_IFINVALID }
341351

342352
static int is_atom(const char *atom, const char *s, int slen)
343353
{
@@ -348,14 +358,31 @@ static int is_atom(const char *atom, const char *s, int slen)
348358
static int expand_atom(struct strbuf *sb, const char *atom, int len,
349359
struct expand_data *data)
350360
{
361+
if (data->is_remote) {
362+
size_t i, allowed_nr = ARRAY_SIZE(remote_object_info_atoms);
363+
for (i = 0; i < allowed_nr; i++)
364+
if (is_atom(remote_object_info_atoms[i], atom, len))
365+
break;
366+
367+
/*
368+
* On remote, skip unsupported atoms returning an empty sb,
369+
* honoring how for-each-ref handles known but inapplicable
370+
* atoms (e.g. %(tagger)).
371+
*/
372+
if (i == allowed_nr)
373+
return 1;
374+
}
375+
351376
if (is_atom("objectname", atom, len)) {
352377
if (!data->mark_query)
353378
strbuf_add_oid_hex(sb, &data->oid);
354379
} else if (is_atom("objecttype", atom, len)) {
355-
if (data->mark_query)
380+
if (data->mark_query) {
356381
data->info.typep = &data->type;
357-
else
358-
strbuf_addstr(sb, type_name(data->type));
382+
} else {
383+
const char *t = type_name(data->type);
384+
strbuf_addstr(sb, t ? t : "");
385+
}
359386
} else if (is_atom("objectsize", atom, len)) {
360387
if (data->mark_query)
361388
data->info.sizep = &data->size;
@@ -711,10 +738,6 @@ static int get_remote_info(struct batch_options *opt,
711738
CALLOC_ARRAY(*remote_object_info, object_info_oids->nr);
712739
gtransport->smart_options->object_info_oids = object_info_oids;
713740

714-
/* 'objectsize' is the only option currently supported */
715-
if (!strstr(opt->format, "%(objectsize)"))
716-
die(_("%s is currently not supported with remote-object-info"), opt->format);
717-
718741
string_list_append(&object_info_options, "size");
719742

720743
if (object_info_options.nr > 0) {
@@ -844,7 +867,9 @@ static void parse_cmd_remote_object_info(struct batch_options *opt,
844867
*/
845868
data->size = *remote_object_info[i].sizep;
846869
opt->batch_mode = BATCH_MODE_INFO;
870+
data->is_remote = 1;
847871
batch_object_write(argv[i + 1], output, opt, data, NULL, 0);
872+
data->is_remote = 0;
848873
} else {
849874
report_object_status(opt, oid_to_hex(&data->oid), &data->oid, "missing");
850875
}

t/t1017-cat-file-remote-object-info.sh

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,21 @@ test_expect_success 'remote-object-info does not die on missing oid like info' '
236236
)
237237
'
238238

239+
# This tests depends on %(objecttype) not being supported yet, once supported
240+
# it needs to be updated.
241+
test_expect_success 'unsupported placeholder on remote returns empty string' '
242+
(
243+
set_transport_variables "$daemon_parent" &&
244+
cd "$daemon_parent/daemon_client_empty" &&
245+
246+
echo "" >expect &&
247+
git cat-file --batch-command="%(objecttype)" >actual <<-EOF &&
248+
remote-object-info "$GIT_DAEMON_URL/parent" $hello_oid
249+
EOF
250+
test_cmp expect actual
251+
)
252+
'
253+
239254
# Test --batch-command remote-object-info with 'git://' and
240255
# transfer.advertiseobjectinfo set to false, i.e. server does not have object-info capability
241256
test_expect_success 'batch-command remote-object-info git:// fails when transfer.advertiseobjectinfo=false' '
@@ -575,10 +590,12 @@ test_expect_success 'remote-object-info fails on unsupported filter option (obje
575590
set_transport_variables "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
576591
cd "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
577592
578-
test_must_fail git cat-file --batch-command="%(objectsize:disk)" 2>err <<-EOF &&
593+
echo "$hello_oid " >expect &&
594+
595+
git cat-file --batch-command="%(objectname) %(objectsize:disk)" >actual <<-EOF &&
579596
remote-object-info "$HTTPD_URL/smart/http_parent" $hello_oid
580597
EOF
581-
test_grep "%(objectsize:disk) is currently not supported with remote-object-info" err
598+
test_cmp expect actual
582599
)
583600
'
584601

@@ -587,10 +604,12 @@ test_expect_success 'remote-object-info fails on unsupported filter option (delt
587604
set_transport_variables "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
588605
cd "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
589606
590-
test_must_fail git cat-file --batch-command="%(deltabase)" 2>err <<-EOF &&
607+
echo "" >expect &&
608+
609+
git cat-file --batch-command="%(deltabase)" >actual <<-EOF &&
591610
remote-object-info "$HTTPD_URL/smart/http_parent" $hello_oid
592611
EOF
593-
test_grep "%(deltabase) is currently not supported with remote-object-info" err
612+
test_cmp expect actual
594613
)
595614
'
596615

0 commit comments

Comments
 (0)