stagit

Fork of `stagit` for git.knutsen.co.
git clone git://git.knutsen.co/stagit
Log | Files | Refs | README | LICENSE

commit ad22404903d25e126d97635b01cecb7be33bfd69
parent f4f53c577eb86d4e65494270a9cf259b27ea22b9
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date:   Wed, 24 Feb 2016 14:47:20 +0100

check path truncation

be strict about it

Diffstat:
MTODO | 2--
Mstagit-index.c | 24++++++++++++++++++------
Mstagit.c | 55++++++++++++++++++++++++++++++++++++++-----------------
3 files changed, 56 insertions(+), 25 deletions(-)

diff --git a/TODO b/TODO @@ -1,5 +1,3 @@ -check path truncation? snprintf(), strlcpy. - performance: - optimize git_diff_get_stats. - speed up generating files. diff --git a/stagit-index.c b/stagit-index.c @@ -178,7 +178,7 @@ main(int argc, char *argv[]) const git_error *e = NULL; FILE *fp; char path[PATH_MAX], *p; - int i, ret = 0; + int i, r, ret = 0; if (argc < 2) { fprintf(stderr, "%s [repodir...]\n", argv[0]); @@ -199,18 +199,24 @@ main(int argc, char *argv[]) continue; } - /* use directory name as name */ + /* use directory name as name, truncation of name is no problem. */ p = xbasename(repodir); snprintf(name, sizeof(name), "%s", p); free(p); /* read description or .git/description */ description[0] = '\0'; - snprintf(path, sizeof(path), "%s%s%s", + r = snprintf(path, sizeof(path), "%s%s%s", repodir, repodir[strlen(repodir)] == '/' ? "" : "/", "description"); + if (r == -1 || (size_t)r >= sizeof(path)) + errx(1, "path truncated: '%s%s%s'", + repodir, repodir[strlen(repodir)] == '/' ? "" : "/", "description"); if (!(fp = fopen(path, "r"))) { - snprintf(path, sizeof(path), "%s%s%s", + r = snprintf(path, sizeof(path), "%s%s%s", repodir, repodir[strlen(repodir)] == '/' ? "" : "/", ".git/description"); + if (r == -1 || (size_t)r >= sizeof(path)) + errx(1, "path truncated: '%s%s%s'", + repodir, repodir[strlen(repodir)] == '/' ? "" : "/", ".git/description"); fp = fopen(path, "r"); } if (fp) { @@ -221,11 +227,17 @@ main(int argc, char *argv[]) /* read owner or .git/owner */ owner[0] = '\0'; - snprintf(path, sizeof(path), "%s%s%s", + r = snprintf(path, sizeof(path), "%s%s%s", repodir, repodir[strlen(repodir)] == '/' ? "" : "/", "owner"); + if (r == -1 || (size_t)r >= sizeof(path)) + errx(1, "path truncated: '%s%s%s'", + repodir, repodir[strlen(repodir)] == '/' ? "" : "/", "owner"); if (!(fp = fopen(path, "r"))) { - snprintf(path, sizeof(path), "%s%s%s", + r = snprintf(path, sizeof(path), "%s%s%s", repodir, repodir[strlen(repodir)] == '/' ? "" : "/", ".git/owner"); + if (r == -1 || (size_t)r >= sizeof(path)) + errx(1, "path truncated: '%s%s%s'", + repodir, repodir[strlen(repodir)] == '/' ? "" : "/", ".git/owner"); fp = fopen(path, "r"); } if (fp) { diff --git a/stagit.c b/stagit.c @@ -188,7 +188,8 @@ mkdirp(const char *path) { char tmp[PATH_MAX], *p; - strlcpy(tmp, path, sizeof(tmp)); + if (strlcpy(tmp, path, sizeof(tmp)) >= sizeof(tmp)) + errx(1, "path truncated: '%s'", path); for (p = tmp + (tmp[0] == '/'); *p; p++) { if (*p != '/') continue; @@ -426,6 +427,7 @@ writelog(FILE *fp, const git_oid *oid) size_t len; char path[PATH_MAX]; FILE *fpfile; + int r; git_revwalk_new(&w, repo); git_revwalk_push(w, oid); @@ -469,7 +471,10 @@ writelog(FILE *fp, const git_oid *oid) relpath = "../"; - snprintf(path, sizeof(path), "commit/%s.html", ci->oid); + r = snprintf(path, sizeof(path), "commit/%s.html", ci->oid); + if (r == -1 || (size_t)r >= sizeof(path)) + errx(1, "path truncated: 'commit/%s.html'", ci->oid); + /* check if file exists if so skip it */ if (access(path, F_OK)) { fpfile = efopen(path, "w"); @@ -591,8 +596,8 @@ writeblob(git_object *obj, const char *fpath, const char *filename, git_off_t fi p = fpath; while (*p) { - if (*p == '/') - strlcat(tmp, "../", sizeof(tmp)); + if (*p == '/' && strlcat(tmp, "../", sizeof(tmp)) >= sizeof(tmp)) + errx(1, "path truncated: '../%s'", tmp); p++; } relpath = tmp; @@ -670,7 +675,7 @@ writefilestree(FILE *fp, git_tree *tree, const char *branch, const char *path) git_object *obj = NULL; git_off_t filesize; size_t count, i; - int lc, ret; + int lc, r, ret; count = git_tree_entrycount(tree); for (i = 0; i < count; i++) { @@ -678,8 +683,11 @@ writefilestree(FILE *fp, git_tree *tree, const char *branch, const char *path) git_tree_entry_to_object(&obj, repo, entry)) return -1; entryname = git_tree_entry_name(entry); - snprintf(entrypath, sizeof(entrypath), "%s%s%s", + r = snprintf(entrypath, sizeof(entrypath), "%s%s%s", path, path[0] ? "/" : "", entryname); + if (r == -1 || (size_t)r >= sizeof(entrypath)) + errx(1, "path truncated: '%s%s%s'", + path, path[0] ? "/" : "", entryname); switch (git_object_type(obj)) { case GIT_OBJ_BLOB: break; @@ -695,12 +703,13 @@ writefilestree(FILE *fp, git_tree *tree, const char *branch, const char *path) git_object_free(obj); continue; } - if (path[0]) - snprintf(filepath, sizeof(filepath), "file/%s/%s.html", - path, entryname); - else - snprintf(filepath, sizeof(filepath), "file/%s.html", - entryname); + + r = snprintf(filepath, sizeof(filepath), "file/%s%s%s.html", + path, path[0] ? "/" : "", entryname); + if (r == -1 || (size_t)r >= sizeof(filepath)) + errx(1, "path truncated: 'file/%s%s%s.html'", + path, path[0] ? "/" : "", entryname); + filesize = git_blob_rawsize((git_blob *)obj); lc = writeblob(obj, filepath, entryname, filesize); @@ -868,7 +877,7 @@ main(int argc, char *argv[]) const git_error *e = NULL; FILE *fp, *fpread; char path[PATH_MAX], *p; - int status; + int r, status; if (argc != 2) { fprintf(stderr, "%s <repodir>\n", argv[0]); @@ -902,11 +911,17 @@ main(int argc, char *argv[]) *p = '\0'; /* read description or .git/description */ - snprintf(path, sizeof(path), "%s%s%s", + r = snprintf(path, sizeof(path), "%s%s%s", repodir, repodir[strlen(repodir)] == '/' ? "" : "/", "description"); + if (r == -1 || (size_t)r >= sizeof(path)) + errx(1, "path truncated: '%s%s%s'", + repodir, repodir[strlen(repodir)] == '/' ? "" : "/", "description"); if (!(fpread = fopen(path, "r"))) { - snprintf(path, sizeof(path), "%s%s%s", + r = snprintf(path, sizeof(path), "%s%s%s", repodir, repodir[strlen(repodir)] == '/' ? "" : "/", ".git/description"); + if (r == -1 || (size_t)r >= sizeof(path)) + errx(1, "path truncated: '%s%s%s'", + repodir, repodir[strlen(repodir)] == '/' ? "" : "/", ".git/description"); fpread = fopen(path, "r"); } if (fpread) { @@ -916,11 +931,17 @@ main(int argc, char *argv[]) } /* read url or .git/url */ - snprintf(path, sizeof(path), "%s%s%s", + r = snprintf(path, sizeof(path), "%s%s%s", repodir, repodir[strlen(repodir)] == '/' ? "" : "/", "url"); + if (r == -1 || (size_t)r >= sizeof(path)) + errx(1, "path truncated: '%s%s%s'", + repodir, repodir[strlen(repodir)] == '/' ? "" : "/", "url"); if (!(fpread = fopen(path, "r"))) { - snprintf(path, sizeof(path), "%s%s%s", + r = snprintf(path, sizeof(path), "%s%s%s", repodir, repodir[strlen(repodir)] == '/' ? "" : "/", ".git/url"); + if (r == -1 || (size_t)r >= sizeof(path)) + errx(1, "path truncated: '%s%s%s'", + repodir, repodir[strlen(repodir)] == '/' ? "" : "/", ".git/url"); fpread = fopen(path, "r"); } if (fpread) {