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

disallow reserved names #4740

Merged
merged 4 commits into from
Jul 3, 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
5 changes: 5 additions & 0 deletions changelog/unreleased/disallow-reserved-names.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Bugfix: Disallow reserved filenames

We now disallow the reserved `..` and `.` filenames. They are only allowed as destinations of move or copy operations.

https://github.com/cs3org/reva/pull/4740
4 changes: 2 additions & 2 deletions internal/http/services/owncloud/ocdav/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,14 @@ func (s *svc) handlePathCopy(w http.ResponseWriter, r *http.Request, ns string)
return
}

if err := ValidateName(path.Base(src), s.nameValidators); err != nil {
if err := ValidateName(filename(src), s.nameValidators); err != nil {
w.WriteHeader(http.StatusBadRequest)
b, err := errors.Marshal(http.StatusBadRequest, "source failed naming rules", "")
errors.HandleWebdavError(appctx.GetLogger(ctx), w, b, err)
return
}

if err := ValidateName(path.Base(dst), s.nameValidators); err != nil {
if err := ValidateDestination(filename(dst), s.nameValidators); err != nil {
w.WriteHeader(http.StatusBadRequest)
b, err := errors.Marshal(http.StatusBadRequest, "destination failed naming rules", "")
errors.HandleWebdavError(appctx.GetLogger(ctx), w, b, err)
Expand Down
4 changes: 2 additions & 2 deletions internal/http/services/owncloud/ocdav/mkcol.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ func (s *svc) handlePathMkcol(w http.ResponseWriter, r *http.Request, ns string)
ctx, span := appctx.GetTracerProvider(r.Context()).Tracer(tracerName).Start(r.Context(), "mkcol")
defer span.End()

fn := path.Join(ns, r.URL.Path)
if err := ValidateName(path.Base(fn), s.nameValidators); err != nil {
if err := ValidateName(filename(r.URL.Path), s.nameValidators); err != nil {
return http.StatusBadRequest, err
}
fn := path.Join(ns, r.URL.Path)
sublog := appctx.GetLogger(ctx).With().Str("path", fn).Logger()

client, err := s.gatewaySelector.Next()
Expand Down
4 changes: 2 additions & 2 deletions internal/http/services/owncloud/ocdav/move.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,14 @@ func (s *svc) handlePathMove(w http.ResponseWriter, r *http.Request, ns string)
return
}

if err := ValidateName(path.Base(srcPath), s.nameValidators); err != nil {
if err := ValidateName(filename(srcPath), s.nameValidators); err != nil {
w.WriteHeader(http.StatusBadRequest)
b, err := errors.Marshal(http.StatusBadRequest, "source failed naming rules", "")
errors.HandleWebdavError(appctx.GetLogger(ctx), w, b, err)
return
}

if err := ValidateName(path.Base(dstPath), s.nameValidators); err != nil {
if err := ValidateDestination(filename(dstPath), s.nameValidators); err != nil {
w.WriteHeader(http.StatusBadRequest)
b, err := errors.Marshal(http.StatusBadRequest, "destination naming rules", "")
errors.HandleWebdavError(appctx.GetLogger(ctx), w, b, err)
Expand Down
5 changes: 5 additions & 0 deletions internal/http/services/owncloud/ocdav/ocdav.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,3 +394,8 @@ func (s *svc) referenceIsChildOf(ctx context.Context, selector pool.Selectable[g
pp := path.Join(parentPathRes.Path, parent.Path) + "/"
return strings.HasPrefix(cp, pp), nil
}

// filename returns the base filename from a path and replaces any slashes with an empty string
func filename(p string) string {
return strings.Trim(path.Base(p), "/")
}
27 changes: 17 additions & 10 deletions internal/http/services/owncloud/ocdav/put.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,15 @@ func (s *svc) handlePathPut(w http.ResponseWriter, r *http.Request, ns string) {
defer span.End()

fn := path.Join(ns, r.URL.Path)

sublog := appctx.GetLogger(ctx).With().Str("path", fn).Logger()

if err := ValidateName(filename(r.URL.Path), s.nameValidators); err != nil {
w.WriteHeader(http.StatusBadRequest)
b, err := errors.Marshal(http.StatusBadRequest, err.Error(), "")
errors.HandleWebdavError(&sublog, w, b, err)
return
}

space, status, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gatewaySelector, fn)
if err != nil {
sublog.Error().Err(err).Str("path", fn).Msg("failed to look up storage space")
Expand All @@ -135,20 +142,13 @@ func (s *svc) handlePut(ctx context.Context, w http.ResponseWriter, r *http.Requ
return
}

length, err := getContentLength(w, r)
length, err := getContentLength(r)
if err != nil {
log.Error().Err(err).Msg("error getting the content length")
w.WriteHeader(http.StatusBadRequest)
return
}

if err := ValidateName(filepath.Base(ref.Path), s.nameValidators); err != nil {
w.WriteHeader(http.StatusBadRequest)
b, err := errors.Marshal(http.StatusBadRequest, err.Error(), "")
errors.HandleWebdavError(&log, w, b, err)
return
}

client, err := s.gatewaySelector.Next()
if err != nil {
log.Error().Err(err).Msg("error selecting next gateway client")
Expand Down Expand Up @@ -411,6 +411,13 @@ func (s *svc) handleSpacesPut(w http.ResponseWriter, r *http.Request, spaceID st
return
}

if err := ValidateName(filename(ref.Path), s.nameValidators); err != nil {
w.WriteHeader(http.StatusBadRequest)
b, err := errors.Marshal(http.StatusBadRequest, err.Error(), "")
errors.HandleWebdavError(&sublog, w, b, err)
return
}

s.handlePut(ctx, w, r, &ref, sublog)
}

Expand All @@ -432,7 +439,7 @@ func checkPreconditions(w http.ResponseWriter, r *http.Request, log zerolog.Logg
return true
}

func getContentLength(w http.ResponseWriter, r *http.Request) (int64, error) {
func getContentLength(r *http.Request) (int64, error) {
length, err := strconv.ParseInt(r.Header.Get(net.HeaderContentLength), 10, 64)
if err != nil {
// Fallback to Upload-Length
Expand Down
28 changes: 11 additions & 17 deletions internal/http/services/owncloud/ocdav/tus.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,15 @@ func (s *svc) handlePathTusPost(w http.ResponseWriter, r *http.Request, ns strin

// read filename from metadata
meta := tusd.ParseMetadataHeader(r.Header.Get(net.HeaderUploadMetadata))
if err := ValidateName(path.Base(meta["filename"]), s.nameValidators); err != nil {
w.WriteHeader(http.StatusPreconditionFailed)
return
}

// append filename to current dir
fn := path.Join(ns, r.URL.Path, meta["filename"])

sublog := appctx.GetLogger(ctx).With().Str("path", fn).Logger()
// check tus headers?

ref := &provider.Reference{
// FIXME ResourceId?
Path: fn,
// a path based request has no resource id, so we can only provide a path. The gateway has te figure out which provider is responsible
Path: path.Join(ns, r.URL.Path, meta["filename"]),
}

sublog := appctx.GetLogger(ctx).With().Str("path", r.URL.Path).Str("filename", meta["filename"]).Logger()

s.handleTusPost(ctx, w, r, meta, ref, sublog)
}

Expand All @@ -82,19 +76,15 @@ func (s *svc) handleSpacesTusPost(w http.ResponseWriter, r *http.Request, spaceI

// read filename from metadata
meta := tusd.ParseMetadataHeader(r.Header.Get(net.HeaderUploadMetadata))
if err := ValidateName(path.Base(meta["filename"]), s.nameValidators); err != nil {
w.WriteHeader(http.StatusPreconditionFailed)
return
}

sublog := appctx.GetLogger(ctx).With().Str("spaceid", spaceID).Str("path", r.URL.Path).Logger()

ref, err := spacelookup.MakeStorageSpaceReference(spaceID, path.Join(r.URL.Path, meta["filename"]))
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}

sublog := appctx.GetLogger(ctx).With().Str("spaceid", spaceID).Str("path", r.URL.Path).Str("filename", meta["filename"]).Logger()

s.handleTusPost(ctx, w, r, meta, &ref, sublog)
}

Expand All @@ -116,6 +106,10 @@ func (s *svc) handleTusPost(ctx context.Context, w http.ResponseWriter, r *http.
w.WriteHeader(http.StatusPreconditionFailed)
return
}
if err := ValidateName(filename(meta["filename"]), s.nameValidators); err != nil {
w.WriteHeader(http.StatusPreconditionFailed)
return
}

// Test if the target is a secret filedrop
var isSecretFileDrop bool
Expand Down
14 changes: 14 additions & 0 deletions internal/http/services/owncloud/ocdav/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ func ValidatorsFromConfig(c *config.Config) []Validator {

// ValidateName will validate a file or folder name, returning an error when it is not accepted
func ValidateName(name string, validators []Validator) error {
return ValidateDestination(name, append(validators, notReserved()))
}

// ValidateDestination will validate a file or folder destination name (which can be . or ..), returning an error when it is not accepted
func ValidateDestination(name string, validators []Validator) error {
for _, v := range validators {
if err := v(name); err != nil {
return fmt.Errorf("name validation failed: %w", err)
Expand All @@ -35,6 +40,15 @@ func ValidateName(name string, validators []Validator) error {
return nil
}

func notReserved() Validator {
return func(s string) error {
if s == ".." || s == "." {
return errors.New(". and .. are reserved names")
}
return nil
}
}

func notEmpty() Validator {
return func(s string) error {
if strings.TrimSpace(s) == "" {
Expand Down
16 changes: 16 additions & 0 deletions tests/acceptance/expected-failures-on-OCIS-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,5 +259,21 @@ _The below features have been added after I last categorized them. AFAICT they a
- [coreApiWebdavMove1/moveFolder.feature:254](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavMove1/moveFolder.feature#L254)
- [coreApiWebdavMove1/moveFolder.feature:259](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavMove1/moveFolder.feature#L259)

### [expected failures due to introduction of `..` mask](https://github.com/cs3org/reva/pull/4740)

- [coreApiWebdavProperties/createFileFolder.feature:206](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L206)
- [coreApiWebdavProperties/createFileFolder.feature:209](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L209)
- [coreApiWebdavProperties/createFileFolder.feature:210](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L210)
- [coreApiWebdavProperties/createFileFolder.feature:212](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L212)
- [coreApiWebdavProperties/createFileFolder.feature:213](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L213)
- [coreApiWebdavProperties/createFileFolder.feature:218](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L218)
- [coreApiWebdavProperties/createFileFolder.feature:220](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L220)
- [coreApiWebdavProperties/createFileFolder.feature:221](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L221)
- [coreApiWebdavProperties/createFileFolder.feature:230](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L230)
- [coreApiWebdavProperties/createFileFolder.feature:233](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L233)
- [coreApiWebdavProperties/createFileFolder.feature:234](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L234)
- [coreApiWebdavProperties/createFileFolder.feature:236](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L236)
- [coreApiWebdavProperties/createFileFolder.feature:237](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L237)

- Note: always have an empty line at the end of this file.
The bash script that processes this file may not process a scenario reference on the last line.
16 changes: 16 additions & 0 deletions tests/acceptance/expected-failures-on-POSIX-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -410,5 +410,21 @@ _The below features have been added after I last categorized them. AFAICT they a
- [coreApiWebdavMove1/moveFolder.feature:276](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavMove1/moveFolder.feature#L276)
- [coreApiWebdavMove1/moveFolder.feature:281](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavMove1/moveFolder.feature#L281)

### expected failures due to introduction of `..` mask

- [coreApiWebdavProperties/createFileFolder.feature:206](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L206)
- [coreApiWebdavProperties/createFileFolder.feature:209](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L209)
- [coreApiWebdavProperties/createFileFolder.feature:210](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L210)
- [coreApiWebdavProperties/createFileFolder.feature:212](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L212)
- [coreApiWebdavProperties/createFileFolder.feature:213](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L213)
- [coreApiWebdavProperties/createFileFolder.feature:218](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L218)
- [coreApiWebdavProperties/createFileFolder.feature:220](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L220)
- [coreApiWebdavProperties/createFileFolder.feature:221](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L221)
- [coreApiWebdavProperties/createFileFolder.feature:230](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L230)
- [coreApiWebdavProperties/createFileFolder.feature:233](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L233)
- [coreApiWebdavProperties/createFileFolder.feature:234](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L234)
- [coreApiWebdavProperties/createFileFolder.feature:236](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L236)
- [coreApiWebdavProperties/createFileFolder.feature:237](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L237)

- Note: always have an empty line at the end of this file.
The bash script that processes this file may not process a scenario reference on the last line.
16 changes: 16 additions & 0 deletions tests/acceptance/expected-failures-on-S3NG-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,5 +262,21 @@ _The below features have been added after I last categorized them. AFAICT they a
- [coreApiWebdavMove1/moveFolder.feature:254](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavMove1/moveFolder.feature#L254)
- [coreApiWebdavMove1/moveFolder.feature:259](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavMove1/moveFolder.feature#L259)

### [create file folder issues resulting from masked `..`](https://github.com/cs3org/reva/pull/4740)

- [coreApiWebdavProperties/createFileFolder.feature:206](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L206)
- [coreApiWebdavProperties/createFileFolder.feature:209](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L209)
- [coreApiWebdavProperties/createFileFolder.feature:210](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L210)
- [coreApiWebdavProperties/createFileFolder.feature:212](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L212)
- [coreApiWebdavProperties/createFileFolder.feature:213](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L213)
- [coreApiWebdavProperties/createFileFolder.feature:218](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L218)
- [coreApiWebdavProperties/createFileFolder.feature:220](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L220)
- [coreApiWebdavProperties/createFileFolder.feature:221](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L221)
- [coreApiWebdavProperties/createFileFolder.feature:230](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L230)
- [coreApiWebdavProperties/createFileFolder.feature:233](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L233)
- [coreApiWebdavProperties/createFileFolder.feature:234](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L234)
- [coreApiWebdavProperties/createFileFolder.feature:236](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L236)
- [coreApiWebdavProperties/createFileFolder.feature:237](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L237)

Note: always have an empty line at the end of this file.
The bash script that processes this file may not process a scenario reference on the last line.
Loading