Skip to content

Commit 49db87a

Browse files
authored
Fix lfs bug (#19072)
* Fix lfs bug
1 parent 3ad6cf2 commit 49db87a

File tree

3 files changed

+81
-0
lines changed

3 files changed

+81
-0
lines changed

modules/storage/local.go

+23
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,20 @@ package storage
66

77
import (
88
"context"
9+
"errors"
910
"io"
1011
"net/url"
1112
"os"
13+
"path"
1214
"path/filepath"
15+
"strings"
1316

1417
"code.gitea.io/gitea/modules/log"
1518
"code.gitea.io/gitea/modules/util"
1619
)
1720

21+
// ErrLocalPathNotSupported represents an error that path is not supported
22+
var ErrLocalPathNotSupported = errors.New("local path is not supported")
1823
var _ ObjectStorage = &LocalStorage{}
1924

2025
// LocalStorageType is the type descriptor for local storage
@@ -59,11 +64,18 @@ func NewLocalStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
5964

6065
// Open a file
6166
func (l *LocalStorage) Open(path string) (Object, error) {
67+
if !isLocalPathValid(path) {
68+
return nil, ErrLocalPathNotSupported
69+
}
6270
return os.Open(filepath.Join(l.dir, path))
6371
}
6472

6573
// Save a file
6674
func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error) {
75+
if !isLocalPathValid(path) {
76+
return 0, ErrLocalPathNotSupported
77+
}
78+
6779
p := filepath.Join(l.dir, path)
6880
if err := os.MkdirAll(filepath.Dir(p), os.ModePerm); err != nil {
6981
return 0, err
@@ -107,8 +119,19 @@ func (l *LocalStorage) Stat(path string) (os.FileInfo, error) {
107119
return os.Stat(filepath.Join(l.dir, path))
108120
}
109121

122+
func isLocalPathValid(p string) bool {
123+
a := path.Clean(p)
124+
if strings.HasPrefix(a, "../") || strings.HasPrefix(a, "..\\") {
125+
return false
126+
}
127+
return a == p
128+
}
129+
110130
// Delete delete a file
111131
func (l *LocalStorage) Delete(path string) error {
132+
if !isLocalPathValid(path) {
133+
return ErrLocalPathNotSupported
134+
}
112135
p := filepath.Join(l.dir, path)
113136
return util.Remove(p)
114137
}

modules/storage/local_test.go

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package storage
6+
7+
import (
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestLocalPathIsValid(t *testing.T) {
14+
kases := []struct {
15+
path string
16+
valid bool
17+
}{
18+
{
19+
"a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
20+
true,
21+
},
22+
{
23+
"../a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
24+
false,
25+
},
26+
{
27+
"a\\0\\a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
28+
true,
29+
},
30+
{
31+
"b/../a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
32+
false,
33+
},
34+
{
35+
"..\\a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
36+
false,
37+
},
38+
}
39+
40+
for _, k := range kases {
41+
t.Run(k.path, func(t *testing.T) {
42+
assert.EqualValues(t, k.valid, isLocalPathValid(k.path))
43+
})
44+
}
45+
}

routers/web/repo/lfs.go

+13
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,13 @@ func LFSFileGet(ctx *context.Context) {
253253
}
254254
ctx.Data["LFSFilesLink"] = ctx.Repo.RepoLink + "/settings/lfs"
255255
oid := ctx.Params("oid")
256+
257+
p := lfs.Pointer{Oid: oid}
258+
if !p.IsValid() {
259+
ctx.NotFound("LFSFileGet", nil)
260+
return
261+
}
262+
256263
ctx.Data["Title"] = oid
257264
ctx.Data["PageIsSettingsLFS"] = true
258265
meta, err := models.GetLFSMetaObjectByOid(ctx.Repo.Repository.ID, oid)
@@ -343,6 +350,12 @@ func LFSDelete(ctx *context.Context) {
343350
return
344351
}
345352
oid := ctx.Params("oid")
353+
p := lfs.Pointer{Oid: oid}
354+
if !p.IsValid() {
355+
ctx.NotFound("LFSDelete", nil)
356+
return
357+
}
358+
346359
count, err := models.RemoveLFSMetaObjectByOid(ctx.Repo.Repository.ID, oid)
347360
if err != nil {
348361
ctx.ServerError("LFSDelete", err)

0 commit comments

Comments
 (0)