Merge branch 'jk/snprintf-truncation'
authorJunio C Hamano <gitster@pobox.com>
Wed, 30 May 2018 12:51:27 +0000 (21:51 +0900)
committerJunio C Hamano <gitster@pobox.com>
Wed, 30 May 2018 12:51:28 +0000 (21:51 +0900)
Avoid unchecked snprintf() to make future code auditing easier.

* jk/snprintf-truncation:
fmt_with_err: add a comment that truncation is OK
shorten_unambiguous_ref: use xsnprintf
fsmonitor: use internal argv_array of struct child_process
log_write_email_headers: use strbufs
http: use strbufs instead of fixed buffers

fsmonitor.c
http.c
http.h
log-tree.c
refs.c
usage.c
index ed3d1a074d60309063d16044bfd83beb78ef0e9d..665bd2d4254b12edf38e94cb0e8b2200ae3bf34a 100644 (file)
@@ -97,19 +97,13 @@ void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)
 static int query_fsmonitor(int version, uint64_t last_update, struct strbuf *query_result)
 {
        struct child_process cp = CHILD_PROCESS_INIT;
-       char ver[64];
-       char date[64];
-       const char *argv[4];
 
-       if (!(argv[0] = core_fsmonitor))
+       if (!core_fsmonitor)
                return -1;
 
-       snprintf(ver, sizeof(ver), "%d", version);
-       snprintf(date, sizeof(date), "%" PRIuMAX, (uintmax_t)last_update);
-       argv[1] = ver;
-       argv[2] = date;
-       argv[3] = NULL;
-       cp.argv = argv;
+       argv_array_push(&cp.args, core_fsmonitor);
+       argv_array_pushf(&cp.args, "%d", version);
+       argv_array_pushf(&cp.args, "%" PRIuMAX, (uintmax_t)last_update);
        cp.use_shell = 1;
        cp.dir = get_git_work_tree();
 
diff --git a/http.c b/http.c
index d9155972d68e82c188a41d0a2a02728d9862570b..deea47411a9d263fc87d9ff03f6b3bf6fa0d0fff 100644 (file)
--- a/http.c
+++ b/http.c
@@ -2083,6 +2083,7 @@ void release_http_pack_request(struct http_pack_request *preq)
                preq->packfile = NULL;
        }
        preq->slot = NULL;
+       strbuf_release(&preq->tmpfile);
        free(preq->url);
        free(preq);
 }
@@ -2105,19 +2106,19 @@ int finish_http_pack_request(struct http_pack_request *preq)
                lst = &((*lst)->next);
        *lst = (*lst)->next;
 
-       if (!strip_suffix(preq->tmpfile, ".pack.temp", &len))
+       if (!strip_suffix(preq->tmpfile.buf, ".pack.temp", &len))
                BUG("pack tmpfile does not end in .pack.temp?");
-       tmp_idx = xstrfmt("%.*s.idx.temp", (int)len, preq->tmpfile);
+       tmp_idx = xstrfmt("%.*s.idx.temp", (int)len, preq->tmpfile.buf);
 
        argv_array_push(&ip.args, "index-pack");
        argv_array_pushl(&ip.args, "-o", tmp_idx, NULL);
