mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Fixed int64 overflow for timestamp in v1/api parseDuration and parseTime (#2501)
* Fixed int64 overflow for timestamp in v1/api parseDuration and parseTime This led to unexpected results on wrong query with "(...)&start=148966367200.372&end=1489667272.372" That query is wrong because of `start > end` but actually internal int64 overflow caused start to be something around MinInt64 (huge negative value) and was passing validation. BTW: Not sure if negative timestamp makes sense even.. But model.Earliest is actually MinInt64, can someone explain me why? Signed-off-by: Bartek Plotka <bwplotka@gmail.com> * Added missing trailing periods on comments. Signed-off-by: Bartek Plotka <bwplotka@gmail.com> * MOved to only `<` and `>`. Removed equal. Signed-off-by: Bartek Plotka <bwplotka@gmail.com>
This commit is contained in:
parent
48d221c11e
commit
1823ae8bc4
|
@ -17,6 +17,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -477,8 +478,11 @@ func respondError(w http.ResponseWriter, apiErr *apiError, data interface{}) {
|
||||||
|
|
||||||
func parseTime(s string) (model.Time, error) {
|
func parseTime(s string) (model.Time, error) {
|
||||||
if t, err := strconv.ParseFloat(s, 64); err == nil {
|
if t, err := strconv.ParseFloat(s, 64); err == nil {
|
||||||
ts := int64(t * float64(time.Second))
|
ts := t * float64(time.Second)
|
||||||
return model.TimeFromUnixNano(ts), nil
|
if ts > float64(math.MaxInt64) || ts < float64(math.MinInt64) {
|
||||||
|
return 0, fmt.Errorf("cannot parse %q to a valid timestamp. It overflows int64", s)
|
||||||
|
}
|
||||||
|
return model.TimeFromUnixNano(int64(ts)), nil
|
||||||
}
|
}
|
||||||
if t, err := time.Parse(time.RFC3339Nano, s); err == nil {
|
if t, err := time.Parse(time.RFC3339Nano, s); err == nil {
|
||||||
return model.TimeFromUnixNano(t.UnixNano()), nil
|
return model.TimeFromUnixNano(t.UnixNano()), nil
|
||||||
|
@ -488,7 +492,11 @@ func parseTime(s string) (model.Time, error) {
|
||||||
|
|
||||||
func parseDuration(s string) (time.Duration, error) {
|
func parseDuration(s string) (time.Duration, error) {
|
||||||
if d, err := strconv.ParseFloat(s, 64); err == nil {
|
if d, err := strconv.ParseFloat(s, 64); err == nil {
|
||||||
return time.Duration(d * float64(time.Second)), nil
|
ts := d * float64(time.Second)
|
||||||
|
if ts > float64(math.MaxInt64) || ts < float64(math.MinInt64) {
|
||||||
|
return 0, fmt.Errorf("cannot parse %q to a valid duration. It overflows int64", s)
|
||||||
|
}
|
||||||
|
return time.Duration(ts), nil
|
||||||
}
|
}
|
||||||
if d, err := model.ParseDuration(s); err == nil {
|
if d, err := model.ParseDuration(s); err == nil {
|
||||||
return time.Duration(d), nil
|
return time.Duration(d), nil
|
||||||
|
|
|
@ -221,7 +221,7 @@ func TestEndpoints(t *testing.T) {
|
||||||
},
|
},
|
||||||
errType: errorBadData,
|
errType: errorBadData,
|
||||||
},
|
},
|
||||||
// Invalid step
|
// Invalid step.
|
||||||
{
|
{
|
||||||
endpoint: api.queryRange,
|
endpoint: api.queryRange,
|
||||||
query: url.Values{
|
query: url.Values{
|
||||||
|
@ -232,7 +232,7 @@ func TestEndpoints(t *testing.T) {
|
||||||
},
|
},
|
||||||
errType: errorBadData,
|
errType: errorBadData,
|
||||||
},
|
},
|
||||||
// Start after end
|
// Start after end.
|
||||||
{
|
{
|
||||||
endpoint: api.queryRange,
|
endpoint: api.queryRange,
|
||||||
query: url.Values{
|
query: url.Values{
|
||||||
|
@ -243,6 +243,17 @@ func TestEndpoints(t *testing.T) {
|
||||||
},
|
},
|
||||||
errType: errorBadData,
|
errType: errorBadData,
|
||||||
},
|
},
|
||||||
|
// Start overflows int64 internally.
|
||||||
|
{
|
||||||
|
endpoint: api.queryRange,
|
||||||
|
query: url.Values{
|
||||||
|
"query": []string{"time()"},
|
||||||
|
"start": []string{"148966367200.372"},
|
||||||
|
"end": []string{"1489667272.372"},
|
||||||
|
"step": []string{"1"},
|
||||||
|
},
|
||||||
|
errType: errorBadData,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
endpoint: api.labelValues,
|
endpoint: api.labelValues,
|
||||||
params: map[string]string{
|
params: map[string]string{
|
||||||
|
@ -593,15 +604,20 @@ func TestParseTime(t *testing.T) {
|
||||||
}, {
|
}, {
|
||||||
input: "30s",
|
input: "30s",
|
||||||
fail: true,
|
fail: true,
|
||||||
|
}, {
|
||||||
|
// Internal int64 overflow.
|
||||||
|
input: "-148966367200.372",
|
||||||
|
fail: true,
|
||||||
|
}, {
|
||||||
|
// Internal int64 overflow.
|
||||||
|
input: "148966367200.372",
|
||||||
|
fail: true,
|
||||||
}, {
|
}, {
|
||||||
input: "123",
|
input: "123",
|
||||||
result: time.Unix(123, 0),
|
result: time.Unix(123, 0),
|
||||||
}, {
|
}, {
|
||||||
input: "123.123",
|
input: "123.123",
|
||||||
result: time.Unix(123, 123000000),
|
result: time.Unix(123, 123000000),
|
||||||
}, {
|
|
||||||
input: "123.123",
|
|
||||||
result: time.Unix(123, 123000000),
|
|
||||||
}, {
|
}, {
|
||||||
input: "2015-06-03T13:21:58.555Z",
|
input: "2015-06-03T13:21:58.555Z",
|
||||||
result: ts,
|
result: ts,
|
||||||
|
@ -643,6 +659,14 @@ func TestParseDuration(t *testing.T) {
|
||||||
}, {
|
}, {
|
||||||
input: "2015-06-03T13:21:58.555Z",
|
input: "2015-06-03T13:21:58.555Z",
|
||||||
fail: true,
|
fail: true,
|
||||||
|
}, {
|
||||||
|
// Internal int64 overflow.
|
||||||
|
input: "-148966367200.372",
|
||||||
|
fail: true,
|
||||||
|
}, {
|
||||||
|
// Internal int64 overflow.
|
||||||
|
input: "148966367200.372",
|
||||||
|
fail: true,
|
||||||
}, {
|
}, {
|
||||||
input: "123",
|
input: "123",
|
||||||
result: 123 * time.Second,
|
result: 123 * time.Second,
|
||||||
|
|
Loading…
Reference in a new issue