Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'internal/httpfs/http_fs.go')
-rw-r--r--internal/httpfs/http_fs.go66
1 files changed, 59 insertions, 7 deletions
diff --git a/internal/httpfs/http_fs.go b/internal/httpfs/http_fs.go
index cd2edb83..3578352f 100644
--- a/internal/httpfs/http_fs.go
+++ b/internal/httpfs/http_fs.go
@@ -8,6 +8,7 @@ package httpfs
import (
"errors"
+ "fmt"
"net/http"
"os"
"path"
@@ -24,15 +25,28 @@ var (
// fileSystemPaths implements the http.FileSystem interface
type fileSystemPaths struct {
allowedPaths []string
+ // workaround for https://gitlab.com/gitlab-org/gitlab/-/issues/326117#note_546346101
+ // where daemon-inplace-chroot=true fails to serve zip archives when
+ // pages_serve_with_zip_file_protocol is enabled
+ // TODO: evaluate if we need to remove this field when we remove
+ // chroot https://gitlab.com/gitlab-org/gitlab-pages/-/issues/561
+ chrootPath string
}
// NewFileSystemPath creates a new fileSystemPaths that can be used to register
-// a file:// protocol with an http.Transport
-func NewFileSystemPath(allowedPaths []string) (http.FileSystem, error) {
- for k, path := range allowedPaths {
- var err error
+// a file:// protocol with an http.Transport.
+// When the daemon runs inside a chroot we need to strip chrootPath out of each
+// of the allowedPaths so that we are able to find the file correctly inside
+// the chroot. When Open is called, the same chrootPath will be stripped out of
+// the full filepath.
+func NewFileSystemPath(allowedPaths []string, chrootPath string) (http.FileSystem, error) {
+ for k, allowedPath := range allowedPaths {
+ strippedPath, err := stripChrootPath(ensureEndingSlash(allowedPath), chrootPath)
+ if err != nil {
+ return nil, err
+ }
- allowedPaths[k], err = filepath.Abs(path)
+ allowedPaths[k], err = filepath.Abs(strippedPath)
if err != nil {
return nil, err
}
@@ -40,6 +54,7 @@ func NewFileSystemPath(allowedPaths []string) (http.FileSystem, error) {
return &fileSystemPaths{
allowedPaths: allowedPaths,
+ chrootPath: chrootPath,
}, nil
}
@@ -50,12 +65,26 @@ func (p *fileSystemPaths) Open(name string) (http.File, error) {
return nil, errInvalidChar
}
- absPath, err := filepath.Abs(filepath.FromSlash(path.Clean("/" + name)))
+ cleanedPath := filepath.FromSlash(path.Clean("/" + name))
+
+ // since deamon can run in a chroot, we allow to define a chroot path that will be stripped from
+ // the FS location
+ // TODO: evaluate if we need to remove this check when we remove chroot
+ // https://gitlab.com/gitlab-org/gitlab-pages/-/issues/561
+ strippedPath, err := stripChrootPath(cleanedPath, p.chrootPath)
+ if err != nil {
+ log.WithError(err).Error(os.ErrPermission)
+
+ return nil, os.ErrPermission
+ }
+
+ absPath, err := filepath.Abs(strippedPath)
if err != nil {
return nil, err
}
for _, allowedPath := range p.allowedPaths {
- if strings.HasPrefix(absPath, allowedPath+"/") {
+ // allowedPath may be a single / in chroot so we need to ensure it's not double slash
+ if strings.HasPrefix(absPath, ensureEndingSlash(allowedPath)) {
return os.Open(absPath)
}
}
@@ -67,3 +96,26 @@ func (p *fileSystemPaths) Open(name string) (http.File, error) {
// https://github.com/golang/go/blob/release-branch.go1.15/src/net/http/fs.go#L635
return nil, os.ErrPermission
}
+
+func ensureEndingSlash(path string) string {
+ if strings.HasSuffix(path, "/") {
+ return path
+ }
+
+ return path + "/"
+}
+
+func stripChrootPath(path, chrootPath string) (string, error) {
+ if chrootPath == "" {
+ return path, nil
+ }
+
+ if !strings.HasPrefix(path, chrootPath+"/") {
+ return "", fmt.Errorf("allowed path %q is not in chroot path %q", path, chrootPath)
+ }
+
+ // path will contain a leading `/`
+ path = path[len(chrootPath):]
+
+ return path, nil
+}