From aff1ce5ae7202d80237bec6023345bbc7e874166 Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Fri, 18 Sep 2020 14:30:46 -0400 Subject: [PATCH] gvfs-helper: verify loose objects after write It is possible that a loose object that is written from a GVFS protocol "get object" request does not match the expected hash. Error out in this case. 2021-10-30: The prototype for read_loose_object() changed in 31deb28 (fsck: don't hard die on invalid object types, 2021-10-01) and 96e41f5 (fsck: report invalid object type-path combinations, 2021-10-01). Signed-off-by: Derrick Stolee --- gvfs-helper.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/gvfs-helper.c b/gvfs-helper.c index 5ad88170f853da..3a1d688cfe95ee 100644 --- a/gvfs-helper.c +++ b/gvfs-helper.c @@ -1885,6 +1885,33 @@ static void install_packfile(struct gh__request_params *params, child_process_clear(&ip); } +/* + * Wrapper for read_loose_object() to read and verify the hash of a + * loose object, and discard the contents buffer. + * + * Returns 0 on success, negative on error (details may be written to stderr). + */ +static int verify_loose_object(const char *path, + const struct object_id *expected_oid) +{ + enum object_type type; + void *contents = NULL; + unsigned long size; + struct strbuf type_name = STRBUF_INIT; + int ret; + struct object_info oi = OBJECT_INFO_INIT; + struct object_id real_oid = *null_oid(); + oi.typep = &type; + oi.sizep = &size; + oi.type_name = &type_name; + + ret = read_loose_object(path, expected_oid, &real_oid, &contents, &oi); + if (!ret) + free(contents); + + return ret; +} + /* * Convert the tempfile into a permanent loose object in the ODB. */ @@ -1916,6 +1943,19 @@ static void install_loose(struct gh__request_params *params, strbuf_addstr(&tmp_path, get_tempfile_path(params->tempfile)); close_tempfile_gently(params->tempfile); + /* + * Compute the hash of the received content (while it is still + * in a temp file) and verify that it matches the OID that we + * requested and was not corrupted. + */ + if (verify_loose_object(tmp_path.buf, ¶ms->loose_oid)) { + strbuf_addf(&status->error_message, + "hash failed for received loose object '%s'", + oid_to_hex(¶ms->loose_oid)); + status->ec = GH__ERROR_CODE__COULD_NOT_INSTALL_LOOSE; + goto cleanup; + } + /* * Try to install the tempfile as the actual loose object. *