security: reject WebDAV virtual-root mutation
This commit is contained in:
@@ -981,6 +981,9 @@ func (f *webdavStorageFS) Create(ctx context.Context, name string, body io.ReadC
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
if isVirtualStorageRoot(f.store, p) {
|
||||||
|
return nil, false, virtualRootMutationError()
|
||||||
|
}
|
||||||
_, statErr := f.store.Stat(p)
|
_, statErr := f.store.Stat(p)
|
||||||
if statErr != nil && !os.IsNotExist(statErr) {
|
if statErr != nil && !os.IsNotExist(statErr) {
|
||||||
return nil, false, statErr
|
return nil, false, statErr
|
||||||
@@ -1002,13 +1005,26 @@ func (f *webdavStorageFS) Create(ctx context.Context, name string, body io.ReadC
|
|||||||
return fi, true, err
|
return fi, true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isVirtualStorageRoot(store storage.Storage, p string) bool {
|
||||||
|
m, ok := store.(storage.Multi)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_, rel, found := m.FindRoot(p)
|
||||||
|
return found && rel == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func virtualRootMutationError() error {
|
||||||
|
return webdav.NewHTTPError(http.StatusForbidden, fmt.Errorf("cannot modify virtual root"))
|
||||||
|
}
|
||||||
|
|
||||||
func (f *webdavStorageFS) RemoveAll(ctx context.Context, name string, opts *webdav.RemoveAllOptions) error {
|
func (f *webdavStorageFS) RemoveAll(ctx context.Context, name string, opts *webdav.RemoveAllOptions) error {
|
||||||
p, err := davSafePath(name)
|
p, err := davSafePath(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if p == "" {
|
if p == "" || isVirtualStorageRoot(f.store, p) {
|
||||||
return fmt.Errorf("cannot remove storage root")
|
return virtualRootMutationError()
|
||||||
}
|
}
|
||||||
if _, err := f.store.Stat(p); err != nil {
|
if _, err := f.store.Stat(p); err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
@@ -1038,8 +1054,8 @@ func (f *webdavStorageFS) Mkdir(ctx context.Context, name string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if p == "" {
|
if p == "" || isVirtualStorageRoot(f.store, p) {
|
||||||
return fmt.Errorf("cannot create storage root")
|
return virtualRootMutationError()
|
||||||
}
|
}
|
||||||
if _, err := f.store.Stat(p); err == nil {
|
if _, err := f.store.Stat(p); err == nil {
|
||||||
return webdav.NewHTTPError(http.StatusMethodNotAllowed, fmt.Errorf("resource already exists"))
|
return webdav.NewHTTPError(http.StatusMethodNotAllowed, fmt.Errorf("resource already exists"))
|
||||||
@@ -1061,6 +1077,9 @@ func (f *webdavStorageFS) Copy(ctx context.Context, name, dest string, opts *web
|
|||||||
if sameOrDescendantPath(src, dst) {
|
if sameOrDescendantPath(src, dst) {
|
||||||
return false, webdav.NewHTTPError(http.StatusConflict, fmt.Errorf("destination is inside source"))
|
return false, webdav.NewHTTPError(http.StatusConflict, fmt.Errorf("destination is inside source"))
|
||||||
}
|
}
|
||||||
|
if isVirtualStorageRoot(f.store, src) || isVirtualStorageRoot(f.store, dst) {
|
||||||
|
return false, virtualRootMutationError()
|
||||||
|
}
|
||||||
_, dstErr := f.store.Stat(dst)
|
_, dstErr := f.store.Stat(dst)
|
||||||
dstExists := dstErr == nil
|
dstExists := dstErr == nil
|
||||||
if dstErr != nil && !os.IsNotExist(dstErr) {
|
if dstErr != nil && !os.IsNotExist(dstErr) {
|
||||||
@@ -1130,6 +1149,9 @@ func (f *webdavStorageFS) Move(ctx context.Context, name, dest string, opts *web
|
|||||||
if sameOrDescendantPath(src, dst) {
|
if sameOrDescendantPath(src, dst) {
|
||||||
return false, webdav.NewHTTPError(http.StatusConflict, fmt.Errorf("destination is inside source"))
|
return false, webdav.NewHTTPError(http.StatusConflict, fmt.Errorf("destination is inside source"))
|
||||||
}
|
}
|
||||||
|
if isVirtualStorageRoot(f.store, src) || isVirtualStorageRoot(f.store, dst) {
|
||||||
|
return false, virtualRootMutationError()
|
||||||
|
}
|
||||||
if _, err := f.store.Stat(dst); err == nil {
|
if _, err := f.store.Stat(dst); err == nil {
|
||||||
// CHFS v4 MOVE does not overwrite an existing destination, even when
|
// CHFS v4 MOVE does not overwrite an existing destination, even when
|
||||||
// Overwrite is omitted/T and the caller has delete permission.
|
// Overwrite is omitted/T and the caller has delete permission.
|
||||||
|
|||||||
Reference in New Issue
Block a user