entry.c: fix possible buffer overflow in remove_subtree()

remove_subtree() manipulated path in a fixed-size buffer even though the length of the input, let alone the length of entries within the directory, were not known in advance. Change the function to take a strbuf argument and use that object as its scratch space. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michael Haggerty committed Mar 13, 2014 at 10:19 UTC 2f29e0c6fa5d312c4e0675b0dd23d3126b9f55fa
1 file changed +17 -17
entry.c
+17 -17
@@ -44,33 +44,33 @@ static void create_directories(const char *path, int path_len,
44 free(buf);
45 }
46
47 -static void remove_subtree(const char *path)
47 +static void remove_subtree(struct strbuf *path)
48 {
49 - DIR *dir = opendir(path);
49 + DIR *dir = opendir(path->buf);
50 struct dirent *de;
51 - char pathbuf[PATH_MAX];
52 - char *name;
51 + int origlen = path->len;
52
53 if (!dir)
55 - die_errno("cannot opendir '%s'", path);
56 - strcpy(pathbuf, path);
57 - name = pathbuf + strlen(path);
58 - *name++ = '/';
54 + die_errno("cannot opendir '%s'", path->buf);
55 while ((de = readdir(dir)) != NULL) {
56 struct stat st;
57 +
58 if (is_dot_or_dotdot(de->d_name))
59 continue;
63 - strcpy(name, de->d_name);
64 - if (lstat(pathbuf, &st))
65 - die_errno("cannot lstat '%s'", pathbuf);
60 +
61 + strbuf_addch(path, '/');
62 + strbuf_addstr(path, de->d_name);
63 + if (lstat(path->buf, &st))
64 + die_errno("cannot lstat '%s'", path->buf);
65 if (S_ISDIR(st.st_mode))
67 - remove_subtree(pathbuf);
68 - else if (unlink(pathbuf))
69 - die_errno("cannot unlink '%s'", pathbuf);
66 + remove_subtree(path);
67 + else if (unlink(path->buf))
68 + die_errno("cannot unlink '%s'", path->buf);
69 + strbuf_setlen(path, origlen);
70 }
71 closedir(dir);
72 - if (rmdir(path))
73 - die_errno("cannot rmdir '%s'", path);
72 + if (rmdir(path->buf))
73 + die_errno("cannot rmdir '%s'", path->buf);
74 }
75
76 static int create_file(const char *path, unsigned int mode)
@@ -271,7 +271,7 @@ int checkout_entry(struct cache_entry *ce,
271 return 0;
272 if (!state->force)
273 return error("%s is a directory", path.buf);
274 - remove_subtree(path.buf);
274 + remove_subtree(&path);
275 } else if (unlink(path.buf))
276 return error("unable to unlink old '%s' (%s)",
277 path.buf, strerror(errno));