check path truncation - stagit-gopher - A git gopher frontend. (mirror)
 (HTM) git clone git://bitreich.org/stagit-gopher/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/stagit-gopher/
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit ad22404903d25e126d97635b01cecb7be33bfd69
 (DIR) parent f4f53c577eb86d4e65494270a9cf259b27ea22b9
 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Wed, 24 Feb 2016 14:47:20 +0100
       
       check path truncation
       
       be strict about it
       
       Diffstat:
         M TODO                                |       2 --
         M stagit-index.c                      |      24 ++++++++++++++++++------
         M stagit.c                            |      55 +++++++++++++++++++++----------
       
       3 files changed, 56 insertions(+), 25 deletions(-)
       ---
 (DIR) 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.
 (DIR) 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) {
 (DIR) 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) {