Skip to content
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

Bugfix: S3 accessor was unable to handle 416 byte range error. #3547

Merged
merged 1 commit into from
Jun 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion accessors/ext4/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func GetExt4Cache(scope vfilter.Scope,
lru_size := vql_subsystem.GetIntFromRow(
scope, scope, constants.NTFS_CACHE_SIZE)

paged_reader, err := readers.NewPagedReader(
paged_reader, err := readers.NewAccessorReader(
scope, accessor, device, int(lru_size))

cache_ctx, err = ext4.GetEXT4Context(paged_reader)
Expand Down
2 changes: 1 addition & 1 deletion accessors/fat/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func GetFATCache(scope vfilter.Scope,
lru_size := vql_subsystem.GetIntFromRow(
scope, scope, constants.NTFS_CACHE_SIZE)

paged_reader, err := readers.NewPagedReader(
paged_reader, err := readers.NewAccessorReader(
scope, accessor, device, int(lru_size))

cache_ctx, err = fat.GetFATContext(paged_reader)
Expand Down
2 changes: 1 addition & 1 deletion accessors/ntfs/readers/ntfs_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func (self *NTFSCachedContext) Start(

lru_size := vql_subsystem.GetIntFromRow(
self.scope, self.scope, constants.NTFS_CACHE_SIZE)
self.paged_reader, err = readers.NewPagedReader(
self.paged_reader, err = readers.NewAccessorReader(
self.scope, self.accessor, self.device, int(lru_size))

if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion accessors/raw_registry/raw_registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ func getRegHive(scope vfilter.Scope,
return nil, err
}

paged_reader, err := readers.NewPagedReader(
paged_reader, err := readers.NewAccessorReader(
scope, pathspec.DelegateAccessor, delegate, int(lru_size))
if err != nil {
scope.Log("%v: did you provide a URL or Pathspec?", err)
Expand Down
10 changes: 10 additions & 0 deletions accessors/s3/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ package s3

import (
"context"
"errors"
"fmt"
"io"

"github.com/aws/aws-sdk-go-v2/aws"
awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http"
"github.com/aws/aws-sdk-go-v2/feature/s3/manager"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
Expand All @@ -30,6 +33,13 @@ func (self *S3Reader) Read(buff []byte) (int, error) {
manager.NewWriteAtBuffer(buff), req)

if err != nil {
var re *awshttp.ResponseError
if errors.As(err, &re) {
if re.HTTPStatusCode() == 416 {
return 0, io.EOF
}
}

return 0, err
}
self.offset += n
Expand Down
3 changes: 1 addition & 2 deletions accessors/s3/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
ntfs "www.velocidex.com/golang/go-ntfs/parser"
"www.velocidex.com/golang/velociraptor/accessors"
"www.velocidex.com/golang/velociraptor/acls"
"www.velocidex.com/golang/velociraptor/utils"
Expand Down Expand Up @@ -201,7 +200,7 @@ func (self RawS3SystemAccessor) OpenWithOSPath(

// Wrap the reader in an in memory cache so we do not have many
// small reads from the network.
paged_reader, err := ntfs.NewPagedReader(
paged_reader, err := utils.NewPagedReader(
utils.MakeReaderAtter(reader), 1024*1024, 20)
return utils.NewReadSeekReaderAdapter(paged_reader), err
}
Expand Down
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ require (
www.velocidex.com/golang/go-prefetch v0.0.0-20220801101854-338dbe61982a
www.velocidex.com/golang/oleparse v0.0.0-20230217092320-383a0121aafe
www.velocidex.com/golang/regparser v0.0.0-20240404115756-2169ac0e3c09
www.velocidex.com/golang/vfilter v0.0.0-20240605081519-e681962fca60
www.velocidex.com/golang/vfilter v0.0.0-20240608150317-307fc598a311
)

require (
Expand All @@ -109,6 +109,7 @@ require (
github.com/Masterminds/sprig/v3 v3.2.2
github.com/Velocidex/file-rotatelogs v0.0.0-20211221020724-d12e4dae4e11
github.com/Velocidex/go-ewf v0.0.0-20240210123447-97dc81b7d8c3
github.com/Velocidex/go-ext4 v0.0.0-20240608083317-8dd00855b069
github.com/Velocidex/go-fat v0.0.0-20230923165230-3e6c4265297a
github.com/Velocidex/go-vhdx v0.0.0-20240601014259-b204818c95fd
github.com/Velocidex/grok v0.0.1
Expand Down Expand Up @@ -163,11 +164,11 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.1 // indirect
github.com/PuerkitoBio/goquery v1.8.1 // indirect
github.com/Velocidex/go-ext4 v0.0.0-20240608083317-8dd00855b069 // indirect
github.com/alecthomas/colour v0.1.0 // indirect
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/aws/aws-sdk-go v1.53.19 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.2 // indirect
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-sdk-go v1.53.19 h1:WEuWc918RXlIaPCyU11F7hH9H1ItK+8m2c/uoQNRUok=
github.com/aws/aws-sdk-go v1.53.19/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go-v2 v1.25.2 h1:/uiG1avJRgLGiQM9X3qJM8+Qa6KRGK5rRPuXE0HUM+w=
github.com/aws/aws-sdk-go-v2 v1.25.2/go.mod h1:Evoc5AsmtveRt1komDwIsjHFyrP5tDuF1D1U+6z6pNo=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 h1:gTK2uhtAPtFcdRRJilZPx8uJLL2J85xK11nKtWL0wfU=
Expand Down Expand Up @@ -1362,7 +1364,7 @@ www.velocidex.com/golang/oleparse v0.0.0-20230217092320-383a0121aafe h1:o9jQWSwK
www.velocidex.com/golang/oleparse v0.0.0-20230217092320-383a0121aafe/go.mod h1:R7IisRzDO7q5LVRJsCQf1xA50LrIavsPWzAjVE4THyY=
www.velocidex.com/golang/regparser v0.0.0-20240404115756-2169ac0e3c09 h1:G1RWYBXP2lSzxKcrAU1YhiUlBetZ7hGIzIiWuuazvfo=
www.velocidex.com/golang/regparser v0.0.0-20240404115756-2169ac0e3c09/go.mod h1:pxSECT5mWM3goJ4sxB4HCJNKnKqiAlpyT8XnvBwkLGU=
www.velocidex.com/golang/vfilter v0.0.0-20240605081519-e681962fca60 h1:r+PPvW2n4AgLEO9Awo19Q4dmqDMKTQgNXbWezKZ+5fA=
www.velocidex.com/golang/vfilter v0.0.0-20240605081519-e681962fca60/go.mod h1:P50KPQr2LpWVAu7ilGH8CBLBASGtOJ2971yA9YhR8rY=
www.velocidex.com/golang/vfilter v0.0.0-20240608150317-307fc598a311 h1:IujLDZmLQ/cMraqK2gXcvvbwe6GJqpmCABjMwFXNqI4=
www.velocidex.com/golang/vfilter v0.0.0-20240608150317-307fc598a311/go.mod h1:P50KPQr2LpWVAu7ilGH8CBLBASGtOJ2971yA9YhR8rY=
www.velocidex.com/golang/vtypes v0.0.0-20240123105603-069d4a7f435c h1:rL/It+Ig+mvIhmy9vl5gg5b6CX2J12x0v2SXIT2RoWE=
www.velocidex.com/golang/vtypes v0.0.0-20240123105603-069d4a7f435c/go.mod h1:tjaJNlBWbvH4cEMrEu678CFR2hrtcdyPINIpRxrOh4U=
230 changes: 230 additions & 0 deletions utils/lru.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
// Based on
// https://github.com/hashicorp/golang-lru/blob/master/simplelru/lru.go
// but more optimized for speed: by changing keys to int mapaccess is
// much faster. We also added locking to the LRU to make it thread
// safe.

package utils

import (
"container/list"
"errors"
"fmt"
"sync"
)

// EvictCallback is used to get a callback when a cache entry is evicted
type EvictCallback func(key int, value interface{})

// LRU implements a thread safe fixed size LRU cache
type LRU struct {
size int
evictList *list.List
items map[int]*list.Element
onEvict EvictCallback

mu sync.Mutex

name string
hits int64
miss int64
total int64
}

// entry is used to hold a value in the evictList
type entry struct {
key int
value interface{}
}

// NewLRU constructs an LRU of the given size
func NewLRU(size int, onEvict EvictCallback, name string) (*LRU, error) {
if size <= 0 {
return nil, errors.New("Must provide a positive size")
}
c := &LRU{
size: size,
evictList: list.New(),
items: make(map[int]*list.Element),
onEvict: onEvict,
name: name,
}
return c, nil
}

// Purge is used to completely clear the cache.
func (self *LRU) Purge() {
self.mu.Lock()
defer self.mu.Unlock()

for k, v := range self.items {
if self.onEvict != nil {
self.onEvict(k, v.Value.(*entry).value)
}
delete(self.items, k)
}
self.evictList.Init()
}

// Add adds a value to the cache. Returns true if an eviction occurred.
func (self *LRU) Add(key int, value interface{}) (evicted bool) {
self.mu.Lock()
defer self.mu.Unlock()

self.total++

// Check for existing item
if ent, ok := self.items[key]; ok {
self.evictList.MoveToFront(ent)
ent.Value.(*entry).value = value
return false
}

// Add new item
ent := &entry{key, value}
entry := self.evictList.PushFront(ent)
self.items[key] = entry

evict := self.evictList.Len() > self.size
// Verify size not exceeded
if evict {
self.removeOldest()
}
return evict
}

func (self *LRU) Touch(key int) {
self.mu.Lock()
defer self.mu.Unlock()

if ent, ok := self.items[key]; ok {
self.evictList.MoveToFront(ent)
}
}

// Get looks up a key's value from the cache.
func (self *LRU) Get(key int) (value interface{}, ok bool) {
self.mu.Lock()
defer self.mu.Unlock()

if ent, ok := self.items[key]; ok {
self.evictList.MoveToFront(ent)
self.hits++
return ent.Value.(*entry).value, true
}
self.miss++
return
}

// Contains checks if a key is in the cache, without updating the recent-ness
// or deleting it for being stale.
func (self *LRU) Contains(key int) (ok bool) {
self.mu.Lock()
defer self.mu.Unlock()

_, ok = self.items[key]
return ok
}

// Peek returns the key value (or undefined if not found) without updating
// the "recently used"-ness of the key.
func (self *LRU) Peek(key int) (value interface{}, ok bool) {
self.mu.Lock()
defer self.mu.Unlock()

var ent *list.Element
if ent, ok = self.items[key]; ok {
return ent.Value.(*entry).value, true
}
return nil, ok
}

// Remove removes the provided key from the cache, returning if the
// key was contained.
func (self *LRU) Remove(key int) (present bool) {
self.mu.Lock()
defer self.mu.Unlock()

if ent, ok := self.items[key]; ok {
self.removeElement(ent)
return true
}
return false
}

// RemoveOldest removes the oldest item from the cache.
func (self *LRU) RemoveOldest() (key int, value interface{}, ok bool) {
self.mu.Lock()
defer self.mu.Unlock()

ent := self.evictList.Back()
if ent != nil {
self.removeElement(ent)
kv := ent.Value.(*entry)
return kv.key, kv.value, true
}
return 0, nil, false
}

// GetOldest returns the oldest entry
func (self *LRU) GetOldest() (key int, value interface{}, ok bool) {
self.mu.Lock()
defer self.mu.Unlock()

ent := self.evictList.Back()
if ent != nil {
kv := ent.Value.(*entry)
return kv.key, kv.value, true
}
return 0, nil, false
}

// Keys returns a slice of the keys in the cache, from oldest to newest.
func (self *LRU) Keys() []int {
self.mu.Lock()
defer self.mu.Unlock()

keys := make([]int, len(self.items))
i := 0
for ent := self.evictList.Back(); ent != nil; ent = ent.Prev() {
keys[i] = ent.Value.(*entry).key
i++
}
return keys
}

// Len returns the number of items in the cache.
func (self *LRU) Len() int {
self.mu.Lock()
defer self.mu.Unlock()

return self.evictList.Len()
}

func (self *LRU) DebugString() string {
self.mu.Lock()
defer self.mu.Unlock()

return fmt.Sprintf("%s LRU %p hit %d miss %d - total %v (%f)\n",
self.name, self,
self.hits, self.miss, self.total,
float64(self.hits)/float64(self.miss))
}

// removeOldest removes the oldest item from the cache.
func (self *LRU) removeOldest() {
ent := self.evictList.Back()
if ent != nil {
self.removeElement(ent)
}
}

// removeElement is used to remove a given list element from the cache
func (self *LRU) removeElement(e *list.Element) {
self.evictList.Remove(e)
kv := e.Value.(*entry)
delete(self.items, kv.key)
if self.onEvict != nil {
self.onEvict(kv.key, kv.value)
}
}
Loading
Loading