git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3] date: detect underflow/overflow when parsing dates with timezone offset

From
darcy via GitGitGadget <gitgitgadget@gmail.com>
Date
Jun 7, 2024, 00:17 UTC
Message-ID
<pull.1726.v3.git.git.1717719428510.gitgitgadget@gmail.com>
In-Reply-To
<pull.1726.v2.git.git.1717369608923.gitgitgadget@gmail.com>
From: darcy <acednes@gmail.com>

Overriding the date of a commit to be close to "1970-01-01 00:00:00" with a large enough positive timezone for the equivelant GMT time to be before the epoch is considered valid by `parse_date_basic`. Similar behaviour occurs when using a date close to "2099-12-31 23:59:59" (the maximum date allowed by `tm_to_time_t`) with a large enough negative timezone offset.

This leads to an integer underflow or underflow respectively in the commit timestamp, which is not caught by `git-commit`, but will cause other services to fail, such as `git-fsck`, which, for the first case, reports "badDateOverflow: invalid author/committer line - date causes integer overflow".

Instead check the timezone offset and fail if the resulting time comes before the epoch "1970-01-01T00:00:00Z" or after the maximum date "2099-12-31T23:59:59Z".

Signed-off-by: Darcy Burke <acednes@gmail.com>
---
    fix: prevent date underflow when using positive timezone offset
    
    cc: Patrick Steinhardt ps@pks.im cc: Phillip Wood
    phillip.wood123@gmail.com cc: darcy acednes@gmail.com cc: Jeff King
    peff@peff.net
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1726%2Fdxrcy%2Fmaster-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1726/dxrcy/master-v3
Pull-Request: https://github.com/git/git/pull/1726
Range-diff vs v2:
 1:  db508b2f533 ! 1:  f0de3a2c543 date: detect underflow when parsing dates with positive timezone offset
     @@ Metadata
      Author: darcy <acednes@gmail.com>
      
       ## Commit message ##
     -    date: detect underflow when parsing dates with positive timezone offset
     +    date: detect underflow/overflow when parsing dates with timezone offset
      
          Overriding the date of a commit to be close to "1970-01-01 00:00:00"
     -    with a large enough timezone for the equivelant GMT time to be before
     -    the epoch is considered valid by `parse_date_basic`.
     +    with a large enough positive timezone for the equivelant GMT time to be
     +    before the epoch is considered valid by `parse_date_basic`. Similar
     +    behaviour occurs when using a date close to "2099-12-31 23:59:59" (the
     +    maximum date allowed by `tm_to_time_t`) with a large enough negative
     +    timezone offset.
      
     -    This leads to an integer underflow in the commit timestamp, which is not
     -    caught by `git-commit`, but will cause other services to fail, such as
     -    `git-fsck`, which reports "badDateOverflow: invalid author/committer
     -    line - date causes integer overflow".
     +    This leads to an integer underflow or underflow respectively in the
     +    commit timestamp, which is not caught by `git-commit`, but will cause
     +    other services to fail, such as `git-fsck`, which, for the first case,
     +    reports "badDateOverflow: invalid author/committer line - date causes
     +    integer overflow".
      
          Instead check the timezone offset and fail if the resulting time comes
     -    before the epoch, "1970-01-01T00:00:00Z", when parsing.
     +    before the epoch "1970-01-01T00:00:00Z" or after the maximum date
     +    "2099-12-31T23:59:59Z".
      
          Signed-off-by: Darcy Burke <acednes@gmail.com>
      
       ## date.c ##
     +@@ date.c: static int match_object_header_date(const char *date, timestamp_t *timestamp, in
     + 	return 0;
     + }
     + 
     ++
     ++/* timestamp of 2099-12-31T23:59:59Z, including 32 leap days */
     ++static const time_t timestamp_max = ((2100L - 1970) * 365 + 32) * 24 * 60 * 60 - 1;
     ++
     + /* Gr. strptime is crap for this; it doesn't have a way to require RFC2822
     +    (i.e. English) day/month names, and it doesn't work correctly with %z. */
     + int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset)
      @@ date.c: int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset)
       		}
       	}
     @@ date.c: int parse_date_basic(const char *date, timestamp_t *timestamp, int *offs
      -	if (!tm_gmt)
      +	if (!tm_gmt) {
      +		if (*offset > 0 && *offset * 60 > *timestamp)
     ++			return -1;
     ++		if (*offset < 0 && -*offset * 60 > timestamp_max - *timestamp)
      +			return -1;
       		*timestamp -= *offset * 60;
      +	}
     @@ date.c: int parse_date_basic(const char *date, timestamp_t *timestamp, int *offs
       
      
       ## t/t0006-date.sh ##
     -@@ t/t0006-date.sh: check_parse '2008-02-14 20:30:45 -:30' '2008-02-14 20:30:45 +0000'
     - check_parse '2008-02-14 20:30:45 -05:00' '2008-02-14 20:30:45 -0500'
     +@@ t/t0006-date.sh: check_parse '2008-02-14 20:30:45 -05:00' '2008-02-14 20:30:45 -0500'
       check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 -0500' EST5
       check_parse 'Thu, 7 Apr 2005 15:14:13 -0700' '2005-04-07 15:14:13 -0700'
     + 
      +check_parse '1970-01-01 00:00:00' '1970-01-01 00:00:00 +0000'
      +check_parse '1970-01-01 00:00:00 +00' '1970-01-01 00:00:00 +0000'
      +check_parse '1970-01-01 00:00:00 Z' '1970-01-01 00:00:00 +0000'
     @@ t/t0006-date.sh: check_parse '2008-02-14 20:30:45 -:30' '2008-02-14 20:30:45 +00
      +check_parse '1969-12-31 23:59:59 Z' bad
      +check_parse '1969-12-31 23:59:59 +11' bad
      +check_parse '1969-12-31 23:59:59 -11' bad
     - 
     ++
     ++check_parse '2099-12-31 23:59:59' '2099-12-31 23:59:59 +0000'
     ++check_parse '2099-12-31 23:59:59 +00' '2099-12-31 23:59:59 +0000'
     ++check_parse '2099-12-31 23:59:59 Z' '2099-12-31 23:59:59 +0000'
     ++check_parse '2099-12-31 23:59:59 +01' '2099-12-31 23:59:59 +0100'
     ++check_parse '2099-12-31 23:59:59 -01' bad
     ++check_parse '2099-12-31 23:59:59 -11' bad
     ++check_parse '2099-12-31 23:00:00 -01' bad
     ++check_parse '2099-12-31 22:59:59 -01' '2099-12-31 22:59:59 -0100'
     ++check_parse '2100-00-00 00:00:00' bad
     ++check_parse '2099-12-30 00:00:00 -11' '2099-12-30 00:00:00 -1100'
     ++check_parse '2100-00-00 00:00:00 +00' bad
     ++check_parse '2100-00-00 00:00:00 Z' bad
     ++check_parse '2100-00-00 00:00:00 -11' bad
     ++check_parse '2100-00-00 00:00:00 +11' bad
     ++
       check_approxidate() {
       	echo "$1 -> $2 +0000" >expect
     + 	test_expect_${3:-success} "parse approxidate ($1)" "
 date.c          | 12 +++++++++++-
 t/t0006-date.sh | 31 +++++++++++++++++++++++++++++++
 2 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/date.c b/date.c
index 7365a4ad24f..95776c8a92f 100644
--- a/date.c
+++ b/date.c
@@ -868,6 +868,10 @@ static int match_object_header_date(const char *date, timestamp_t *timestamp, in
 	return 0;
 }
 
+
+/* timestamp of 2099-12-31T23:59:59Z, including 32 leap days */
+static const time_t timestamp_max = ((2100L - 1970) * 365 + 32) * 24 * 60 * 60 - 1;
+
 /* Gr. strptime is crap for this; it doesn't have a way to require RFC2822
    (i.e. English) day/month names, and it doesn't work correctly with %z. */
 int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset)
@@ -937,8 +941,14 @@ int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset)
 		}
 	}
 