-       argv_array_push(&ip.args, preq->tmpfile);
+       argv_array_push(&ip.args, preq->tmpfile.buf);
        ip.git_cmd = 1;
        ip.no_stdin = 1;
        ip.no_stdout = 1;
 
        if (run_command(&ip)) {
-               unlink(preq->tmpfile);
+               unlink(preq->tmpfile.buf);
                unlink(tmp_idx);
                free(tmp_idx);
                return -1;
@@ -2125,7 +2126,7 @@ int finish_http_pack_request(struct http_pack_request *preq)
 
        unlink(sha1_pack_index_name(p->sha1));
 
-       if (finalize_object_file(preq->tmpfile, sha1_pack_name(p->sha1))
+       if (finalize_object_file(preq->tmpfile.buf, sha1_pack_name(p->sha1))
         || finalize_object_file(tmp_idx, sha1_pack_index_name(p->sha1))) {
                free(tmp_idx);
                return -1;
@@ -2144,6 +2145,7 @@ struct http_pack_request *new_http_pack_request(
        struct http_pack_request *preq;
 
        preq = xcalloc(1, sizeof(*preq));
+       strbuf_init(&preq->tmpfile, 0);
        preq->target = target;
 
        end_url_with_slash(&buf, base_url);
@@ -2151,12 +2153,11 @@ struct http_pack_request *new_http_pack_request(
                sha1_to_hex(target->sha1));
        preq->url = strbuf_detach(&buf, NULL);
 
-       snprintf(preq->tmpfile, sizeof(preq->tmpfile), "%s.temp",
-               sha1_pack_name(target->sha1));
-       preq->packfile = fopen(preq->tmpfile, "a");
+       strbuf_addf(&preq->tmpfile, "%s.temp", sha1_pack_name(target->sha1));
+       preq->packfile = fopen(preq->tmpfile.buf, "a");
        if (!preq->packfile) {
                error("Unable to open local file %s for pack",
-                     preq->tmpfile);
+                     preq->tmpfile.buf);
                goto abort;
        }
 
@@ -2183,6 +2184,7 @@ struct http_pack_request *new_http_pack_request(
        return preq;
 
 abort:
+       strbuf_release(&preq->tmpfile);
        free(preq->url);
        free(preq);
        return NULL;
@@ -2233,7 +2235,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
 {
        char *hex = sha1_to_hex(sha1);
        struct strbuf filename = STRBUF_INIT;
-       char prevfile[PATH_MAX];
+       struct strbuf prevfile = STRBUF_INIT;
        int prevlocal;
        char prev_buf[PREV_BUF_SIZE];
        ssize_t prev_read = 0;
@@ -2241,40 +2243,41 @@ struct http_object_request *new_http_object_request(const char *base_url,
        struct http_object_request *freq;
 
        freq = xcalloc(1, sizeof(*freq));
+       strbuf_init(&freq->tmpfile, 0);
        hashcpy(freq->sha1, sha1);
        freq->localfile = -1;
 
        sha1_file_name(the_repository, &filename, sha1);
-       snprintf(freq->tmpfile, sizeof(freq->tmpfile),
-                "%s.temp", filename.buf);
+       strbuf_addf(&freq->tmpfile, "%s.temp", filename.buf);
 
-       snprintf(prevfile, sizeof(prevfile), "%s.prev", filename.buf);
-       unlink_or_warn(prevfile);
-       rename(freq->tmpfile, prevfile);
-       unlink_or_warn(freq->tmpfile);
+       strbuf_addf(&prevfile, "%s.prev", filename.buf);
+       unlink_or_warn(prevfile.buf);
+       rename(freq->tmpfile.buf, prevfile.buf);
+       unlink_or_warn(freq->tmpfile.buf);
        strbuf_release(&filename);
 
        if (freq->localfile != -1)
                error("fd leakage in start: %d", freq->localfile);
-       freq->localfile = open(freq->tmpfile,
+       freq->localfile = open(freq->tmpfile.buf,
                               O_WRONLY | O_CREAT | O_EXCL, 0666);
        /*
         * This could have failed due to the "lazy directory creation";
         * try to mkdir the last path component.
         */
        if (freq->localfile < 0 && errno == ENOENT) {
-               char *dir = strrchr(freq->tmpfile, '/');
+               char *dir = strrchr(freq->tmpfile.buf, '/');
                if (dir) {
                        *dir = 0;
-                       mkdir(freq->tmpfile, 0777);
+                       mkdir(freq->tmpfile.buf, 0777);
                        *dir = '/';
                }
-               freq->localfile = open(freq->tmpfile,
+               freq->localfile = open(freq->tmpfile.buf,
                                       O_WRONLY | O_CREAT | O_EXCL, 0666);
        }
 
        if (freq->localfile < 0) {
-               error_errno("Couldn't create temporary file %s", freq->tmpfile);
+               error_errno("Couldn't create temporary file %s",
+                           freq->tmpfile.buf);
                goto abort;
        }
 
@@ -2288,7 +2291,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
         * If a previous temp file is present, process what was already
         * fetched.
         */
-       prevlocal = open(prevfile, O_RDONLY);
+       prevlocal = open(prevfile.buf, O_RDONLY);
        if (prevlocal != -1) {
                do {
                        prev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);
@@ -2305,7 +2308,8 @@ struct http_object_request *new_http_object_request(const char *base_url,
                } while (prev_read > 0);
                close(prevlocal);
        }
-       unlink_or_warn(prevfile);
+       unlink_or_warn(prevfile.buf);
+       strbuf_release(&prevfile);
 
        /*
         * Reset inflate/SHA1 if there was an error reading the previous temp
@@ -2320,7 +2324,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
                        lseek(freq->localfile, 0, SEEK_SET);
                        if (ftruncate(freq->localfile, 0) < 0) {
                                error_errno("Couldn't truncate temporary file %s",
-                                           freq->tmpfile);
+                                           freq->tmpfile.buf);
                                goto abort;
                        }
                }
@@ -2350,6 +2354,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
        return freq;
 
 abort:
+       strbuf_release(&prevfile);
        free(freq->url);
        free(freq);
        return NULL;
@@ -2377,24 +2382,24 @@ int finish_http_object_request(struct http_object_request *freq)
        if (freq->http_code == 416) {
                warning("requested range invalid; we may already have all the data.");
        } else if (freq->curl_result != CURLE_OK) {
-               if (stat(freq->tmpfile, &st) == 0)
+               if (stat(freq->tmpfile.buf, &st) == 0)
                        if (st.st_size == 0)
-                               unlink_or_warn(freq->tmpfile);
+                               unlink_or_warn(freq->tmpfile.buf);
                return -1;
        }
 
        git_inflate_end(&freq->stream);
        git_SHA1_Final(freq->real_sha1, &freq->c);
        if (freq->zret != Z_STREAM_END) {
-               unlink_or_warn(freq->tmpfile);
+               unlink_or_warn(freq->tmpfile.buf);
                return -1;
        }
        if (hashcmp(freq->sha1, freq->real_sha1)) {
-               unlink_or_warn(freq->tmpfile);
+               unlink_or_warn(freq->tmpfile.buf);
                return -1;
        }
        sha1_file_name(the_repository, &filename, freq->sha1);
-       freq->rename = finalize_object_file(freq->tmpfile, filename.buf);
+       freq->rename = finalize_object_file(freq->tmpfile.buf, filename.buf);
        strbuf_release(&filename);
 
        return freq->rename;
@@ -2402,7 +2407,7 @@ int finish_http_object_request(struct http_object_request *freq)
 
 void abort_http_object_request(struct http_object_request *freq)
 {
-       unlink_or_warn(freq->tmpfile);
+       unlink_or_warn(freq->tmpfile.buf);
 
        release_http_object_request(freq);
 }
@@ -2422,4 +2427,5 @@ void release_http_object_request(struct http_object_request *freq)
                release_active_slot(freq->slot);
                freq->slot = NULL;
        }
+       strbuf_release(&freq->tmpfile);
 }
diff --git a/http.h b/http.h
index 4df4a25e1abc232c27f1b00ba0a97b05a689db2e..d305ca1dc7a3f931a81353c56060e98f4039c692 100644 (file)
--- a/http.h
+++ b/http.h
@@ -207,7 +207,7 @@ struct http_pack_request {
        struct packed_git *target;
        struct packed_git **lst;
        FILE *packfile;
-       char tmpfile[PATH_MAX];
+       struct strbuf tmpfile;
        struct active_request_slot *slot;
 };
 
@@ -219,7 +219,7 @@ extern void release_http_pack_request(struct http_pack_request *preq);
 /* Helpers for fetching object */
 struct http_object_request {
        char *url;
-       char tmpfile[PATH_MAX];
+       struct strbuf tmpfile;
        int localfile;
        CURLcode curl_result;
        char errorstr[CURL_ERROR_SIZE];
index 724bae0de25b5b6e22dfecee233ff999be880dd5..4aef85331e0b696d0373cf1bdb0743a7e6b58c36 100644 (file)
@@ -387,11 +387,15 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
                graph_show_oneline(opt->graph);
        }
        if (opt->mime_boundary && maybe_multipart) {
-               static char subject_buffer[1024];
-               static char buffer[1024];
+               static struct strbuf subject_buffer = STRBUF_INIT;
+               static struct strbuf buffer = STRBUF_INIT;
                struct strbuf filename =  STRBUF_INIT;
                *need_8bit_cte_p = -1; /* NEVER */
-               snprintf(subject_buffer, sizeof(subject_buffer) - 1,
+
+               strbuf_reset(&subject_buffer);
+               strbuf_reset(&buffer);
+
+               strbuf_addf(&subject_buffer,
                         "%s"
                         "MIME-Version: 1.0\n"
                         "Content-Type: multipart/mixed;"
@@ -406,13 +410,13 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
                         extra_headers ? extra_headers : "",
                         mime_boundary_leader, opt->mime_boundary,
                         mime_boundary_leader, opt->mime_boundary);
-               extra_headers = subject_buffer;
+               extra_headers = subject_buffer.buf;
 
                if (opt->numbered_files)
                        strbuf_addf(&filename, "%d", opt->nr);
                else
                        fmt_output_commit(&filename, commit, opt);
-               snprintf(buffer, sizeof(buffer) - 1,
+               strbuf_addf(&buffer,
                         "\n--%s%s\n"
                         "Content-Type: text/x-patch;"
                         " name=\"%s\"\n"
@@ -423,7 +427,7 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
                         filename.buf,
                         opt->no_inline ? "attachment" : "inline",
                         filename.buf);
-               opt->diffopt.stat_sep = buffer;
+               opt->diffopt.stat_sep = buffer.buf;
                strbuf_release(&filename);
        }
        *extra_headers_p = extra_headers;
diff --git a/refs.c b/refs.c
index 20fb35d8952611527e7ade5c2e394c4bde79291b..0eb379f9312fd9f167fea2e0f148c85c47cd2ff0 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1162,8 +1162,8 @@ char *shorten_unambiguous_ref(const char *refname, int strict)
                for (i = 0; i < nr_rules; i++) {
                        assert(offset < total_len);
                        scanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + offset;
-                       offset += snprintf(scanf_fmts[i], total_len - offset,
-                                          ref_rev_parse_rules[i], 2, "%s") + 1;
+                       offset += xsnprintf(scanf_fmts[i], total_len - offset,
+                                           ref_rev_parse_rules[i], 2, "%s") + 1;
                }
        }
 
diff --git a/usage.c b/usage.c
index 9c84dccfa9719d925b23eb63247d79d5dfe4b817..cc803336bd5e6761b7fd50c33dba5aa9f734c4ba 100644 (file)
--- a/usage.c
+++ b/usage.c
@@ -148,6 +148,7 @@ static const char *fmt_with_err(char *buf, int n, const char *fmt)
                }
        }
        str_error[j] = 0;
+       /* Truncation is acceptable here */
        snprintf(buf, n, "%s: %s", fmt, str_error);
        return buf;
 }