Skip to content

Commit 0b6ec07

Browse files
peffgitster
authored andcommitted
fsck: assert newline presence in fsck_ident()
The fsck code purports to handle buffers that are not NUL-terminated, but fsck_ident() uses some string functions. This works OK in practice, as explained in 8e43090 (fsck: do not assume NUL-termination of buffers, 2023-01-19). Before calling fsck_ident() we'll have called verify_headers(), which makes sure we have at least a trailing newline. And none of our string-like functions will walk past that newline. However, that makes this code at the top of fsck_ident() very confusing: *ident = strchrnul(*ident, '\n'); if (**ident == '\n') (*ident)++; We should always see that newline, or our memory safety assumptions have been violated! Further, using strchrnul() is weird, since the whole point is that if the newline is not there, we don't necessarily have a NUL at all, and might read off the end of the buffer. So let's have callers pass in the boundary of our buffer, which lets us safely find the newline with memchr(). And if it is not there, this is a BUG(), because it means our caller did not validate the input with verify_headers() as it was supposed to (and we are better off bailing rather than having memory-safety problems). Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent c4c9089 commit 0b6ec07

File tree

1 file changed

+9
-7
lines changed

1 file changed

+9
-7
lines changed

fsck.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -859,16 +859,18 @@ static int verify_headers(const void *data, unsigned long size,
859859
FSCK_MSG_UNTERMINATED_HEADER, "unterminated header");
860860
}
861861

862-
static int fsck_ident(const char **ident,
862+
static int fsck_ident(const char **ident, const char *ident_end,
863863
const struct object_id *oid, enum object_type type,
864864
struct fsck_options *options)
865865
{
866866
const char *p = *ident;
867+
const char *nl;
867868
char *end;
868869

869-
*ident = strchrnul(*ident, '\n');
870-
if (**ident == '\n')
871-
(*ident)++;
870+
nl = memchr(p, '\n', ident_end - p);
871+
if (!nl)
872+
BUG("verify_headers() should have made sure we have a newline");
873+
*ident = nl + 1;
872874

873875
if (*p == '<')
874876
return report(options, oid, type, FSCK_MSG_MISSING_NAME_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
@@ -957,7 +959,7 @@ static int fsck_commit(const struct object_id *oid,
957959
author_count = 0;
958960
while (buffer < buffer_end && skip_prefix(buffer, "author ", &buffer)) {
959961
author_count++;
960-
err = fsck_ident(&buffer, oid, OBJ_COMMIT, options);
962+
err = fsck_ident(&buffer, buffer_end, oid, OBJ_COMMIT, options);
961963
if (err)
962964
return err;
963965
}
@@ -969,7 +971,7 @@ static int fsck_commit(const struct object_id *oid,
969971
return err;
970972
if (buffer >= buffer_end || !skip_prefix(buffer, "committer ", &buffer))
971973
return report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_COMMITTER, "invalid format - expected 'committer' line");
972-
err = fsck_ident(&buffer, oid, OBJ_COMMIT, options);
974+
err = fsck_ident(&buffer, buffer_end, oid, OBJ_COMMIT, options);
973975
if (err)
974976
return err;
975977
if (memchr(buffer_begin, '\0', size)) {
@@ -1064,7 +1066,7 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
10641066
goto done;
10651067
}
10661068
else
1067-
ret = fsck_ident(&buffer, oid, OBJ_TAG, options);
1069+
ret = fsck_ident(&buffer, buffer_end, oid, OBJ_TAG, options);
10681070

10691071
if (buffer < buffer_end && !starts_with(buffer, "\n")) {
10701072
/*

0 commit comments

Comments
 (0)