local: fix panic on Range request past the end of a symlink GHSA-p6m2-r3w9-mpxw CVE-PENDING
With --links/-l, a symlink is served as a .rclonelink object whose content is the target path. A Range request with a start offset beyond the target length (e.g. "Range: bytes=99999999999-") reached openTranslatedLink and sliced the target string at that offset, panicking with "slice bounds out of range". Clamp the offset to the target length so an out-of-range start reads empty, matching how a real file read past EOF behaves.
This commit is contained in:
@@ -1423,6 +1423,13 @@ func (o *Object) openTranslatedLink(offset, limit int64) (lrc io.ReadCloser, err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Clamp offset into range to avoid panic
|
||||
if offset < 0 {
|
||||
offset = 0
|
||||
}
|
||||
if offset > int64(len(linkdst)) {
|
||||
offset = int64(len(linkdst))
|
||||
}
|
||||
return readers.NewLimitedReadCloser(io.NopCloser(strings.NewReader(linkdst[offset:])), limit), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -210,6 +211,32 @@ func TestSymlink(t *testing.T) {
|
||||
require.NoError(t, in.Close())
|
||||
}
|
||||
|
||||
// TestSymlinkRangeBeyondEnd checks range requests on a translated
|
||||
// symlink's target string don't panic.
|
||||
func TestSymlinkRangeBeyondEnd(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
r := fstest.NewRun(t)
|
||||
f := r.Flocal.(*Fs)
|
||||
linksMode(f)
|
||||
|
||||
const target = "file.txt"
|
||||
require.NoError(t, putLink(ctx, f, "symlink.txt", target))
|
||||
|
||||
o, err := f.NewObject(ctx, "symlink.txt"+fs.LinkSuffix)
|
||||
require.NoError(t, err)
|
||||
|
||||
// An offset just past the end and a wildly large offset must both read
|
||||
// empty rather than panicking.
|
||||
for _, start := range []int64{int64(len(target)), int64(len(target)) + 1, math.MaxInt64} {
|
||||
in, err := o.Open(ctx, &fs.RangeOption{Start: start, End: -1})
|
||||
require.NoError(t, err)
|
||||
contents, err := io.ReadAll(in)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, string(contents))
|
||||
require.NoError(t, in.Close())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSymlinkError(t *testing.T) {
|
||||
m := configmap.Simple{
|
||||
"links": "true",
|
||||
|
||||
Reference in New Issue
Block a user