diff options
author | Jeff King <peff@peff.net> | 2019-04-05 14:13:10 -0400 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2019-04-16 16:58:21 +0900 |
commit | b83a3089b584f622054e85b9bacbd18014259b7c (patch) | |
tree | 45a47f025d4ebe8e740bee0388f24c35d6d305e0 /server-info.c | |
parent | ddc56d4710fa004c922349407f3de0c3adf90ac9 (diff) | |
download | git-b83a3089b584f622054e85b9bacbd18014259b7c.tar.gz |
server-info: fix blind pointer arithmetic
When we're writing out a new objects/info/packs file, we read back the
old one to try to keep the ordering the same. When we see a line
starting with "P", we expect "P pack-1234..." and blindly jump to "line
+ 2" to parse the pack name. If we saw a line with _just_ "P" and
nothing else, we'd jump past the end of the buffer and start reading
arbitrary memory.
This shouldn't be a big attack vector, as the files are local to the
repository and written by us, but it's clearly worth fixing (we do read
remote copies of the file for dumb-http fetches, but using a totally
different parser!).
Let's instead use skip_prefix() here, which avoids pointer arithmetic
altogether. Note that this converts our switch statement to an if/else
chain, making it slightly more verbose. But it will also make it easier
to do a few follow-on cleanups.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'server-info.c')
-rw-r--r-- | server-info.c | 22 |
1 files changed, 12 insertions, 10 deletions
diff --git a/server-info.c b/server-info.c index e2b2d6a27a..b61a6be4c2 100644 --- a/server-info.c +++ b/server-info.c @@ -112,9 +112,9 @@ static struct pack_info *find_pack_by_name(const char *name) /* Returns non-zero when we detect that the info in the * old file is useless. */ -static int parse_pack_def(const char *line, int old_cnt) +static int parse_pack_def(const char *packname, int old_cnt) { - struct pack_info *i = find_pack_by_name(line + 2); + struct pack_info *i = find_pack_by_name(packname); if (i) { i->old_num = old_cnt; return 0; @@ -139,6 +139,7 @@ static int read_pack_info_file(const char *infofile) return 1; /* nonexistent is not an error. */ while (fgets(line, sizeof(line), fp)) { + const char *arg; int len = strlen(line); if (len && line[len-1] == '\n') line[--len] = 0; @@ -146,17 +147,18 @@ static int read_pack_info_file(const char *infofile) if (!len) continue; - switch (line[0]) { - case 'P': /* P name */ - if (parse_pack_def(line, old_cnt++)) + if (skip_prefix(line, "P ", &arg)) { + /* P name */ + if (parse_pack_def(arg, old_cnt++)) goto out_stale; - break; - case 'D': /* we used to emit D but that was misguided. */ - case 'T': /* we used to emit T but nobody uses it. */ + } else if (line[0] == 'D') { + /* we used to emit D but that was misguided. */ goto out_stale; - default: + } else if (line[0] == 'T') { + /* we used to emit T but nobody uses it. */ + goto out_stale; + } else { error("unrecognized: %s", line); - break; } } fclose(fp); |