fs/object: fix memory object out of bounds Seek

This commit is contained in:
Nick Craig-Wood 2025-02-28 17:01:00 +00:00
parent 64b3d1d539
commit ccef29bbff
2 changed files with 29 additions and 4 deletions

View File

@ -279,19 +279,26 @@ func (o *MemoryObject) SetModTime(ctx context.Context, modTime time.Time) error
// Open opens the file for read. Call Close() on the returned io.ReadCloser
func (o *MemoryObject) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadCloser, error) {
content := o.content
var offset, limit int64 = 0, -1
for _, option := range options {
switch x := option.(type) {
case *fs.RangeOption:
content = o.content[x.Start:x.End]
offset, limit = x.Decode(o.Size())
case *fs.SeekOption:
content = o.content[x.Offset:]
offset = x.Offset
default:
if option.Mandatory() {
fs.Logf(o, "Unsupported mandatory option: %v", option)
}
}
}
content := o.content
offset = max(offset, 0)
if limit < 0 {
content = content[offset:]
} else {
content = content[offset:min(offset+limit, int64(len(content)))]
}
return io.NopCloser(bytes.NewBuffer(content)), nil
}

View File

@ -110,6 +110,7 @@ func TestMemoryObject(t *testing.T) {
assert.Equal(t, newNow, o.ModTime(context.Background()))
checkOpen := func(rc io.ReadCloser, expected string) {
t.Helper()
actual, err := io.ReadAll(rc)
assert.NoError(t, err)
err = rc.Close()
@ -118,6 +119,7 @@ func TestMemoryObject(t *testing.T) {
}
checkContent := func(o fs.Object, expected string) {
t.Helper()
rc, err := o.Open(context.Background())
assert.NoError(t, err)
checkOpen(rc, expected)
@ -127,12 +129,28 @@ func TestMemoryObject(t *testing.T) {
rc, err := o.Open(context.Background(), &fs.RangeOption{Start: 1, End: 3})
assert.NoError(t, err)
checkOpen(rc, "ot")
checkOpen(rc, "ota")
rc, err = o.Open(context.Background(), &fs.RangeOption{Start: 1, End: -1})
assert.NoError(t, err)
checkOpen(rc, "otato")
rc, err = o.Open(context.Background(), &fs.RangeOption{Start: 1, End: 4096})
assert.NoError(t, err)
checkOpen(rc, "otato")
rc, err = o.Open(context.Background(), &fs.RangeOption{Start: -1, End: 4})
assert.NoError(t, err)
checkOpen(rc, "tato")
rc, err = o.Open(context.Background(), &fs.SeekOption{Offset: 3})
assert.NoError(t, err)
checkOpen(rc, "ato")
rc, err = o.Open(context.Background(), &fs.SeekOption{Offset: -100})
assert.NoError(t, err)
checkOpen(rc, "potato")
// check it fits within the buffer
newNow = now.Add(2 * time.Minute)
newContent := bytes.NewBufferString("Rutabaga")