aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2022-03-14 23:18:27 +0800
committerGitHub <noreply@github.com>2022-03-14 16:18:27 +0100
commit49db87a035a28cd8eaa4abdd5832f952ca6449d9 (patch)
tree231676f5ca713844297cc16a52700fc50c8712fb
parent3ad6cf20695ea4e56e00427c6af76efc25e9b670 (diff)
downloadgitea-49db87a035a28cd8eaa4abdd5832f952ca6449d9.tar.gz
gitea-49db87a035a28cd8eaa4abdd5832f952ca6449d9.zip
Fix lfs bug (#19072)
* Fix lfs bug
-rw-r--r--modules/storage/local.go23
-rw-r--r--modules/storage/local_test.go45
-rw-r--r--routers/web/repo/lfs.go13
3 files changed, 81 insertions, 0 deletions
diff --git a/modules/storage/local.go b/modules/storage/local.go
index 022e6186d4..8d9aa603d0 100644
--- a/modules/storage/local.go
+++ b/modules/storage/local.go
@@ -6,15 +6,20 @@ package storage
import (
"context"
+ "errors"
"io"
"net/url"
"os"
+ "path"
"path/filepath"
+ "strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
)
+// ErrLocalPathNotSupported represents an error that path is not supported
+var ErrLocalPathNotSupported = errors.New("local path is not supported")
var _ ObjectStorage = &LocalStorage{}
// LocalStorageType is the type descriptor for local storage
@@ -59,11 +64,18 @@ func NewLocalStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
// Open a file
func (l *LocalStorage) Open(path string) (Object, error) {
+ if !isLocalPathValid(path) {
+ return nil, ErrLocalPathNotSupported
+ }
return os.Open(filepath.Join(l.dir, path))
}
// Save a file
func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error) {
+ if !isLocalPathValid(path) {
+ return 0, ErrLocalPathNotSupported
+ }
+
p := filepath.Join(l.dir, path)
if err := os.MkdirAll(filepath.Dir(p), os.ModePerm); err != nil {
return 0, err
@@ -107,8 +119,19 @@ func (l *LocalStorage) Stat(path string) (os.FileInfo, error) {
return os.Stat(filepath.Join(l.dir, path))
}
+func isLocalPathValid(p string) bool {
+ a := path.Clean(p)
+ if strings.HasPrefix(a, "../") || strings.HasPrefix(a, "..\\") {
+ return false
+ }
+ return a == p
+}
+
// Delete delete a file
func (l *LocalStorage) Delete(path string) error {
+ if !isLocalPathValid(path) {
+ return ErrLocalPathNotSupported
+ }
p := filepath.Join(l.dir, path)
return util.Remove(p)
}
diff --git a/modules/storage/local_test.go b/modules/storage/local_test.go
new file mode 100644
index 0000000000..8714f37f0d
--- /dev/null
+++ b/modules/storage/local_test.go
@@ -0,0 +1,45 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package storage
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestLocalPathIsValid(t *testing.T) {
+ kases := []struct {
+ path string
+ valid bool
+ }{
+ {
+ "a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
+ true,
+ },
+ {
+ "../a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
+ false,
+ },
+ {
+ "a\\0\\a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
+ true,
+ },
+ {
+ "b/../a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
+ false,
+ },
+ {
+ "..\\a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
+ false,
+ },
+ }
+
+ for _, k := range kases {
+ t.Run(k.path, func(t *testing.T) {
+ assert.EqualValues(t, k.valid, isLocalPathValid(k.path))
+ })
+ }
+}
diff --git a/routers/web/repo/lfs.go b/routers/web/repo/lfs.go
index d2d62786fe..c0f6b039d6 100644
--- a/routers/web/repo/lfs.go
+++ b/routers/web/repo/lfs.go
@@ -253,6 +253,13 @@ func LFSFileGet(ctx *context.Context) {
}
ctx.Data["LFSFilesLink"] = ctx.Repo.RepoLink + "/settings/lfs"
oid := ctx.Params("oid")
+
+ p := lfs.Pointer{Oid: oid}
+ if !p.IsValid() {
+ ctx.NotFound("LFSFileGet", nil)
+ return
+ }
+
ctx.Data["Title"] = oid
ctx.Data["PageIsSettingsLFS"] = true
meta, err := models.GetLFSMetaObjectByOid(ctx.Repo.Repository.ID, oid)
@@ -343,6 +350,12 @@ func LFSDelete(ctx *context.Context) {
return
}
oid := ctx.Params("oid")
+ p := lfs.Pointer{Oid: oid}
+ if !p.IsValid() {
+ ctx.NotFound("LFSDelete", nil)
+ return
+ }
+
count, err := models.RemoveLFSMetaObjectByOid(ctx.Repo.Repository.ID, oid)
if err != nil {
ctx.ServerError("LFSDelete", err)