Skip to content

Commit e9ba678

Browse files
peffgitster
authored andcommitted
enter_repo: convert fixed-size buffers to strbufs
We use two PATH_MAX-sized buffers to represent the repo path, and must make sure not to overflow them. We do take care to check the lengths, but the logic is rather hard to follow, as we use several magic numbers (e.g., "PATH_MAX - 10"). And in fact you _can_ overflow the buffer if you have a ".git" file with an extremely long path in it. By switching to strbufs, these problems all go away. We do, however, retain the check that the initial input we get is no larger than PATH_MAX. This function is an entry point for untrusted repo names from the network, and it's a good idea to keep a sanity check (both to avoid allocating arbitrary amounts of memory, and also as a layer of defense against any downstream users of the names). Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent b4600fb commit e9ba678

File tree

1 file changed

+29
-28
lines changed

1 file changed

+29
-28
lines changed

path.c

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,8 @@ char *expand_user_path(const char *path)
391391
*/
392392
const char *enter_repo(const char *path, int strict)
393393
{
394-
static char used_path[PATH_MAX];
395-
static char validated_path[PATH_MAX];
394+
static struct strbuf validated_path = STRBUF_INIT;
395+
static struct strbuf used_path = STRBUF_INIT;
396396

397397
if (!path)
398398
return NULL;
@@ -407,46 +407,47 @@ const char *enter_repo(const char *path, int strict)
407407
while ((1 < len) && (path[len-1] == '/'))
408408
len--;
409409

410+
/*
411+
* We can handle arbitrary-sized buffers, but this remains as a
412+
* sanity check on untrusted input.
413+
*/
410414
if (PATH_MAX <= len)
411415
return NULL;
412-
strncpy(used_path, path, len); used_path[len] = 0 ;
413-
strcpy(validated_path, used_path);
414416

415-
if (used_path[0] == '~') {
416-
char *newpath = expand_user_path(used_path);
417-
if (!newpath || (PATH_MAX - 10 < strlen(newpath))) {
418-
free(newpath);
417+
strbuf_reset(&used_path);
418+
strbuf_reset(&validated_path);
419+
strbuf_add(&used_path, path, len);
420+
strbuf_add(&validated_path, path, len);
421+
422+
if (used_path.buf[0] == '~') {
423+
char *newpath = expand_user_path(used_path.buf);
424+
if (!newpath)
419425
return NULL;
420-
}
421-
/*
422-
* Copy back into the static buffer. A pity
423-
* since newpath was not bounded, but other
424-
* branches of the if are limited by PATH_MAX
425-
* anyway.
426-
*/
427-
strcpy(used_path, newpath); free(newpath);
426+
strbuf_attach(&used_path, newpath, strlen(newpath),
427+
strlen(newpath));
428428
}
429-
else if (PATH_MAX - 10 < len)
430-
return NULL;
431-
len = strlen(used_path);
432429
for (i = 0; suffix[i]; i++) {
433430
struct stat st;
434-
strcpy(used_path + len, suffix[i]);
435-
if (!stat(used_path, &st) &&
431+
size_t baselen = used_path.len;
432+
strbuf_addstr(&used_path, suffix[i]);
433+
if (!stat(used_path.buf, &st) &&
436434
(S_ISREG(st.st_mode) ||
437-
(S_ISDIR(st.st_mode) && is_git_directory(used_path)))) {
438-
strcat(validated_path, suffix[i]);
435+
(S_ISDIR(st.st_mode) && is_git_directory(used_path.buf)))) {
436+
strbuf_addstr(&validated_path, suffix[i]);
439437
break;
440438
}
439+
strbuf_setlen(&used_path, baselen);
441440
}
442441
if (!suffix[i])
443442
return NULL;
444-
gitfile = read_gitfile(used_path) ;
445-
if (gitfile)
446-
strcpy(used_path, gitfile);
447-
if (chdir(used_path))
443+
gitfile = read_gitfile(used_path.buf) ;
444+
if (gitfile) {
445+
strbuf_reset(&used_path);
446+
strbuf_addstr(&used_path, gitfile);
447+
}
448+
if (chdir(used_path.buf))
448449
return NULL;
449-
path = validated_path;
450+
path = validated_path.buf;
450451
}
451452
else if (chdir(path))
452453
return NULL;

0 commit comments

Comments
 (0)