-	if (!tm_gmt)
+	if (!tm_gmt) {
+		if (*offset > 0 && *offset * 60 > *timestamp)
+			return -1;
+		if (*offset < 0 && -*offset * 60 > timestamp_max - *timestamp)
+			return -1;
 		*timestamp -= *offset * 60;
+	}
+
 	return 0; /* success */
 }
 
diff --git a/t/t0006-date.sh b/t/t0006-date.sh
index 3031256d143..e8fdf361ad4 100755
--- a/t/t0006-date.sh
+++ b/t/t0006-date.sh
@@ -117,6 +117,37 @@ check_parse '2008-02-14 20:30:45 -05:00' '2008-02-14 20:30:45 -0500'
 check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 -0500' EST5
 check_parse 'Thu, 7 Apr 2005 15:14:13 -0700' '2005-04-07 15:14:13 -0700'
 
+check_parse '1970-01-01 00:00:00' '1970-01-01 00:00:00 +0000'
+check_parse '1970-01-01 00:00:00 +00' '1970-01-01 00:00:00 +0000'
+check_parse '1970-01-01 00:00:00 Z' '1970-01-01 00:00:00 +0000'
+check_parse '1970-01-01 00:00:00 -01' '1970-01-01 00:00:00 -0100'
+check_parse '1970-01-01 00:00:00 +01' bad
+check_parse '1970-01-01 00:00:00 +11' bad
+check_parse '1970-01-01 00:59:59 +01' bad
+check_parse '1970-01-01 01:00:00 +01' '1970-01-01 01:00:00 +0100'
+check_parse '1970-01-01 01:00:00 +11' bad
+check_parse '1970-01-02 00:00:00 +11' '1970-01-02 00:00:00 +1100'
+check_parse '1969-12-31 23:59:59' bad
+check_parse '1969-12-31 23:59:59 +00' bad
+check_parse '1969-12-31 23:59:59 Z' bad
+check_parse '1969-12-31 23:59:59 +11' bad
+check_parse '1969-12-31 23:59:59 -11' bad
+
+check_parse '2099-12-31 23:59:59' '2099-12-31 23:59:59 +0000'
+check_parse '2099-12-31 23:59:59 +00' '2099-12-31 23:59:59 +0000'
+check_parse '2099-12-31 23:59:59 Z' '2099-12-31 23:59:59 +0000'
+check_parse '2099-12-31 23:59:59 +01' '2099-12-31 23:59:59 +0100'
+check_parse '2099-12-31 23:59:59 -01' bad
+check_parse '2099-12-31 23:59:59 -11' bad
+check_parse '2099-12-31 23:00:00 -01' bad
+check_parse '2099-12-31 22:59:59 -01' '2099-12-31 22:59:59 -0100'
+check_parse '2100-00-00 00:00:00' bad
+check_parse '2099-12-30 00:00:00 -11' '2099-12-30 00:00:00 -1100'
+check_parse '2100-00-00 00:00:00 +00' bad
+check_parse '2100-00-00 00:00:00 Z' bad
+check_parse '2100-00-00 00:00:00 -11' bad
+check_parse '2100-00-00 00:00:00 +11' bad
+
 check_approxidate() {
 	echo "$1 -> $2 +0000" >expect
 	test_expect_${3:-success} "parse approxidate ($1)" "

base-commit: cd77e87115eab5e80e6b161e7b84a79ba1a12cdc
-- 
gitgitgadget
Previous: darcyNext: Junio C Hamano
Message 15 of 29 in “fix: prevent date underflow when using positive timezone offset”
  1. fix: prevent date underflow when using positive timezone offsetdarcy via GitGitGadget, May 27, 2024
  2. Patrick SteinhardtMay 28, 2024
  3. Phillip WoodMay 28, 2024
  4. Junio C HamanoMay 28, 2024
  5. date: detect underflow when parsing dates with positive timezone offsetdarcy via GitGitGadget, Jun 2, 2024
  6. Junio C HamanoJun 3, 2024
  7. darcyJun 3, 2024
  8. Phillip WoodJun 3, 2024
  9. darcyJun 4, 2024
  10. Jeff KingJun 4, 2024
  11. darcyJun 5, 2024
  12. Phillip WoodJun 5, 2024
  13. Junio C HamanoJun 5, 2024
  14. darcyJun 6, 2024
  15. date: detect underflow/overflow when parsing dates with timezone offsetdarcy via GitGitGadget, Jun 7, 2024
  16. Junio C HamanoJun 7, 2024
  17. Junio C HamanoJun 8, 2024
  18. Junio C HamanoJun 14, 2024
  19. Karthik NayakJun 15, 2024
  20. Junio C HamanoJun 11, 2024
  21. rsbecker@nexbridge.comJun 11, 2024
  22. Junio C HamanoJun 11, 2024
  23. Phillip WoodJun 12, 2024
  24. Karthik NayakJun 12, 2024
  25. Phillip WoodJun 13, 2024
  26. Junio C HamanoJun 13, 2024
  27. Karthik NayakJun 14, 2024
  28. Junio C HamanoJun 14, 2024
  29. Karthik NayakJun 15, 2024

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.