fsck: detect and warn a commit with embedded NUL

Even though a Git commit object is designed to be capable of storing any binary data as its payload, in practice people use it to describe the changes in textual form, and tools like "git log" are designed to treat the payload as text. Detect and warn when we see any commit object with a NUL byte in it. Note that a NUL byte in the header part is already detected as a grave error. This change is purely about the message part. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Apr 14, 2016 at 10:58 UTC 6d2d780f6359df424a625a51f09da80ab6dc1ef8
2 files changed +26
fsck.c
+8
@@ -59,6 +59,7 @@
59 FUNC(HAS_DOTGIT, WARN) \
60 FUNC(NULL_SHA1, WARN) \
61 FUNC(ZERO_PADDED_FILEMODE, WARN) \
62 + FUNC(NUL_IN_COMMIT, WARN) \
63 /* infos (reported as warnings, but ignored by default) */ \
64 FUNC(BAD_TAG_NAME, INFO) \
65 FUNC(MISSING_TAGGER_ENTRY, INFO)
@@ -610,6 +611,7 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer,
611 struct commit_graft *graft;
612 unsigned parent_count, parent_line_count = 0, author_count;
613 int err;
614 + const char *buffer_begin = buffer;
615
616 if (verify_headers(buffer, size, &commit->object, options))
617 return -1;
@@ -671,6 +673,12 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer,
673 if (err)
674 return err;
675 }
676 + if (memchr(buffer_begin, '\0', size)) {
677 + err = report(options, &commit->object, FSCK_MSG_NUL_IN_COMMIT,
678 + "NUL byte in the commit object body");
679 + if (err)
680 + return err;
681 + }
682 return 0;
683 }
684
t/t1450-fsck.sh
+18
@@ -427,6 +427,24 @@ test_expect_success 'fsck allows .Ňit' '
427 )
428 '
429
430 +test_expect_success 'NUL in commit' '
431 + rm -fr nul-in-commit &&
432 + git init nul-in-commit &&
433 + (
434 + cd nul-in-commit &&
435 + git commit --allow-empty -m "initial commitQNUL after message" &&
436 + git cat-file commit HEAD >original &&
437 + q_to_nul <original >munged &&
438 + git hash-object -w -t commit --stdin <munged >name &&
439 + git branch bad $(cat name) &&
440 +
441 + test_must_fail git -c fsck.nulInCommit=error fsck 2>warn.1 &&
442 + grep nulInCommit warn.1 &&
443 + git fsck 2>warn.2 &&
444 + grep nulInCommit warn.2
445 + )
446 +'
447 +
448 # create a static test repo which is broken by omitting
449 # one particular object ($1, which is looked up via rev-parse
450 # in the new repository).