mirror of
https://github.com/portainer/portainer.git
synced 2025-08-04 21:35:23 +02:00
fix(filesystem): harden the filesystem service to avoid path traversal attacks EE-1922 (#5957)
fix(filesystem): harden the filesystem service to avoid path traversal attacks EE-1922
This commit is contained in:
parent
c763219f74
commit
28f71e486a
21 changed files with 292 additions and 176 deletions
|
@ -2,7 +2,6 @@ package customtemplates
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
httperror "github.com/portainer/libhttp/error"
|
||||
"github.com/portainer/libhttp/request"
|
||||
|
@ -41,7 +40,7 @@ func (handler *Handler) customTemplateFile(w http.ResponseWriter, r *http.Reques
|
|||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to find a custom template with the specified identifier inside the database", err}
|
||||
}
|
||||
|
||||
fileContent, err := handler.FileService.GetFileContent(path.Join(customTemplate.ProjectPath, customTemplate.EntryPoint))
|
||||
fileContent, err := handler.FileService.GetFileContent(customTemplate.ProjectPath, customTemplate.EntryPoint)
|
||||
if err != nil {
|
||||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve custom template file from disk", err}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ func (handler *Handler) edgeJobFile(w http.ResponseWriter, r *http.Request) *htt
|
|||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to find an Edge job with the specified identifier inside the database", err}
|
||||
}
|
||||
|
||||
edgeJobFileContent, err := handler.FileService.GetFileContent(edgeJob.ScriptPath)
|
||||
edgeJobFileContent, err := handler.FileService.GetFileContent("", edgeJob.ScriptPath)
|
||||
if err != nil {
|
||||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve Edge job script file from disk", err}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package edgestacks
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
httperror "github.com/portainer/libhttp/error"
|
||||
"github.com/portainer/libhttp/request"
|
||||
|
@ -45,7 +44,7 @@ func (handler *Handler) edgeStackFile(w http.ResponseWriter, r *http.Request) *h
|
|||
fileName = stack.ManifestPath
|
||||
}
|
||||
|
||||
stackFileContent, err := handler.FileService.GetFileContent(path.Join(stack.ProjectPath, fileName))
|
||||
stackFileContent, err := handler.FileService.GetFileContent(stack.ProjectPath, fileName)
|
||||
if err != nil {
|
||||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve Compose file from disk", err}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package edgestacks
|
|||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
@ -56,7 +55,7 @@ func (handler *Handler) convertAndStoreKubeManifestIfNeeded(edgeStack *portainer
|
|||
return nil
|
||||
}
|
||||
|
||||
composeConfig, err := handler.FileService.GetFileContent(path.Join(edgeStack.ProjectPath, edgeStack.EntryPoint))
|
||||
composeConfig, err := handler.FileService.GetFileContent(edgeStack.ProjectPath, edgeStack.EntryPoint)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to retrieve Compose file from disk: %w", err)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package endpointedge
|
|||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
httperror "github.com/portainer/libhttp/error"
|
||||
"github.com/portainer/libhttp/request"
|
||||
|
@ -75,7 +74,7 @@ func (handler *Handler) endpointEdgeStackInspect(w http.ResponseWriter, r *http.
|
|||
}
|
||||
}
|
||||
|
||||
stackFileContent, err := handler.FileService.GetFileContent(path.Join(edgeStack.ProjectPath, fileName))
|
||||
stackFileContent, err := handler.FileService.GetFileContent(edgeStack.ProjectPath, fileName)
|
||||
if err != nil {
|
||||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve Compose file from disk", err}
|
||||
}
|
||||
|
|
|
@ -131,7 +131,7 @@ func (handler *Handler) endpointStatusInspect(w http.ResponseWriter, r *http.Req
|
|||
Version: job.Version,
|
||||
}
|
||||
|
||||
file, err := handler.FileService.GetFileContent(job.ScriptPath)
|
||||
file, err := handler.FileService.GetFileContent("", job.ScriptPath)
|
||||
|
||||
if err != nil {
|
||||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve Edge job script file", err}
|
||||
|
|
|
@ -3,7 +3,6 @@ package stacks
|
|||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
@ -389,10 +388,9 @@ func (handler *Handler) deployComposeStack(config *composeStackDeploymentConfig)
|
|||
!isAdminOrEndpointAdmin {
|
||||
|
||||
for _, file := range append([]string{config.stack.EntryPoint}, config.stack.AdditionalFiles...) {
|
||||
path := path.Join(config.stack.ProjectPath, file)
|
||||
stackContent, err := handler.FileService.GetFileContent(path)
|
||||
stackContent, err := handler.FileService.GetFileContent(config.stack.ProjectPath, file)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to get stack file content `%q`", path)
|
||||
return errors.Wrapf(err, "failed to get stack file content `%q`", file)
|
||||
}
|
||||
|
||||
err = handler.isValidStackFile(stackContent, securitySettings)
|
||||
|
|
|
@ -3,7 +3,6 @@ package stacks
|
|||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
@ -399,8 +398,7 @@ func (handler *Handler) deploySwarmStack(config *swarmStackDeploymentConfig) err
|
|||
|
||||
if !settings.AllowBindMountsForRegularUsers && !isAdminOrEndpointAdmin {
|
||||
for _, file := range append([]string{config.stack.EntryPoint}, config.stack.AdditionalFiles...) {
|
||||
path := path.Join(config.stack.ProjectPath, file)
|
||||
stackContent, err := handler.FileService.GetFileContent(path)
|
||||
stackContent, err := handler.FileService.GetFileContent(config.stack.ProjectPath, file)
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "failed to get stack file content")
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
@ -198,8 +197,8 @@ func (handler *Handler) deleteStack(userID portainer.UserID, stack *portainer.St
|
|||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
for _, fileName := range fileNames {
|
||||
manifestFilePath := path.Join(tmpDir, fileName)
|
||||
manifestContent, err := ioutil.ReadFile(path.Join(stack.ProjectPath, fileName))
|
||||
manifestFilePath := filesystem.JoinPaths(tmpDir, fileName)
|
||||
manifestContent, err := handler.FileService.GetFileContent(stack.ProjectPath, fileName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to read manifest file")
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package stacks
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
httperror "github.com/portainer/libhttp/error"
|
||||
"github.com/portainer/libhttp/request"
|
||||
|
@ -82,7 +81,7 @@ func (handler *Handler) stackFile(w http.ResponseWriter, r *http.Request) *httpe
|
|||
}
|
||||
}
|
||||
|
||||
stackFileContent, err := handler.FileService.GetFileContent(path.Join(stack.ProjectPath, stack.EntryPoint))
|
||||
stackFileContent, err := handler.FileService.GetFileContent(stack.ProjectPath, stack.EntryPoint)
|
||||
if err != nil {
|
||||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve Compose file from disk", err}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
|
@ -108,7 +107,7 @@ func (handler *Handler) updateKubernetesStack(r *http.Request, stack *portainer.
|
|||
tempFileDir, _ := ioutil.TempDir("", "kub_file_content")
|
||||
defer os.RemoveAll(tempFileDir)
|
||||
|
||||
if err := filesystem.WriteToFile(path.Join(tempFileDir, stack.EntryPoint), []byte(payload.StackFileContent)); err != nil {
|
||||
if err := filesystem.WriteToFile(filesystem.JoinPaths(tempFileDir, stack.EntryPoint), []byte(payload.StackFileContent)); err != nil {
|
||||
return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: "Failed to persist deployment file in a temp directory", Err: err}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
httperror "github.com/portainer/libhttp/error"
|
||||
|
@ -68,9 +67,7 @@ func (handler *Handler) templateFile(w http.ResponseWriter, r *http.Request) *ht
|
|||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to clone git repository", err}
|
||||
}
|
||||
|
||||
composeFilePath := path.Join(projectPath, payload.ComposeFilePathInRepository)
|
||||
|
||||
fileContent, err := handler.FileService.GetFileContent(composeFilePath)
|
||||
fileContent, err := handler.FileService.GetFileContent(projectPath, payload.ComposeFilePathInRepository)
|
||||
if err != nil {
|
||||
return &httperror.HandlerError{http.StatusInternalServerError, "Failed loading file content", err}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue