1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-05-29 22:36:11 +02:00

Merge branch 'jk/snprintf-truncation'

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
This commit is contained in:
Junio C Hamano 2018-05-30 21:51:27 +09:00
commit 7c3d15fe31
6 changed files with 55 additions and 50 deletions

View 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) static int query_fsmonitor(int version, uint64_t last_update, struct strbuf *query_result)
{ {
struct child_process cp = CHILD_PROCESS_INIT; 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; return -1;
snprintf(ver, sizeof(ver), "%d", version); argv_array_push(&cp.args, core_fsmonitor);
snprintf(date, sizeof(date), "%" PRIuMAX, (uintmax_t)last_update); argv_array_pushf(&cp.args, "%d", version);
argv[1] = ver; argv_array_pushf(&cp.args, "%" PRIuMAX, (uintmax_t)last_update);
argv[2] = date;
argv[3] = NULL;
cp.argv = argv;
cp.use_shell = 1; cp.use_shell = 1;
cp.dir = get_git_work_tree(); cp.dir = get_git_work_tree();

66
http.c
View File

@ -2083,6 +2083,7 @@ void release_http_pack_request(struct http_pack_request *preq)
preq->packfile = NULL; preq->packfile = NULL;
} }
preq->slot = NULL; preq->slot = NULL;
strbuf_release(&preq->tmpfile);
free(preq->url); free(preq->url);
free(preq); free(preq);
} }
@ -2105,19 +2106,19 @@ int finish_http_pack_request(struct http_pack_request *preq)
lst = &((*lst)->next); lst = &((*lst)->next);
*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?"); 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_push(&ip.args, "index-pack");
argv_array_pushl(&ip.args, "-o", tmp_idx, NULL); 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.git_cmd = 1;
ip.no_stdin = 1; ip.no_stdin = 1;
ip.no_stdout = 1; ip.no_stdout = 1;
if (run_command(&ip)) { if (run_command(&ip)) {
unlink(preq->tmpfile); unlink(preq->tmpfile.buf);
unlink(tmp_idx); unlink(tmp_idx);
free(tmp_idx); free(tmp_idx);
return -1; return -1;
@ -2125,7 +2126,7 @@ int finish_http_pack_request(struct http_pack_request *preq)
unlink(sha1_pack_index_name(p->sha1)); 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))) { || finalize_object_file(tmp_idx, sha1_pack_index_name(p->sha1))) {
free(tmp_idx); free(tmp_idx);
return -1; return -1;
@ -2144,6 +2145,7 @@ struct http_pack_request *new_http_pack_request(
struct http_pack_request *preq; struct http_pack_request *preq;
preq = xcalloc(1, sizeof(*preq)); preq = xcalloc(1, sizeof(*preq));
strbuf_init(&preq->tmpfile, 0);
preq->target = target; preq->target = target;
end_url_with_slash(&buf, base_url); end_url_with_slash(&buf, base_url);
@ -2151,12 +2153,11 @@ struct http_pack_request *new_http_pack_request(
sha1_to_hex(target->sha1)); sha1_to_hex(target->sha1));
preq->url = strbuf_detach(&buf, NULL); preq->url = strbuf_detach(&buf, NULL);
snprintf(preq->tmpfile, sizeof(preq->tmpfile), "%s.temp", strbuf_addf(&preq->tmpfile, "%s.temp", sha1_pack_name(target->sha1));
sha1_pack_name(target->sha1)); preq->packfile = fopen(preq->tmpfile.buf, "a");
preq->packfile = fopen(preq->tmpfile, "a");
if (!preq->packfile) { if (!preq->packfile) {
error("Unable to open local file %s for pack", error("Unable to open local file %s for pack",
preq->tmpfile); preq->tmpfile.buf);
goto abort; goto abort;
} }
@ -2183,6 +2184,7 @@ struct http_pack_request *new_http_pack_request(
return preq; return preq;
abort: abort:
strbuf_release(&preq->tmpfile);
free(preq->url); free(preq->url);
free(preq); free(preq);
return NULL; return NULL;
@ -2233,7 +2235,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
{ {
char *hex = sha1_to_hex(sha1); char *hex = sha1_to_hex(sha1);
struct strbuf filename = STRBUF_INIT; struct strbuf filename = STRBUF_INIT;
char prevfile[PATH_MAX]; struct strbuf prevfile = STRBUF_INIT;
int prevlocal; int prevlocal;
char prev_buf[PREV_BUF_SIZE]; char prev_buf[PREV_BUF_SIZE];
ssize_t prev_read = 0; 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; struct http_object_request *freq;
freq = xcalloc(1, sizeof(*freq)); freq = xcalloc(1, sizeof(*freq));
strbuf_init(&freq->tmpfile, 0);
hashcpy(freq->sha1, sha1); hashcpy(freq->sha1, sha1);
freq->localfile = -1; freq->localfile = -1;
sha1_file_name(the_repository, &filename, sha1); sha1_file_name(the_repository, &filename, sha1);
snprintf(freq->tmpfile, sizeof(freq->tmpfile), strbuf_addf(&freq->tmpfile, "%s.temp", filename.buf);
"%s.temp", filename.buf);
snprintf(prevfile, sizeof(prevfile), "%s.prev", filename.buf); strbuf_addf(&prevfile, "%s.prev", filename.buf);
unlink_or_warn(prevfile); unlink_or_warn(prevfile.buf);
rename(freq->tmpfile, prevfile); rename(freq->tmpfile.buf, prevfile.buf);
unlink_or_warn(freq->tmpfile); unlink_or_warn(freq->tmpfile.buf);
strbuf_release(&filename); strbuf_release(&filename);
if (freq->localfile != -1) if (freq->localfile != -1)
error("fd leakage in start: %d", freq->localfile); 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); O_WRONLY | O_CREAT | O_EXCL, 0666);
/* /*
* This could have failed due to the "lazy directory creation"; * This could have failed due to the "lazy directory creation";
* try to mkdir the last path component. * try to mkdir the last path component.
*/ */
if (freq->localfile < 0 && errno == ENOENT) { if (freq->localfile < 0 && errno == ENOENT) {
char *dir = strrchr(freq->tmpfile, '/'); char *dir = strrchr(freq->tmpfile.buf, '/');
if (dir) { if (dir) {
*dir = 0; *dir = 0;
mkdir(freq->tmpfile, 0777); mkdir(freq->tmpfile.buf, 0777);
*dir = '/'; *dir = '/';
} }
freq->localfile = open(freq->tmpfile, freq->localfile = open(freq->tmpfile.buf,
O_WRONLY | O_CREAT | O_EXCL, 0666); O_WRONLY | O_CREAT | O_EXCL, 0666);
} }
if (freq->localfile < 0) { 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; 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 * If a previous temp file is present, process what was already
* fetched. * fetched.
*/ */
prevlocal = open(prevfile, O_RDONLY); prevlocal = open(prevfile.buf, O_RDONLY);
if (prevlocal != -1) { if (prevlocal != -1) {
do { do {
prev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE); 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); } while (prev_read > 0);
close(prevlocal); 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 * 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); lseek(freq->localfile, 0, SEEK_SET);
if (ftruncate(freq->localfile, 0) < 0) { if (ftruncate(freq->localfile, 0) < 0) {
error_errno("Couldn't truncate temporary file %s", error_errno("Couldn't truncate temporary file %s",
freq->tmpfile); freq->tmpfile.buf);
goto abort; goto abort;
} }
} }
@ -2350,6 +2354,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
return freq; return freq;
abort: abort:
strbuf_release(&prevfile);
free(freq->url); free(freq->url);
free(freq); free(freq);
return NULL; return NULL;
@ -2377,24 +2382,24 @@ int finish_http_object_request(struct http_object_request *freq)
if (freq->http_code == 416) { if (freq->http_code == 416) {
warning("requested range invalid; we may already have all the data."); warning("requested range invalid; we may already have all the data.");
} else if (freq->curl_result != CURLE_OK) { } 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) if (st.st_size == 0)
unlink_or_warn(freq->tmpfile); unlink_or_warn(freq->tmpfile.buf);
return -1; return -1;
} }
git_inflate_end(&freq->stream); git_inflate_end(&freq->stream);
git_SHA1_Final(freq->real_sha1, &freq->c); git_SHA1_Final(freq->real_sha1, &freq->c);
if (freq->zret != Z_STREAM_END) { if (freq->zret != Z_STREAM_END) {
unlink_or_warn(freq->tmpfile); unlink_or_warn(freq->tmpfile.buf);
return -1; return -1;
} }
if (hashcmp(freq->sha1, freq->real_sha1)) { if (hashcmp(freq->sha1, freq->real_sha1)) {
unlink_or_warn(freq->tmpfile); unlink_or_warn(freq->tmpfile.buf);
return -1; return -1;
} }
sha1_file_name(the_repository, &filename, freq->sha1); 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); strbuf_release(&filename);
return freq->rename; 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) 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); release_http_object_request(freq);
} }
@ -2422,4 +2427,5 @@ void release_http_object_request(struct http_object_request *freq)
release_active_slot(freq->slot); release_active_slot(freq->slot);
freq->slot = NULL; freq->slot = NULL;
} }
strbuf_release(&freq->tmpfile);
} }

4
http.h
View File

@ -207,7 +207,7 @@ struct http_pack_request {
struct packed_git *target; struct packed_git *target;
struct packed_git **lst; struct packed_git **lst;
FILE *packfile; FILE *packfile;
char tmpfile[PATH_MAX]; struct strbuf tmpfile;
struct active_request_slot *slot; struct active_request_slot *slot;
}; };
@ -219,7 +219,7 @@ extern void release_http_pack_request(struct http_pack_request *preq);
/* Helpers for fetching object */ /* Helpers for fetching object */
struct http_object_request { struct http_object_request {
char *url; char *url;
char tmpfile[PATH_MAX]; struct strbuf tmpfile;
int localfile; int localfile;
CURLcode curl_result; CURLcode curl_result;
char errorstr[CURL_ERROR_SIZE]; char errorstr[CURL_ERROR_SIZE];

View File

@ -387,11 +387,15 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
graph_show_oneline(opt->graph); graph_show_oneline(opt->graph);
} }
if (opt->mime_boundary && maybe_multipart) { if (opt->mime_boundary && maybe_multipart) {
static char subject_buffer[1024]; static struct strbuf subject_buffer = STRBUF_INIT;
static char buffer[1024]; static struct strbuf buffer = STRBUF_INIT;
struct strbuf filename = STRBUF_INIT; struct strbuf filename = STRBUF_INIT;
*need_8bit_cte_p = -1; /* NEVER */ *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" "%s"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: multipart/mixed;" "Content-Type: multipart/mixed;"
@ -406,13 +410,13 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
extra_headers ? extra_headers : "", extra_headers ? extra_headers : "",
mime_boundary_leader, opt->mime_boundary, mime_boundary_leader, opt->mime_boundary,
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) if (opt->numbered_files)
strbuf_addf(&filename, "%d", opt->nr); strbuf_addf(&filename, "%d", opt->nr);
else else
fmt_output_commit(&filename, commit, opt); fmt_output_commit(&filename, commit, opt);
snprintf(buffer, sizeof(buffer) - 1, strbuf_addf(&buffer,
"\n--%s%s\n" "\n--%s%s\n"
"Content-Type: text/x-patch;" "Content-Type: text/x-patch;"
" name=\"%s\"\n" " name=\"%s\"\n"
@ -423,7 +427,7 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
filename.buf, filename.buf,
opt->no_inline ? "attachment" : "inline", opt->no_inline ? "attachment" : "inline",
filename.buf); filename.buf);
opt->diffopt.stat_sep = buffer; opt->diffopt.stat_sep = buffer.buf;
strbuf_release(&filename); strbuf_release(&filename);
} }
*extra_headers_p = extra_headers; *extra_headers_p = extra_headers;

4
refs.c
View File

@ -1162,8 +1162,8 @@ char *shorten_unambiguous_ref(const char *refname, int strict)
for (i = 0; i < nr_rules; i++) { for (i = 0; i < nr_rules; i++) {
assert(offset < total_len); assert(offset < total_len);
scanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + offset; scanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + offset;
offset += snprintf(scanf_fmts[i], total_len - offset, offset += xsnprintf(scanf_fmts[i], total_len - offset,
ref_rev_parse_rules[i], 2, "%s") + 1; ref_rev_parse_rules[i], 2, "%s") + 1;
} }
} }

View File

@ -148,6 +148,7 @@ static const char *fmt_with_err(char *buf, int n, const char *fmt)
} }
} }
str_error[j] = 0; str_error[j] = 0;
/* Truncation is acceptable here */
snprintf(buf, n, "%s: %s", fmt, str_error); snprintf(buf, n, "%s: %s", fmt, str_error);
return buf; return buf;
} }