Merge branch 'ap/path-max'

* ap/path-max:
  Prevent buffer overflows when path is too long
This commit is contained in:
Junio C Hamano 2014-01-10 10:32:18 -08:00
commit 273c54f82c
3 changed files with 42 additions and 36 deletions

View File

@ -215,23 +215,25 @@ const char *absolute_path(const char *path)
*/ */
const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
{ {
static char path[PATH_MAX]; static struct strbuf path = STRBUF_INIT;
#ifndef GIT_WINDOWS_NATIVE #ifndef GIT_WINDOWS_NATIVE
if (!pfx_len || is_absolute_path(arg)) if (!pfx_len || is_absolute_path(arg))
return arg; return arg;
memcpy(path, pfx, pfx_len); strbuf_reset(&path);
strcpy(path + pfx_len, arg); strbuf_add(&path, pfx, pfx_len);
strbuf_addstr(&path, arg);
#else #else
char *p; char *p;
/* don't add prefix to absolute paths, but still replace '\' by '/' */ /* don't add prefix to absolute paths, but still replace '\' by '/' */
strbuf_reset(&path);
if (is_absolute_path(arg)) if (is_absolute_path(arg))
pfx_len = 0; pfx_len = 0;
else if (pfx_len) else if (pfx_len)
memcpy(path, pfx, pfx_len); strbuf_add(&path, pfx, pfx_len);
strcpy(path + pfx_len, arg); strbuf_addstr(&path, arg);
for (p = path + pfx_len; *p; p++) for (p = path.buf + pfx_len; *p; p++)
if (*p == '\\') if (*p == '\\')
*p = '/'; *p = '/';
#endif #endif
return path; return path.buf;
} }

View File

@ -73,15 +73,16 @@ struct pair_order {
static int match_order(const char *path) static int match_order(const char *path)
{ {
int i; int i;
char p[PATH_MAX]; static struct strbuf p = STRBUF_INIT;
for (i = 0; i < order_cnt; i++) { for (i = 0; i < order_cnt; i++) {
strcpy(p, path); strbuf_reset(&p);
while (p[0]) { strbuf_addstr(&p, path);
while (p.buf[0]) {
char *cp; char *cp;
if (!fnmatch(order[i], p, 0)) if (!fnmatch(order[i], p.buf, 0))
return i; return i;
cp = strrchr(p, '/'); cp = strrchr(p.buf, '/');
if (!cp) if (!cp)
break; break;
*cp = 0; *cp = 0;

View File

@ -830,23 +830,24 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
} }
static int clear_ce_flags_1(struct cache_entry **cache, int nr, static int clear_ce_flags_1(struct cache_entry **cache, int nr,
char *prefix, int prefix_len, struct strbuf *prefix,
int select_mask, int clear_mask, int select_mask, int clear_mask,
struct exclude_list *el, int defval); struct exclude_list *el, int defval);
/* Whole directory matching */ /* Whole directory matching */
static int clear_ce_flags_dir(struct cache_entry **cache, int nr, static int clear_ce_flags_dir(struct cache_entry **cache, int nr,
char *prefix, int prefix_len, struct strbuf *prefix,
char *basename, char *basename,
int select_mask, int clear_mask, int select_mask, int clear_mask,
struct exclude_list *el, int defval) struct exclude_list *el, int defval)
{ {
struct cache_entry **cache_end; struct cache_entry **cache_end;
int dtype = DT_DIR; int dtype = DT_DIR;
int ret = is_excluded_from_list(prefix, prefix_len, int ret = is_excluded_from_list(prefix->buf, prefix->len,
basename, &dtype, el); basename, &dtype, el);
int rc;
prefix[prefix_len++] = '/'; strbuf_addch(prefix, '/');
/* If undecided, use matching result of parent dir in defval */ /* If undecided, use matching result of parent dir in defval */
if (ret < 0) if (ret < 0)
@ -854,7 +855,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,
for (cache_end = cache; cache_end != cache + nr; cache_end++) { for (cache_end = cache; cache_end != cache + nr; cache_end++) {
struct cache_entry *ce = *cache_end; struct cache_entry *ce = *cache_end;
if (strncmp(ce->name, prefix, prefix_len)) if (strncmp(ce->name, prefix->buf, prefix->len))
break; break;
} }
@ -865,10 +866,12 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,
* calling clear_ce_flags_1(). That function will call * calling clear_ce_flags_1(). That function will call
* the expensive is_excluded_from_list() on every entry. * the expensive is_excluded_from_list() on every entry.
*/ */
return clear_ce_flags_1(cache, cache_end - cache, rc = clear_ce_flags_1(cache, cache_end - cache,
prefix, prefix_len, prefix,
select_mask, clear_mask, select_mask, clear_mask,
el, ret); el, ret);
strbuf_setlen(prefix, prefix->len - 1);
return rc;
} }
/* /*
@ -887,7 +890,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,
* Top level path has prefix_len zero. * Top level path has prefix_len zero.
*/ */
static int clear_ce_flags_1(struct cache_entry **cache, int nr, static int clear_ce_flags_1(struct cache_entry **cache, int nr,
char *prefix, int prefix_len, struct strbuf *prefix,
int select_mask, int clear_mask, int select_mask, int clear_mask,
struct exclude_list *el, int defval) struct exclude_list *el, int defval)
{ {
@ -907,10 +910,10 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,
continue; continue;
} }
if (prefix_len && strncmp(ce->name, prefix, prefix_len)) if (prefix->len && strncmp(ce->name, prefix->buf, prefix->len))
break; break;
name = ce->name + prefix_len; name = ce->name + prefix->len;
slash = strchr(name, '/'); slash = strchr(name, '/');
/* If it's a directory, try whole directory match first */ /* If it's a directory, try whole directory match first */
@ -918,29 +921,26 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,
int processed; int processed;
len = slash - name; len = slash - name;
memcpy(prefix + prefix_len, name, len); strbuf_add(prefix, name, len);
/*
* terminate the string (no trailing slash),
* clear_c_f_dir needs it
*/
prefix[prefix_len + len] = '\0';
processed = clear_ce_flags_dir(cache, cache_end - cache, processed = clear_ce_flags_dir(cache, cache_end - cache,
prefix, prefix_len + len, prefix,
prefix + prefix_len, prefix->buf + prefix->len - len,
select_mask, clear_mask, select_mask, clear_mask,
el, defval); el, defval);
/* clear_c_f_dir eats a whole dir already? */ /* clear_c_f_dir eats a whole dir already? */
if (processed) { if (processed) {
cache += processed; cache += processed;
strbuf_setlen(prefix, prefix->len - len);
continue; continue;
} }
prefix[prefix_len + len++] = '/'; strbuf_addch(prefix, '/');
cache += clear_ce_flags_1(cache, cache_end - cache, cache += clear_ce_flags_1(cache, cache_end - cache,
prefix, prefix_len + len, prefix,
select_mask, clear_mask, el, defval); select_mask, clear_mask, el, defval);
strbuf_setlen(prefix, prefix->len - len - 1);
continue; continue;
} }
@ -961,9 +961,12 @@ static int clear_ce_flags(struct cache_entry **cache, int nr,
int select_mask, int clear_mask, int select_mask, int clear_mask,
struct exclude_list *el) struct exclude_list *el)
{ {
char prefix[PATH_MAX]; static struct strbuf prefix = STRBUF_INIT;
strbuf_reset(&prefix);
return clear_ce_flags_1(cache, nr, return clear_ce_flags_1(cache, nr,
prefix, 0, &prefix,
select_mask, clear_mask, select_mask, clear_mask,
el, 0); el, 0);
} }