write_untracked_extension: use FLEX_ALLOC helper

We perform unchecked additions when computing the size of a "struct ondisk_untracked_cache". This is unlikely to have an integer overflow in practice, but we'd like to avoid this dangerous pattern to make further audits easier. Note that there's one subtlety here, though. We protect ourselves against a NULL exclude_per_dir entry in our source, and avoid calling strlen() on it, keeping "len" at 0. But later, we unconditionally memcpy "len + 1" bytes to get the trailing NUL byte. If we did have a NULL exclude_per_dir, we would read from bogus memory. As it turns out, though, we always create this field pointing to a string literal, so there's no bug. We can just get rid of the pointless extra conditional. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Feb 22, 2016 at 17:44 UTC e0b837351084c3cb52c5acaf8a505835e631744a
1 file changed +4 -5
dir.c
+4 -5
@@ -2324,16 +2324,15 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra
2324 struct ondisk_untracked_cache *ouc;
2325 struct write_data wd;
2326 unsigned char varbuf[16];
2327 - int len = 0, varint_len;
2328 - if (untracked->exclude_per_dir)
2329 - len = strlen(untracked->exclude_per_dir);
2330 - ouc = xmalloc(sizeof(*ouc) + len + 1);
2327 + int varint_len;
2328 + size_t len = strlen(untracked->exclude_per_dir);
2329 +
2330 + FLEX_ALLOC_MEM(ouc, exclude_per_dir, untracked->exclude_per_dir, len);
2331 stat_data_to_disk(&ouc->info_exclude_stat, &untracked->ss_info_exclude.stat);
2332 stat_data_to_disk(&ouc->excludes_file_stat, &untracked->ss_excludes_file.stat);
2333 hashcpy(ouc->info_exclude_sha1, untracked->ss_info_exclude.sha1);
2334 hashcpy(ouc->excludes_file_sha1, untracked->ss_excludes_file.sha1);
2335 ouc->dir_flags = htonl(untracked->dir_flags);
2336 - memcpy(ouc->exclude_per_dir, untracked->exclude_per_dir, len + 1);
2336
2337 varint_len = encode_varint(untracked->ident.len, varbuf);
2338 strbuf_add(out, varbuf, varint_len);