mailsplit: make PATH_MAX buffers dynamic

There are several PATH_MAX-sized buffers in mailsplit, along
with some questionable uses of sprintf.  These are not
really of security interest, as local mailsplit pathnames
are not typically under control of an attacker, and you
could generally only overflow a few numbers at the end of a
path that approaches PATH_MAX (a longer path would choke
mailsplit long before). But it does not hurt to be careful,
and as a bonus we lift some limits for systems with
too-small PATH_MAX varibles.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jeff King 2015-09-24 17:05:51 -04:00 committed by Junio C Hamano
parent c1fd080917
commit 1d895f194f

View File

@ -98,30 +98,37 @@ static int populate_maildir_list(struct string_list *list, const char *path)
{ {
DIR *dir; DIR *dir;
struct dirent *dent; struct dirent *dent;
char name[PATH_MAX]; char *name = NULL;
char *subs[] = { "cur", "new", NULL }; char *subs[] = { "cur", "new", NULL };
char **sub; char **sub;
int ret = -1;
for (sub = subs; *sub; ++sub) { for (sub = subs; *sub; ++sub) {
snprintf(name, sizeof(name), "%s/%s", path, *sub); free(name);
name = xstrfmt("%s/%s", path, *sub);
if ((dir = opendir(name)) == NULL) { if ((dir = opendir(name)) == NULL) {
if (errno == ENOENT) if (errno == ENOENT)
continue; continue;
error("cannot opendir %s (%s)", name, strerror(errno)); error("cannot opendir %s (%s)", name, strerror(errno));
return -1; goto out;
} }
while ((dent = readdir(dir)) != NULL) { while ((dent = readdir(dir)) != NULL) {
if (dent->d_name[0] == '.') if (dent->d_name[0] == '.')
continue; continue;
snprintf(name, sizeof(name), "%s/%s", *sub, dent->d_name); free(name);
name = xstrfmt("%s/%s", *sub, dent->d_name);
string_list_insert(list, name); string_list_insert(list, name);
} }
closedir(dir); closedir(dir);
} }
return 0; ret = 0;
out:
free(name);
return ret;
} }
static int maildir_filename_cmp(const char *a, const char *b) static int maildir_filename_cmp(const char *a, const char *b)
@ -148,8 +155,7 @@ static int maildir_filename_cmp(const char *a, const char *b)
static int split_maildir(const char *maildir, const char *dir, static int split_maildir(const char *maildir, const char *dir,
int nr_prec, int skip) int nr_prec, int skip)
{ {
char file[PATH_MAX]; char *file = NULL;
char name[PATH_MAX];
FILE *f = NULL; FILE *f = NULL;
int ret = -1; int ret = -1;
int i; int i;
@ -161,7 +167,11 @@ static int split_maildir(const char *maildir, const char *dir,
goto out; goto out;
for (i = 0; i < list.nr; i++) { for (i = 0; i < list.nr; i++) {
snprintf(file, sizeof(file), "%s/%s", maildir, list.items[i].string); char *name;
free(file);
file = xstrfmt("%s/%s", maildir, list.items[i].string);
f = fopen(file, "r"); f = fopen(file, "r");
if (!f) { if (!f) {
error("cannot open mail %s (%s)", file, strerror(errno)); error("cannot open mail %s (%s)", file, strerror(errno));
@ -173,8 +183,9 @@ static int split_maildir(const char *maildir, const char *dir,
goto out; goto out;
} }
sprintf(name, "%s/%0*d", dir, nr_prec, ++skip); name = xstrfmt("%s/%0*d", dir, nr_prec, ++skip);
split_one(f, name, 1); split_one(f, name, 1);
free(name);
fclose(f); fclose(f);
f = NULL; f = NULL;
@ -184,6 +195,7 @@ static int split_maildir(const char *maildir, const char *dir,
out: out:
if (f) if (f)
fclose(f); fclose(f);
free(file);
string_list_clear(&list, 1); string_list_clear(&list, 1);
return ret; return ret;
} }
@ -191,7 +203,6 @@ out:
static int split_mbox(const char *file, const char *dir, int allow_bare, static int split_mbox(const char *file, const char *dir, int allow_bare,
int nr_prec, int skip) int nr_prec, int skip)
{ {
char name[PATH_MAX];
int ret = -1; int ret = -1;
int peek; int peek;
@ -218,8 +229,9 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
} }
while (!file_done) { while (!file_done) {
sprintf(name, "%s/%0*d", dir, nr_prec, ++skip); char *name = xstrfmt("%s/%0*d", dir, nr_prec, ++skip);
file_done = split_one(f, name, allow_bare); file_done = split_one(f, name, allow_bare);
free(name);
} }
if (f != stdin) if (f != stdin)