Skip to content

Commit

Permalink
server-info: fix blind pointer arithmetic
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
peff authored and gitster committed Apr 16, 2019
1 parent ddc56d4 commit b83a308
Showing 1 changed file with 12 additions and 10 deletions.
22 changes: 12 additions & 10 deletions server-info.c
Expand Up @@ -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;
Expand All @@ -139,24 +139,26 @@ 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;

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);
Expand Down

0 comments on commit b83a308

Please sign in to comment.