From df4df5cf4847e03172dbb72ef4b778ab8cd7ad74 Mon Sep 17 00:00:00 2001 From: Mike Cohen Date: Mon, 12 Aug 2024 13:23:39 +1000 Subject: [PATCH] Bugfix: Comparisons with time object were incorrect. --- fixtures/multi_vql_queries.golden | 20 ++++++++++++++ protocols/protocol_gt.go | 19 +++++++++++++ protocols/protocol_lt.go | 46 +++++++++++++++++++++++++++++-- vfilter_test.go | 22 +++++++++++++++ 4 files changed, 104 insertions(+), 3 deletions(-) diff --git a/fixtures/multi_vql_queries.golden b/fixtures/multi_vql_queries.golden index b9bfaaf..5f07a51 100644 --- a/fixtures/multi_vql_queries.golden +++ b/fixtures/multi_vql_queries.golden @@ -1311,5 +1311,25 @@ "s.B": 2, "B": 2 } + ], + "086/000 Test timestamp comparisons: SELECT timestamp(epoch=1723428985) \u003c 1118628985, 1118628985 \u003c timestamp(epoch=1723428985), timestamp(epoch=1723428985) \u003c timestamp(epoch=1118628985), timestamp(epoch=1118628985) \u003c timestamp(epoch=1723428985), timestamp(epoch=1723428985) \u003e 1118628985, 1118628985 \u003e timestamp(epoch=1723428985), timestamp(epoch=1723428985) \u003e timestamp(epoch=1118628985), timestamp(epoch=1118628985) \u003e timestamp(epoch=1723428985), timestamp(epoch=1723428985) \u003c 1118628985.0, 1118628985.0 \u003c timestamp(epoch=1723428985), timestamp(epoch=1723428985) \u003e 1118628985.0, 1118628985.0 \u003e timestamp(epoch=1723428985), timestamp(epoch=1723428985) \u003c \"2024-08-12T02:15:25.176Z\", \"2024-08-12T02:15:25.176Z\" \u003c timestamp(epoch=1723428985), timestamp(epoch=1723428985) \u003e \"2024-08-12T02:15:25.176Z\", \"2024-08-12T02:15:25.176Z\" \u003e timestamp(epoch=1723428985) FROM scope()": [ + { + "timestamp(epoch=1723428985) \u003c 1118628985": false, + "1118628985 \u003c timestamp(epoch=1723428985)": true, + "timestamp(epoch=1723428985) \u003c timestamp(epoch=1118628985)": false, + "timestamp(epoch=1118628985) \u003c timestamp(epoch=1723428985)": true, + "timestamp(epoch=1723428985) \u003e 1118628985": true, + "1118628985 \u003e timestamp(epoch=1723428985)": false, + "timestamp(epoch=1723428985) \u003e timestamp(epoch=1118628985)": true, + "timestamp(epoch=1118628985) \u003e timestamp(epoch=1723428985)": false, + "timestamp(epoch=1723428985) \u003c 1118628985.0": false, + "1118628985.0 \u003c timestamp(epoch=1723428985)": true, + "timestamp(epoch=1723428985) \u003e 1118628985.0": true, + "1118628985.0 \u003e timestamp(epoch=1723428985)": false, + "timestamp(epoch=1723428985) \u003c \"2024-08-12T02:15:25.176Z\"": false, + "\"2024-08-12T02:15:25.176Z\" \u003c timestamp(epoch=1723428985)": false, + "timestamp(epoch=1723428985) \u003e \"2024-08-12T02:15:25.176Z\"": false, + "\"2024-08-12T02:15:25.176Z\" \u003e timestamp(epoch=1723428985)": false + } ] } \ No newline at end of file diff --git a/protocols/protocol_gt.go b/protocols/protocol_gt.go index b508195..3842304 100644 --- a/protocols/protocol_gt.go +++ b/protocols/protocol_gt.go @@ -43,6 +43,15 @@ func (self GtDispatcher) Gt(scope types.Scope, a types.Any, b types.Any) bool { return false case string: + if isTime(b) { + lhs, ok := utils.ToInt64(t) + if ok { + rhs, ok := toTime(b) + if ok { + return time.Unix(lhs, 0).After(*rhs) + } + } + } rhs, ok := b.(string) if ok { return t > rhs @@ -50,6 +59,16 @@ func (self GtDispatcher) Gt(scope types.Scope, a types.Any, b types.Any) bool { // If it is integer like, coerce to int. case int, int8, int16, int32, int64, uint8, uint16, uint32, uint64: + if isTime(b) { + lhs, ok := utils.ToInt64(t) + if ok { + rhs, ok := toTime(b) + if ok { + return time.Unix(lhs, 0).After(*rhs) + } + } + } + lhs, ok := utils.ToInt64(t) if ok { return intGt(lhs, b) diff --git a/protocols/protocol_lt.go b/protocols/protocol_lt.go index 8e1394e..1083883 100644 --- a/protocols/protocol_lt.go +++ b/protocols/protocol_lt.go @@ -1,6 +1,7 @@ package protocols import ( + "math" "time" "www.velocidex.com/golang/vfilter/types" @@ -64,13 +65,26 @@ func (self LtDispatcher) Lt(scope types.Scope, a types.Any, b types.Any) bool { return false case string: - rhs, ok := b.(string) - if ok { - return t < rhs + // Let string comparisons with time fall through to protocol + // selection. + if !isTime(b) { + rhs, ok := b.(string) + if ok { + return t < rhs + } } // If it is integer like, coerce to int. case int, int8, int16, int32, int64, uint8, uint16, uint32, uint64: + if isTime(b) { + lhs, ok := utils.ToInt64(t) + if ok { + rhs, ok := toTime(b) + if ok { + return time.Unix(lhs, 0).Before(*rhs) + } + } + } lhs, ok := utils.ToInt64(t) if ok { return intLt(lhs, b) @@ -141,13 +155,39 @@ func (self LtDispatcher) Lt(scope types.Scope, a types.Any, b types.Any) bool { return false } +func isTime(a types.Any) bool { + switch a.(type) { + case time.Time: + return true + case *time.Time: + return true + } + return false +} + func toTime(a types.Any) (*time.Time, bool) { switch t := a.(type) { case time.Time: return &t, true + case *time.Time: return t, true + + case float64: + sec_f, dec_f := math.Modf(t) + dec_f *= 1e9 + res := time.Unix(int64(sec_f), int64(dec_f)) + return &res, true + default: + // Maybe it is an int + sec, ok := utils.ToInt64(a) + if ok { + // Treat it as an epoch seconds + res := time.Unix(sec, 0) + return &res, true + } + return nil, false } } diff --git a/vfilter_test.go b/vfilter_test.go index f599cee..94fe789 100644 --- a/vfilter_test.go +++ b/vfilter_test.go @@ -1301,6 +1301,28 @@ LET Data <= (dict(A=1), dict(B=2)) LET s = scope() SELECT s.A, A, s.B, B FROM Data +`}, + // Comparing time to strings in unsupported in the base vfilter + // project, it is added with specialized handlers with + // Velociraptor. + {"Test timestamp comparisons", ` +SELECT timestamp(epoch=1723428985) < 1118628985, + 1118628985 < timestamp(epoch=1723428985), + timestamp(epoch=1723428985) < timestamp(epoch=1118628985), + timestamp(epoch=1118628985) < timestamp(epoch=1723428985), + timestamp(epoch=1723428985) > 1118628985, + 1118628985 > timestamp(epoch=1723428985), + timestamp(epoch=1723428985) > timestamp(epoch=1118628985), + timestamp(epoch=1118628985) > timestamp(epoch=1723428985), + timestamp(epoch=1723428985) < 1118628985.0, + 1118628985.0 < timestamp(epoch=1723428985), + timestamp(epoch=1723428985) > 1118628985.0, + 1118628985.0 > timestamp(epoch=1723428985), + timestamp(epoch=1723428985) < "2024-08-12T02:15:25.176Z", + "2024-08-12T02:15:25.176Z" < timestamp(epoch=1723428985), + timestamp(epoch=1723428985) > "2024-08-12T02:15:25.176Z", + "2024-08-12T02:15:25.176Z" > timestamp(epoch=1723428985) +FROM scope() `}, }