avoid using fixed PATH_MAX buffers for refs

Many functions which handle refs use a PATH_MAX-sized buffer to do so. This is mostly reasonable as we have to write loose refs into the filesystem, and at least on Linux the 4K PATH_MAX is big enough that nobody would care. But: 1. The static PATH_MAX is not always the filesystem limit. 2. On other platforms, PATH_MAX may be much smaller. 3. As we move to alternate ref storage, we won't be bound by filesystem limits. Let's convert these to heap buffers so we don't have to worry about truncation or size limits. We may want to eventually constrain ref lengths for sanity and to prevent malicious names, but we should do so consistently across all platforms, and in a central place (like the ref code). Signed-off-by: Jeff King <peff@peff.net>

Jeff King committed Mar 28, 2017 at 15:46 UTC 7f897b6f176319ec0f490d286c3fee11187d7095
4 files changed +41 -39
builtin/checkout.c
+2 -3
@@ -908,11 +908,10 @@ static int check_tracking_name(struct remote *remote, void *cb_data)
908 static const char *unique_tracking_name(const char *name, struct object_id *oid)
909 {
910 struct tracking_name_data cb_data = { NULL, NULL, NULL, 1 };
911 - char src_ref[PATH_MAX];
912 - snprintf(src_ref, PATH_MAX, "refs/heads/%s", name);
913 - cb_data.src_ref = src_ref;
911 + cb_data.src_ref = xstrfmt("refs/heads/%s", name);
912 cb_data.dst_oid = oid;
913 for_each_remote(check_tracking_name, &cb_data);
914 + free(cb_data.src_ref);
915 if (cb_data.unique)
916 return cb_data.dst_ref;
917 free(cb_data.dst_ref);
builtin/ls-remote.c
+6 -4
@@ -17,17 +17,19 @@ static const char * const ls_remote_usage[] = {
17 static int tail_match(const char **pattern, const char *path)
18 {
19 const char *p;
20 - char pathbuf[PATH_MAX];
20 + char *pathbuf;
21
22 if (!pattern)
23 return 1; /* no restriction */
24
25 - if (snprintf(pathbuf, sizeof(pathbuf), "/%s", path) > sizeof(pathbuf))
26 - return error("insanely long ref %.*s...", 20, path);
25 + pathbuf = xstrfmt("/%s", path);
26 while ((p = *(pattern++)) != NULL) {
28 - if (!wildmatch(p, pathbuf, 0, NULL))
27 + if (!wildmatch(p, pathbuf, 0, NULL)) {
28 + free(pathbuf);
29 return 1;
30 + }
31 }
32 + free(pathbuf);
33 return 0;
34 }
35
builtin/replace.c
+27 -23
@@ -93,26 +93,31 @@ typedef int (*each_replace_name_fn)(const char *name, const char *ref,
93 static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
94 {
95 const char **p, *full_hex;
96 - char ref[PATH_MAX];
96 + struct strbuf ref = STRBUF_INIT;
97 + size_t base_len;
98 int had_error = 0;
99 struct object_id oid;
100
101 + strbuf_addstr(&ref, git_replace_ref_base);
102 + base_len = ref.len;
103 +
104 for (p = argv; *p; p++) {
105 if (get_oid(*p, &oid)) {
106 error("Failed to resolve '%s' as a valid ref.", *p);
107 had_error = 1;
108 continue;
109 }
106 - full_hex = oid_to_hex(&oid);
107 - snprintf(ref, sizeof(ref), "%s%s", git_replace_ref_base, full_hex);
108 - /* read_ref() may reuse the buffer */
109 - full_hex = ref + strlen(git_replace_ref_base);
110 - if (read_ref(ref, oid.hash)) {
110 +
111 + strbuf_setlen(&ref, base_len);
112 + strbuf_addstr(&ref, oid_to_hex(&oid));
113 + full_hex = ref.buf + base_len;
114 +
115 + if (read_ref(ref.buf, oid.hash)) {
116 error("replace ref '%s' not found.", full_hex);
117 had_error = 1;
118 continue;
119 }
115 - if (fn(full_hex, ref, &oid))
120 + if (fn(full_hex, ref.buf, &oid))
121 had_error = 1;
122 }
123 return had_error;
@@ -129,21 +134,18 @@ static int delete_replace_ref(const char *name, const char *ref,
134
135 static void check_ref_valid(struct object_id *object,
136 struct object_id *prev,
132 - char *ref,
133 - int ref_size,
137 + struct strbuf *ref,
138 int force)
139 {
136 - if (snprintf(ref, ref_size,
137 - "%s%s", git_replace_ref_base,
138 - oid_to_hex(object)) > ref_size - 1)
139 - die("replace ref name too long: %.*s...", 50, ref);
140 - if (check_refname_format(ref, 0))
141 - die("'%s' is not a valid ref name.", ref);
142 -
143 - if (read_ref(ref, prev->hash))
140 + strbuf_reset(ref);
141 + strbuf_addf(ref, "%s%s", git_replace_ref_base, oid_to_hex(object));
142 + if (check_refname_format(ref->buf, 0))
143 + die("'%s' is not a valid ref name.", ref->buf);
144 +
145 + if (read_ref(ref->buf, prev->hash))
146 oidclr(prev);
147 else if (!force)
146 - die("replace ref '%s' already exists", ref);
148 + die("replace ref '%s' already exists", ref->buf);
149 }
150
151 static int replace_object_oid(const char *object_ref,
@@ -154,7 +156,7 @@ static int replace_object_oid(const char *object_ref,
156 {
157 struct object_id prev;
158 enum object_type obj_type, repl_type;
157 - char ref[PATH_MAX];
159 + struct strbuf ref = STRBUF_INIT;
160 struct ref_transaction *transaction;
161 struct strbuf err = STRBUF_INIT;
162
@@ -167,16 +169,17 @@ static int replace_object_oid(const char *object_ref,
169 object_ref, typename(obj_type),
170 replace_ref, typename(repl_type));
171
170 - check_ref_valid(object, &prev, ref, sizeof(ref), force);
172 + check_ref_valid(object, &prev, &ref, force);
173
174 transaction = ref_transaction_begin(&err);
175 if (!transaction ||
174 - ref_transaction_update(transaction, ref, repl->hash, prev.hash,
176 + ref_transaction_update(transaction, ref.buf, repl->hash, prev.hash,
177 0, NULL, &err) ||
178 ref_transaction_commit(transaction, &err))
179 die("%s", err.buf);
180
181 ref_transaction_free(transaction);
182 + strbuf_release(&ref);
183 return 0;
184 }
185
@@ -280,7 +283,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw)
283 char *tmpfile = git_pathdup("REPLACE_EDITOBJ");
284 enum object_type type;
285 struct object_id old, new, prev;
283 - char ref[PATH_MAX];
286 + struct strbuf ref = STRBUF_INIT;
287
288 if (get_oid(object_ref, &old) < 0)
289 die("Not a valid object name: '%s'", object_ref);
@@ -289,7 +292,8 @@ static int edit_and_replace(const char *object_ref, int force, int raw)
292 if (type < 0)
293 die("unable to get object type for %s", oid_to_hex(&old));
294
292 - check_ref_valid(&old, &prev, ref, sizeof(ref), force);
295 + check_ref_valid(&old, &prev, &ref, force);
296 + strbuf_release(&ref);
297
298 export_object(&old, type, raw, tmpfile);
299 if (launch_editor(tmpfile, NULL, NULL) < 0)
builtin/tag.c
+6 -9
@@ -72,25 +72,22 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
72 const void *cb_data)
73 {
74 const char **p;
75 - char ref[PATH_MAX];
75 + struct strbuf ref = STRBUF_INIT;
76 int had_error = 0;
77 unsigned char sha1[20];
78
79 for (p = argv; *p; p++) {
80 - if (snprintf(ref, sizeof(ref), "refs/tags/%s", *p)
81 - >= sizeof(ref)) {
82 - error(_("tag name too long: %.*s..."), 50, *p);
83 - had_error = 1;
84 - continue;
85 - }
86 - if (read_ref(ref, sha1)) {
80 + strbuf_reset(&ref);
81 + strbuf_addf(&ref, "refs/tags/%s", *p);
82 + if (read_ref(ref.buf, sha1)) {
83 error(_("tag '%s' not found."), *p);
84 had_error = 1;
85 continue;
86 }
91 - if (fn(*p, ref, sha1, cb_data))
87 + if (fn(*p, ref.buf, sha1, cb_data))
88 had_error = 1;
89 }
90 + strbuf_release(&ref);
91 return had_error;
92 }
93