On 15/09/15 16:36, Jeff King wrote: > We sometimes sprintf into static buffers when we know that > the size of the buffer is large enough to fit the input > (either because it's a constant, or because it's numeric > input that is bounded in size). Likewise with strcpy of > constant strings. > > However, these sites make it hard to audit sprintf and > strcpy calls for buffer overflows, as a reader has to > cross-reference the size of the array with the input. Let's > use xsnprintf instead, which communicates to a reader that > we don't expect this to overflow (and catches the mistake in > case we do). > > Signed-off-by: Jeff King <peff@xxxxxxxx> > --- > These are all pretty trivial; the obvious thing to get wrong is that > "sizeof(buf)" is not the correct length if "buf" is a pointer. I > considered a macro wrapper like: > > #define xsnprintf_array(dst, fmt, ...) \ > xsnprintf(dst, sizeof(dst) + BARF_UNLESS_AN_ARRAY(dst), \ > fmt, __VA_ARGS__) > > but obviously that requires variadic macro support. > > archive-tar.c | 2 +- > builtin/gc.c | 2 +- > builtin/init-db.c | 11 ++++++----- > builtin/ls-tree.c | 9 +++++---- > builtin/merge-index.c | 2 +- > builtin/merge-recursive.c | 2 +- > builtin/read-tree.c | 2 +- > builtin/unpack-file.c | 2 +- > compat/mingw.c | 8 +++++--- > compat/winansi.c | 2 +- > connect.c | 2 +- > convert.c | 3 ++- > daemon.c | 4 ++-- > diff.c | 12 ++++++------ > http-push.c | 2 +- > http.c | 6 +++--- > ll-merge.c | 12 ++++++------ > refs.c | 8 ++++---- > sideband.c | 4 ++-- > strbuf.c | 4 ++-- > 20 files changed, 52 insertions(+), 47 deletions(-) > > diff --git a/archive-tar.c b/archive-tar.c > index b6b30bb..d543f93 100644 > --- a/archive-tar.c > +++ b/archive-tar.c > @@ -301,7 +301,7 @@ static int write_global_extended_header(struct archiver_args *args) > memset(&header, 0, sizeof(header)); > *header.typeflag = TYPEFLAG_GLOBAL_HEADER; > mode = 0100666; > - strcpy(header.name, "pax_global_header"); > + xsnprintf(header.name, sizeof(header.name), "pax_global_header"); How about using strlcpy() instead? Thus: - strcpy(header.name, "pax_global_header"); + strlcpy(header.name, "pax_global_header", sizeof(header.name)); Ditto for other similar (strcpy->xsnprintf) hunks below. ATB, Ramsay Jones > prepare_header(args, &header, mode, ext_header.len); > write_blocked(&header, sizeof(header)); > write_blocked(ext_header.buf, ext_header.len); > diff --git a/builtin/gc.c b/builtin/gc.c > index 0ad8d30..57584bc 100644 > --- a/builtin/gc.c > +++ b/builtin/gc.c > @@ -194,7 +194,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid) > return NULL; > > if (gethostname(my_host, sizeof(my_host))) > - strcpy(my_host, "unknown"); > + xsnprintf(my_host, sizeof(my_host), "unknown"); > > pidfile_path = git_pathdup("gc.pid"); > fd = hold_lock_file_for_update(&lock, pidfile_path, > diff --git a/builtin/init-db.c b/builtin/init-db.c > index 69323e1..e7d0e31 100644 > --- a/builtin/init-db.c > +++ b/builtin/init-db.c > @@ -262,7 +262,8 @@ static int create_default_files(const char *template_path) > } > > /* This forces creation of new config file */ > - sprintf(repo_version_string, "%d", GIT_REPO_VERSION); > + xsnprintf(repo_version_string, sizeof(repo_version_string), > + "%d", GIT_REPO_VERSION); > git_config_set("core.repositoryformatversion", repo_version_string); > > path[len] = 0; > @@ -414,13 +415,13 @@ int init_db(const char *template_dir, unsigned int flags) > */ > if (shared_repository < 0) > /* force to the mode value */ > - sprintf(buf, "0%o", -shared_repository); > + xsnprintf(buf, sizeof(buf), "0%o", -shared_repository); > else if (shared_repository == PERM_GROUP) > - sprintf(buf, "%d", OLD_PERM_GROUP); > + xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_GROUP); > else if (shared_repository == PERM_EVERYBODY) > - sprintf(buf, "%d", OLD_PERM_EVERYBODY); > + xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY); > else > - die("oops"); > + die("BUG: invalid value for shared_repository"); > git_config_set("core.sharedrepository", buf); > git_config_set("receive.denyNonFastforwards", "true"); > } > diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c > index 3b04a0f..0e30d86 100644 > --- a/builtin/ls-tree.c > +++ b/builtin/ls-tree.c > @@ -96,12 +96,13 @@ static int show_tree(const unsigned char *sha1, struct strbuf *base, > if (!strcmp(type, blob_type)) { > unsigned long size; > if (sha1_object_info(sha1, &size) == OBJ_BAD) > - strcpy(size_text, "BAD"); > + xsnprintf(size_text, sizeof(size_text), > + "BAD"); > else > - snprintf(size_text, sizeof(size_text), > - "%lu", size); > + xsnprintf(size_text, sizeof(size_text), > + "%lu", size); > } else > - strcpy(size_text, "-"); > + xsnprintf(size_text, sizeof(size_text), "-"); > printf("%06o %s %s %7s\t", mode, type, > find_unique_abbrev(sha1, abbrev), > size_text); > diff --git a/builtin/merge-index.c b/builtin/merge-index.c > index 1a1eafa..1d66111 100644 > --- a/builtin/merge-index.c > +++ b/builtin/merge-index.c > @@ -23,7 +23,7 @@ static int merge_entry(int pos, const char *path) > break; > found++; > strcpy(hexbuf[stage], sha1_to_hex(ce->sha1)); > - sprintf(ownbuf[stage], "%o", ce->ce_mode); > + xsnprintf(ownbuf[stage], sizeof(ownbuf[stage]), "%o", ce->ce_mode); > arguments[stage] = hexbuf[stage]; > arguments[stage + 4] = ownbuf[stage]; > } while (++pos < active_nr); > diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c > index a90f28f..491efd5 100644 > --- a/builtin/merge-recursive.c > +++ b/builtin/merge-recursive.c > @@ -14,7 +14,7 @@ static const char *better_branch_name(const char *branch) > > if (strlen(branch) != 40) > return branch; > - sprintf(githead_env, "GITHEAD_%s", branch); > + xsnprintf(githead_env, sizeof(githead_env), "GITHEAD_%s", branch); > name = getenv(githead_env); > return name ? name : branch; > } > diff --git a/builtin/read-tree.c b/builtin/read-tree.c > index 2379e11..8c693e7 100644 > --- a/builtin/read-tree.c > +++ b/builtin/read-tree.c > @@ -90,7 +90,7 @@ static int debug_merge(const struct cache_entry * const *stages, > debug_stage("index", stages[0], o); > for (i = 1; i <= o->merge_size; i++) { > char buf[24]; > - sprintf(buf, "ent#%d", i); > + xsnprintf(buf, sizeof(buf), "ent#%d", i); > debug_stage(buf, stages[i], o); > } > return 0; > diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c > index 1920029..6fc6bcd 100644 > --- a/builtin/unpack-file.c > +++ b/builtin/unpack-file.c > @@ -12,7 +12,7 @@ static char *create_temp_file(unsigned char *sha1) > if (!buf || type != OBJ_BLOB) > die("unable to read blob object %s", sha1_to_hex(sha1)); > > - strcpy(path, ".merge_file_XXXXXX"); > + xsnprintf(path, sizeof(path), ".merge_file_XXXXXX"); > fd = xmkstemp(path); > if (write_in_full(fd, buf, size) != size) > die_errno("unable to write temp-file"); > diff --git a/compat/mingw.c b/compat/mingw.c > index f74da23..a168800 100644 > --- a/compat/mingw.c > +++ b/compat/mingw.c > @@ -2133,9 +2133,11 @@ int uname(struct utsname *buf) > { > DWORD v = GetVersion(); > memset(buf, 0, sizeof(*buf)); > - strcpy(buf->sysname, "Windows"); > - sprintf(buf->release, "%u.%u", v & 0xff, (v >> 8) & 0xff); > + xsnprintf(buf->sysname, sizeof(buf->sysname), "Windows"); > + xsnprintf(buf->release, sizeof(buf->release), > + "%u.%u", v & 0xff, (v >> 8) & 0xff); > /* assuming NT variants only.. */ > - sprintf(buf->version, "%u", (v >> 16) & 0x7fff); > + xsnprintf(buf->version, sizeof(buf->version), > + "%u", (v >> 16) & 0x7fff); > return 0; > } > diff --git a/compat/winansi.c b/compat/winansi.c > index efc5bb3..ceff55b 100644 > --- a/compat/winansi.c > +++ b/compat/winansi.c > @@ -539,7 +539,7 @@ void winansi_init(void) > return; > > /* create a named pipe to communicate with the console thread */ > - sprintf(name, "\\\\.\\pipe\\winansi%lu", GetCurrentProcessId()); > + xsnprintf(name, sizeof(name), "\\\\.\\pipe\\winansi%lu", GetCurrentProcessId()); > hwrite = CreateNamedPipe(name, PIPE_ACCESS_OUTBOUND, > PIPE_TYPE_BYTE | PIPE_WAIT, 1, BUFFER_SIZE, 0, 0, NULL); > if (hwrite == INVALID_HANDLE_VALUE) > diff --git a/connect.c b/connect.c > index c0144d8..1d5c5e0 100644 > --- a/connect.c > +++ b/connect.c > @@ -332,7 +332,7 @@ static const char *ai_name(const struct addrinfo *ai) > static char addr[NI_MAXHOST]; > if (getnameinfo(ai->ai_addr, ai->ai_addrlen, addr, sizeof(addr), NULL, 0, > NI_NUMERICHOST) != 0) > - strcpy(addr, "(unknown)"); > + xsnprintf(addr, sizeof(addr), "(unknown)"); > > return addr; > } > diff --git a/convert.c b/convert.c > index f3bd3e9..814e814 100644 > --- a/convert.c > +++ b/convert.c > @@ -1289,7 +1289,8 @@ static struct stream_filter *ident_filter(const unsigned char *sha1) > { > struct ident_filter *ident = xmalloc(sizeof(*ident)); > > - sprintf(ident->ident, ": %s $", sha1_to_hex(sha1)); > + xsnprintf(ident->ident, sizeof(ident->ident), > + ": %s $", sha1_to_hex(sha1)); > strbuf_init(&ident->left, 0); > ident->filter.vtbl = &ident_vtbl; > ident->state = 0; > diff --git a/daemon.c b/daemon.c > index f9eb296..5218a3f 100644 > --- a/daemon.c > +++ b/daemon.c > @@ -901,7 +901,7 @@ static const char *ip2str(int family, struct sockaddr *sin, socklen_t len) > inet_ntop(family, &((struct sockaddr_in*)sin)->sin_addr, ip, len); > break; > default: > - strcpy(ip, "<unknown>"); > + xsnprintf(ip, sizeof(ip), "<unknown>"); > } > return ip; > } > @@ -916,7 +916,7 @@ static int setup_named_sock(char *listen_addr, int listen_port, struct socketlis > int gai; > long flags; > > - sprintf(pbuf, "%d", listen_port); > + xsnprintf(pbuf, sizeof(pbuf), "%d", listen_port); > memset(&hints, 0, sizeof(hints)); > hints.ai_family = AF_UNSPEC; > hints.ai_socktype = SOCK_STREAM; > diff --git a/diff.c b/diff.c > index 08508f6..788e371 100644 > --- a/diff.c > +++ b/diff.c > @@ -2880,7 +2880,7 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp, > temp->name = get_tempfile_path(&temp->tempfile); > strcpy(temp->hex, sha1_to_hex(sha1)); > temp->hex[40] = 0; > - sprintf(temp->mode, "%06o", mode); > + xsnprintf(temp->mode, sizeof(temp->mode), "%06o", mode); > strbuf_release(&buf); > strbuf_release(&template); > free(path_dup); > @@ -2897,8 +2897,8 @@ static struct diff_tempfile *prepare_temp_file(const char *name, > * a '+' entry produces this for file-1. > */ > temp->name = "/dev/null"; > - strcpy(temp->hex, "."); > - strcpy(temp->mode, "."); > + xsnprintf(temp->hex, sizeof(temp->hex), "."); > + xsnprintf(temp->mode, sizeof(temp->mode), "."); > return temp; > } > > @@ -2935,7 +2935,7 @@ static struct diff_tempfile *prepare_temp_file(const char *name, > * !(one->sha1_valid), as long as > * DIFF_FILE_VALID(one). > */ > - sprintf(temp->mode, "%06o", one->mode); > + xsnprintf(temp->mode, sizeof(temp->mode), "%06o", one->mode); > } > return temp; > } > @@ -4081,9 +4081,9 @@ const char *diff_unique_abbrev(const unsigned char *sha1, int len) > if (abblen < 37) { > static char hex[41]; > if (len < abblen && abblen <= len + 2) > - sprintf(hex, "%s%.*s", abbrev, len+3-abblen, ".."); > + xsnprintf(hex, sizeof(hex), "%s%.*s", abbrev, len+3-abblen, ".."); > else > - sprintf(hex, "%s...", abbrev); > + xsnprintf(hex, sizeof(hex), "%s...", abbrev); > return hex; > } > return sha1_to_hex(sha1); > diff --git a/http-push.c b/http-push.c > index c98dad2..154e67b 100644 > --- a/http-push.c > +++ b/http-push.c > @@ -881,7 +881,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout) > strbuf_addf(&out_buffer.buf, LOCK_REQUEST, escaped); > free(escaped); > > - sprintf(timeout_header, "Timeout: Second-%ld", timeout); > + xsnprintf(timeout_header, sizeof(timeout_header), "Timeout: Second-%ld", timeout); > dav_headers = curl_slist_append(dav_headers, timeout_header); > dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml"); > > diff --git a/http.c b/http.c > index 9dce380..7b02259 100644 > --- a/http.c > +++ b/http.c > @@ -1104,7 +1104,7 @@ static void write_accept_language(struct strbuf *buf) > decimal_places++, max_q *= 10) > ; > > - sprintf(q_format, ";q=0.%%0%dd", decimal_places); > + xsnprintf(q_format, sizeof(q_format), ";q=0.%%0%dd", decimal_places); > > strbuf_addstr(buf, "Accept-Language: "); > > @@ -1601,7 +1601,7 @@ struct http_pack_request *new_http_pack_request( > fprintf(stderr, > "Resuming fetch of pack %s at byte %ld\n", > sha1_to_hex(target->sha1), prev_posn); > - sprintf(range, "Range: bytes=%ld-", prev_posn); > + xsnprintf(range, sizeof(range), "Range: bytes=%ld-", prev_posn); > preq->range_header = curl_slist_append(NULL, range); > curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER, > preq->range_header); > @@ -1761,7 +1761,7 @@ struct http_object_request *new_http_object_request(const char *base_url, > fprintf(stderr, > "Resuming fetch of object %s at byte %ld\n", > hex, prev_posn); > - sprintf(range, "Range: bytes=%ld-", prev_posn); > + xsnprintf(range, sizeof(range), "Range: bytes=%ld-", prev_posn); > range_header = curl_slist_append(range_header, range); > curl_easy_setopt(freq->slot->curl, > CURLOPT_HTTPHEADER, range_header); > diff --git a/ll-merge.c b/ll-merge.c > index fc3c049..56f73b3 100644 > --- a/ll-merge.c > +++ b/ll-merge.c > @@ -142,11 +142,11 @@ static struct ll_merge_driver ll_merge_drv[] = { > { "union", "built-in union merge", ll_union_merge }, > }; > > -static void create_temp(mmfile_t *src, char *path) > +static void create_temp(mmfile_t *src, char *path, size_t len) > { > int fd; > > - strcpy(path, ".merge_file_XXXXXX"); > + xsnprintf(path, len, ".merge_file_XXXXXX"); > fd = xmkstemp(path); > if (write_in_full(fd, src->ptr, src->size) != src->size) > die_errno("unable to write temp-file"); > @@ -187,10 +187,10 @@ static int ll_ext_merge(const struct ll_merge_driver *fn, > > result->ptr = NULL; > result->size = 0; > - create_temp(orig, temp[0]); > - create_temp(src1, temp[1]); > - create_temp(src2, temp[2]); > - sprintf(temp[3], "%d", marker_size); > + create_temp(orig, temp[0], sizeof(temp[0])); > + create_temp(src1, temp[1], sizeof(temp[1])); > + create_temp(src2, temp[2], sizeof(temp[2])); > + xsnprintf(temp[3], sizeof(temp[3]), "%d", marker_size); > > strbuf_expand(&cmd, fn->cmdline, strbuf_expand_dict_cb, &dict); > > diff --git a/refs.c b/refs.c > index 4e15f60..d5c8b2f 100644 > --- a/refs.c > +++ b/refs.c > @@ -3326,10 +3326,10 @@ static int log_ref_write_fd(int fd, const unsigned char *old_sha1, > msglen = msg ? strlen(msg) : 0; > maxlen = strlen(committer) + msglen + 100; > logrec = xmalloc(maxlen); > - len = sprintf(logrec, "%s %s %s\n", > - sha1_to_hex(old_sha1), > - sha1_to_hex(new_sha1), > - committer); > + len = xsnprintf(logrec, maxlen, "%s %s %s\n", > + sha1_to_hex(old_sha1), > + sha1_to_hex(new_sha1), > + committer); > if (msglen) > len += copy_msg(logrec + len - 1, msg) - 1; > > diff --git a/sideband.c b/sideband.c > index 7f9dc22..fde8adc 100644 > --- a/sideband.c > +++ b/sideband.c > @@ -137,11 +137,11 @@ ssize_t send_sideband(int fd, int band, const char *data, ssize_t sz, int packet > if (packet_max - 5 < n) > n = packet_max - 5; > if (0 <= band) { > - sprintf(hdr, "%04x", n + 5); > + xsnprintf(hdr, sizeof(hdr), "%04x", n + 5); > hdr[4] = band; > write_or_die(fd, hdr, 5); > } else { > - sprintf(hdr, "%04x", n + 4); > + xsnprintf(hdr, sizeof(hdr), "%04x", n + 4); > write_or_die(fd, hdr, 4); > } > write_or_die(fd, p, n); > diff --git a/strbuf.c b/strbuf.c > index 6c1b577..46a3d20 100644 > --- a/strbuf.c > +++ b/strbuf.c > @@ -245,8 +245,8 @@ void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size > static char prefix2[2]; > > if (prefix1[0] != comment_line_char) { > - sprintf(prefix1, "%c ", comment_line_char); > - sprintf(prefix2, "%c", comment_line_char); > + xsnprintf(prefix1, sizeof(prefix1), "%c ", comment_line_char); > + xsnprintf(prefix2, sizeof(prefix2), "%c", comment_line_char); > } > add_lines(out, prefix1, prefix2, buf, size); > } -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html