Compare commits

...

8 Commits

Author SHA1 Message Date
Joe Chen
012a1ba19e release: update version to 0.12.9 2022-06-07 21:29:32 +08:00
Joe Chen
a24b22c909 http: clean request path from Git endpoints (#7022) 2022-06-07 21:26:15 +08:00
Joe Chen
20923a8829 pathutil: check both styles of os.PathSeparator (#7020) 2022-06-07 21:25:51 +08:00
E99p1ant
4c02b480dc issues: sanitize DisplayName (#7009)
* issues: display issue poster’s `Name` instead of `DisplayName`

* sanitize display name

* update changelog
2022-06-07 21:24:56 +08:00
Joe Chen
deeb3f73e4 repo_editor: check both styles of os.PathSeparator in all systems (#7005)
# Conflicts:
#	CHANGELOG.md
2022-06-07 21:24:37 +08:00
Joe Chen
1bc379f4d4 pull: ignore PR status check if head repository is missing (#7004)
# Conflicts:
#	internal/db/pull.go
2022-06-07 21:23:38 +08:00
Joe Chen
8e8b185ea1 http: fix non-sense NotFound call (#7003) 2022-06-07 21:21:29 +08:00
Joe Chen
42ad18a245 repo: remove hard-coded branch name in init (#6999) 2022-06-07 21:20:54 +08:00
10 changed files with 125 additions and 50 deletions

View File

@@ -22,10 +22,13 @@ All notable changes to Gogs are documented in this file.
### Fixed
- _Security:_ XSS in cookies. [#6953](https://github.com/gogs/gogs/issues/6953)
- _Security:_ OS Command Injection in file uploading. [#6968](https://github.com/gogs/gogs/issues/6968)
- _Security:_ Remote Command Execution in file editing. [#6555](https://github.com/gogs/gogs/issues/6555)
- _Security:_ OS Command Injection in file editor. [#7000](https://github.com/gogs/gogs/issues/7000)
- _Security:_ Sanitize `DisplayName` in repository issue list. [#7009](https://github.com/gogs/gogs/pull/7009)
- _Security:_ Path Traversal in file editor on Windows. [#7001](https://github.com/gogs/gogs/issues/7001)
- _Security:_ Path Traversal in Git HTTP endpoints. [#7002](https://github.com/gogs/gogs/issues/7002)
- Unable to use LDAP authentication on ARM machines. [#6761](https://github.com/gogs/gogs/issues/6761)
- Unable to init repository during creation on Windows. [#6967](https://github.com/gogs/gogs/issues/6967)
- Mysterious panic on `Value not found for type *repo.HTTPContext`. [#6963](https://github.com/gogs/gogs/issues/6963)
### Removed
@@ -47,6 +50,19 @@ All notable changes to Gogs are documented in this file.
- Configuration option `[database] PASSWD` is no longer used, please use `[database] PASSWORD`.
- Remove option to use Makefile as the build tool. [#6980](https://github.com/gogs/gogs/pull/6980)
## 0.12.8
### Changed
- All users (including admins) need to use the configuration option `[security] LOCAL_NETWORK_ALLOWLIST` to allow repository migration and webhooks to be able to access local network addresses, which is a comma separated list of hostnames. [#6988](https://github.com/gogs/gogs/pull/6988)
### Fixed
- _Security:_ SSRF in webhook. [#6901](https://github.com/gogs/gogs/issues/6901)
- _Security:_ XSS in cookies. [#6953](https://github.com/gogs/gogs/issues/6953)
- _Security:_ OS Command Injection in file uploading. [#6968](https://github.com/gogs/gogs/issues/6968)
- _Security:_ Remote Command Execution in file editing. [#6555](https://github.com/gogs/gogs/issues/6555)
## 0.12.7
### Fixed

View File

@@ -19,7 +19,7 @@ import (
)
func init() {
conf.App.Version = "0.12.8"
conf.App.Version = "0.12.9"
}
func main() {

View File

@@ -621,11 +621,6 @@ func (pr *PullRequest) UpdateCols(cols ...string) error {
// UpdatePatch generates and saves a new patch.
func (pr *PullRequest) UpdatePatch() (err error) {
if pr.HeadRepo == nil {
log.Trace("PullRequest[%d].UpdatePatch: ignored cruppted data", pr.ID)
return nil
}
headGitRepo, err := git.Open(pr.HeadRepo.RepoPath())
if err != nil {
return fmt.Errorf("open repository: %v", err)
@@ -759,6 +754,11 @@ func (prs PullRequestList) LoadAttributes() error {
func addHeadRepoTasks(prs []*PullRequest) {
for _, pr := range prs {
if pr.HeadRepo == nil {
log.Trace("addHeadRepoTasks[%d]: missing head repository", pr.ID)
continue
}
log.Trace("addHeadRepoTasks[%d]: composing new test task", pr.ID)
if err := pr.UpdatePatch(); err != nil {
log.Error("UpdatePatch: %v", err)

View File

@@ -912,7 +912,7 @@ func initRepoCommit(tmpPath string, sig *git.Signature) (err error) {
if _, stderr, err = process.ExecDir(-1,
tmpPath, fmt.Sprintf("initRepoCommit (git push): %s", tmpPath),
"git", "push", "origin", "master"); err != nil {
"git", "push"); err != nil {
return fmt.Errorf("git push: %s", stderr)
}
return nil

View File

@@ -455,10 +455,12 @@ type UploadRepoFileOptions struct {
// path of the repository.
func isRepositoryGitPath(path string) bool {
return strings.HasSuffix(path, ".git") ||
strings.Contains(path, ".git"+string(os.PathSeparator)) ||
strings.Contains(path, ".git/") ||
strings.Contains(path, `.git\`) ||
// Windows treats ".git." the same as ".git"
strings.HasSuffix(path, ".git.") ||
strings.Contains(path, ".git."+string(os.PathSeparator))
strings.Contains(path, ".git./") ||
strings.Contains(path, `.git.\`)
}
func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions) error {

View File

@@ -5,7 +5,6 @@
package db
import (
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
@@ -16,23 +15,37 @@ func Test_isRepositoryGitPath(t *testing.T) {
path string
wantVal bool
}{
{path: filepath.Join(".", ".git"), wantVal: true},
{path: filepath.Join(".", ".git", ""), wantVal: true},
{path: filepath.Join(".", ".git", "hooks", "pre-commit"), wantVal: true},
{path: filepath.Join(".git", "hooks"), wantVal: true},
{path: filepath.Join("dir", ".git"), wantVal: true},
{path: ".git", wantVal: true},
{path: "./.git", wantVal: true},
{path: ".git/hooks/pre-commit", wantVal: true},
{path: ".git/hooks", wantVal: true},
{path: "dir/.git", wantVal: true},
{path: filepath.Join(".", ".git."), wantVal: true},
{path: filepath.Join(".", ".git.", ""), wantVal: true},
{path: filepath.Join(".", ".git.", "hooks", "pre-commit"), wantVal: true},
{path: filepath.Join(".git.", "hooks"), wantVal: true},
{path: filepath.Join("dir", ".git."), wantVal: true},
{path: ".gitignore", wantVal: false},
{path: "dir/.gitkeep", wantVal: false},
{path: filepath.Join(".gitignore"), wantVal: false},
{path: filepath.Join("dir", ".gitkeep"), wantVal: false},
// Windows-specific
{path: `.git\`, wantVal: true},
{path: `.git\hooks\pre-commit`, wantVal: true},
{path: `.git\hooks`, wantVal: true},
{path: `dir\.git`, wantVal: true},
{path: `.\.git.`, wantVal: true},
{path: `.\.git.\`, wantVal: true},
{path: `.git.\hooks\pre-commit`, wantVal: true},
{path: `.git.\hooks`, wantVal: true},
{path: `dir\.git.`, wantVal: true},
{path: "./.git.", wantVal: true},
{path: "./.git./", wantVal: true},
{path: ".git./hooks/pre-commit", wantVal: true},
{path: ".git./hooks", wantVal: true},
{path: "dir/.git.", wantVal: true},
{path: `dir\.gitkeep`, wantVal: false},
}
for _, test := range tests {
t.Run("", func(t *testing.T) {
t.Run(test.path, func(t *testing.T) {
assert.Equal(t, test.wantVal, isRepositoryGitPath(test.path))
})
}

View File

@@ -9,7 +9,9 @@ import (
"strings"
)
// Clean cleans up given path and returns a relative path that goes straight down.
// Clean cleans up given path and returns a relative path that goes straight
// down to prevent path traversal.
func Clean(p string) string {
p = strings.ReplaceAll(p, `\`, "/")
return strings.Trim(path.Clean("/"+p), "/")
}

View File

@@ -12,38 +12,73 @@ import (
func TestClean(t *testing.T) {
tests := []struct {
path string
expVal string
path string
wantVal string
}{
{
path: "../../../readme.txt",
expVal: "readme.txt",
path: "../../../readme.txt",
wantVal: "readme.txt",
},
{
path: "a/../../../readme.txt",
expVal: "readme.txt",
path: "a/../../../readme.txt",
wantVal: "readme.txt",
},
{
path: "/../a/b/../c/../readme.txt",
expVal: "a/readme.txt",
path: "/../a/b/../c/../readme.txt",
wantVal: "a/readme.txt",
},
{
path: "/a/readme.txt",
expVal: "a/readme.txt",
path: "../../objects/info/..",
wantVal: "objects",
},
{
path: "/",
expVal: "",
path: "/a/readme.txt",
wantVal: "a/readme.txt",
},
{
path: "/",
wantVal: "",
},
{
path: "/a/b/c/readme.txt",
expVal: "a/b/c/readme.txt",
path: "/a/b/c/readme.txt",
wantVal: "a/b/c/readme.txt",
},
// Windows-specific
{
path: `..\..\..\readme.txt`,
wantVal: "readme.txt",
},
{
path: `a\..\..\..\readme.txt`,
wantVal: "readme.txt",
},
{
path: `\..\a\b\..\c\..\readme.txt`,
wantVal: "a/readme.txt",
},
{
path: `\a\readme.txt`,
wantVal: "a/readme.txt",
},
{
path: `..\..\..\../README.md`,
wantVal: "README.md",
},
{
path: `\`,
wantVal: "",
},
{
path: `\a\b\c\readme.txt`,
wantVal: `a/b/c/readme.txt`,
},
}
for _, test := range tests {
t.Run("", func(t *testing.T) {
assert.Equal(t, test.expVal, Clean(test.path))
t.Run(test.path, func(t *testing.T) {
assert.Equal(t, test.wantVal, Clean(test.path))
})
}
}

View File

@@ -23,6 +23,7 @@ import (
"gogs.io/gogs/internal/conf"
"gogs.io/gogs/internal/db"
"gogs.io/gogs/internal/lazyregexp"
"gogs.io/gogs/internal/pathutil"
"gogs.io/gogs/internal/tool"
)
@@ -99,7 +100,7 @@ func HTTPContexter() macaron.Handler {
!strings.Contains(action, "info/") &&
!strings.Contains(action, "HEAD") &&
!strings.Contains(action, "objects/") {
c.NotFound()
c.Error(http.StatusBadRequest, fmt.Sprintf("Unrecognized action %q", action))
return
}
@@ -402,15 +403,21 @@ func HTTP(c *HTTPContext) {
}
if route.method != c.Req.Method {
c.NotFound()
c.Error(http.StatusNotFound)
return
}
file := strings.TrimPrefix(reqPath, m[1]+"/")
dir, err := getGitRepoPath(m[1])
cleaned := pathutil.Clean(m[1])
if m[1] != "/"+cleaned {
c.Error(http.StatusBadRequest, "Request path contains suspicious characters")
return
}
file := strings.TrimPrefix(reqPath, cleaned)
dir, err := getGitRepoPath(cleaned)
if err != nil {
log.Warn("HTTP.getGitRepoPath: %v", err)
c.NotFound()
c.Error(http.StatusNotFound)
return
}
@@ -429,5 +436,5 @@ func HTTP(c *HTTPContext) {
return
}
c.NotFound()
c.Error(http.StatusNotFound)
}

View File

@@ -113,7 +113,7 @@
{{end}}
<p class="desc">
{{$.i18n.Tr "repo.issues.opened_by" $timeStr .Poster.HomeLink .Poster.DisplayName | Safe}}
{{$.i18n.Tr "repo.issues.opened_by" $timeStr .Poster.HomeLink .Poster.DisplayName | Sanitize | Safe}}
{{if .Milestone}}
<a class="milestone" href="{{$.Link}}?type={{$.ViewType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.Milestone.ID}}&assignee={{$.AssigneeID}}">
<span class="octicon octicon-milestone"></span> {{.Milestone.Name | Sanitize}}