mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-08-16 12:16:36 +00:00
* s3: validate indirect filer path inputs * s3: avoid query parsing on common request path * filer: scope copy/move source against JWT AllowedPrefixes maybeCheckJwtAuthorization only checked r.URL.Path, but copy and move read their source from the cp.from / mv.from query params. A prefix-restricted token could copy or move data out of a subtree it cannot otherwise reach. Check every path the request touches, reusing pathHasComponentPrefix so `..` in the source is collapsed before the prefix match. * s3: confine iceberg CreateTable location to the catalog bucket CreateTable derived the metadata bucket and path from the client-supplied req.Location / req.Name and wrote there directly, so a caller scoped to one table bucket could place metadata in another bucket (and path.Join collapsed any `..`). Require the parsed bucket to equal the request's catalog bucket and reject traversal segments in the table path. * webdav: clean client path before subFolder confinement wrappedFs concatenated subFolder + name before the underlying FileSystem ran path.Clean, so `..` in the request path or COPY/MOVE Destination resolved across the FilerRootPath confinement boundary. Clean the name as a rooted path first so traversal segments collapse below subFolder. Only the non-default -filer.path (non-empty subFolder) setup was affected. * filer: enforce read-only rule on real write path with destination header The x-seaweedfs-destination header overrides the path used for storage-rule matching while the entry is written at r.URL.Path, letting a caller select a writable rule for a read-only target. When the header is present, also check the read-only/quota rule against the actual write path.
25 lines
579 B
Go
25 lines
579 B
Go
package weed_server
|
|
|
|
import "testing"
|
|
|
|
func TestWrappedFsConfine(t *testing.T) {
|
|
w := wrappedFs{subFolder: "/confined"}
|
|
tests := []struct {
|
|
name string
|
|
want string
|
|
}{
|
|
{"/a/b", "/confined/a/b"},
|
|
{"a/b", "/confined/a/b"},
|
|
{"/", "/confined/"},
|
|
{"/../etc/passwd", "/confined/etc/passwd"},
|
|
{"/a/../../etc", "/confined/etc"},
|
|
{"/a/./b", "/confined/a/b"},
|
|
{"/a//b", "/confined/a/b"},
|
|
}
|
|
for _, tt := range tests {
|
|
if got := w.confine(tt.name); got != tt.want {
|
|
t.Errorf("confine(%q) = %q, want %q (must stay under subFolder)", tt.name, got, tt.want)
|
|
}
|
|
}
|
|
}
|