-
Notifications
You must be signed in to change notification settings - Fork 17.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
time: better handling of overflow in time.Time #71979
Comments
Related Issues
Related Code Changes
Related Documentation (Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.) |
In #63844 it was noted that restricting to ±32767 years wasn't really acceptable |
If it isn't clear, this issue isn't about changing the range of supported instants. It's about what we do when some time package operation goes outside that range. |
Personally, I would expect to overflow to use saturation arithmetic. It's what I've observed for Do you have any suggestions for |
Maybe there should be a saturating |
Apologies for failing to provide proper credit: Thanks to @kuprumxyz for bringing the security issues in time overflow to our attention. |
Hi everyone here, and thanks to @neild for giving the credit! To clarify: I am a security researcher, and encountered this issue while auditing a blockchain project; so I've made a responsible vulnerability disclosure via [email protected]. I will describe the details of what I've encountered, and will offer my perspective, as a security researcher. In the blockchain project I am auditing I have encountered the following fragment (abstracted): // timestamp is received from the transaction input (untrusted)
timeout := time.Unix(int64(timestamp), 0)
if timeout.Before(blockTime) {
return nil, "timeout is less than the current block timestamp"
}
if timeout.After(blockTime.Add(MaxTimeoutDelta)) {
return nil, "timeout exceeds the maximum expected value"
} In the above, some transaction is received by the system, which contains the During my testing I've found some values for
Running
The crux of the problem: for a large enough timestamp, there is a phase transition: up to timestamp In the audited project it came very close to an exploit: the only factor was that there was not only Now, here is a security perspective wrt. the Golang's Time module. Functions, such as As an engineer, I fully understand that there are no systems with such lifespans (but otoh, who knows?). But, as a security researcher, here is the important point: A system should be able to handle adversarial inputs, and its functions should not violate their contracts. Any such violation can be exploited. How to fix that? Ideally, I would like to see all functions strictly adhering to their contracts. If a function accepts
I hope this is helpful, and looking forward to a more secure Golang, for everyone's benefit! |
Hi @kuprumxyz, thank you for your research into this bug. This issue is of interest to the json/v2 project (#71497) since it aims to support directly unmarshaling a JSON number containing a Unix timestamp into a The problem is that I don't think we can trivial change the internal epoch of |
I should note that @kuprumxyz's example above is exhibiting extra confusing behavior because it's triggering #56909: |
The Unix overflow issue is not quite #56909 since that one is about the Date constructor. I think we probably shouldn't fix any of those until we decide about saturation, because saturating would be an alternative and arguably better fix. |
Is there any good reason not to do saturation on any operation that can wrap the timestamp? We don't define our behavior on over/underflow (so hopefully no backwards compatibility concerns), and saturating seems strictly better than wrapping. That does leave the question of what, if anything, the time.Unix documentation should say about the acceptable input range. Perhaps we could conservatively document the Unix seconds |
The
time.Time
type has a large, but finite range. The time package does not, so far as I can determine, document what this range is.A
Time
can represent instants billions of years in the past or future. So far as I can tell, we've taken a general attitude that instants outside the probable lifespan of the human species are out of scope for the package and can be ignored.For example,
time.Unix
converts a Unix timestamp (seconds & nanoseconds since the Unix epoch) to aTime
. It documents the handling of out-of-range values only by saying:Functions such as
time.AddDate
do not document their behavior on overflow.Most programs will never encounter out-of-range dates. (If Go proves to be unexpectedly durable on geologic time scales, we can leave the problem of increasing the size of the
time.Time
seconds counter to future generations.) However, a program handling adversarial inputs (such as a very large Unix timestamp) may be induced to overflow atime.Time
, with surprising and undocumented results.We could harden the time package a bit more against overflow. Some specific functions that we might harden:
time.Unix
could either saturate or return the zero time when provided with an out-of-range value.time.Add
andtime.AddDate
could saturate rather than wrapping on overflow.time.Round
could either truncate or saturate on overflow.There might be others I'm missing.
Alternatively, we could leave the implementation alone and document what validation users should perform to adequately defend against adversarial inputs to
time.Unix
.Edit: Thanks to @kuprumxyz for bringing potential security issues in time overflow to our attention.
The text was updated successfully, but these errors were encountered: