http: simplify parsing of remote objects/info/packs

We can use skip_prefix() and parse_oid_hex() to continuously increment our pointer, rather than dealing with magic numbers. This also fixes a few small shortcomings: - if we see a line with the right prefix, suffix, and length, i.e. matching /P pack-.{40}.pack\n/, we'll interpret the middle part as hex without checking if it could be parsed. This could lead to us looking at uninitialized garbage in the hash array. In practice this means we'll just make a garbage request to the server which will fail, though it's interesting that a malicious server could convince us to leak 40 bytes of uninitialized stack to them. - the current code is picky about seeing a newline at the end of file, but we can easily be more liberal Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Apr 5, 2019 at 14:12 UTC ddc56d4710fa004c922349407f3de0c3adf90ac9
1 file changed +14 -21
http.c
+14 -21
@@ -2147,11 +2147,11 @@ add_pack:
2147 int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
2148 {
2149 struct http_get_options options = {0};
2150 - int ret = 0, i = 0;
2151 - char *url, *data;
2150 + int ret = 0;
2151 + char *url;
2152 + const char *data;
2153 struct strbuf buf = STRBUF_INIT;
2153 - unsigned char hash[GIT_MAX_RAWSZ];
2154 - const unsigned hexsz = the_hash_algo->hexsz;
2154 + struct object_id oid;
2155
2156 end_url_with_slash(&buf, base_url);
2157 strbuf_addstr(&buf, "objects/info/packs");
@@ -2163,24 +2163,17 @@ int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
2163 goto cleanup;
2164
2165 data = buf.buf;
2166 - while (i < buf.len) {
2167 - switch (data[i]) {
2168 - case 'P':
2169 - i++;
2170 - if (i + hexsz + 12 <= buf.len &&
2171 - starts_with(data + i, " pack-") &&
2172 - starts_with(data + i + hexsz + 6, ".pack\n")) {
2173 - get_sha1_hex(data + i + 6, hash);
2174 - fetch_and_setup_pack_index(packs_head, hash,
2175 - base_url);
2176 - i += hexsz + 11;
2177 - break;
2178 - }
2179 - default:
2180 - while (i < buf.len && data[i] != '\n')
2181 - i++;
2166 + while (*data) {
2167 + if (skip_prefix(data, "P pack-", &data) &&
2168 + !parse_oid_hex(data, &oid, &data) &&
2169 + skip_prefix(data, ".pack", &data) &&
2170 + (*data == '\n' || *data == '\0')) {
2171 + fetch_and_setup_pack_index(packs_head, oid.hash, base_url);
2172 + } else {
2173 + data = strchrnul(data, '\n');
2174 }
2183 - i++;
2175 + if (*data)
2176 + data++; /* skip past newline */
2177 }
2178
2179 cleanup: