fix: prevent directory traversal attack when writing request files

This commit is contained in:
Anton
2024-01-19 20:47:09 +05:00
parent 02473a2b61
commit bca91d71e5
5 changed files with 176 additions and 3 deletions

View File

@@ -8,7 +8,6 @@ import (
"io"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"time"
@@ -54,7 +53,10 @@ func (e *Docker) Exec(req Request) Execution {
if e.cmd.Entry != "" {
// write request files to the temp directory
err = e.writeFiles(dir, req.Files)
if err != nil {
var argErr ArgumentError
if errors.As(err, &argErr) {
return Fail(req.ID, err)
} else if err != nil {
err = NewExecutionError("write files to temp dir", err)
return Fail(req.ID, err)
}
@@ -171,7 +173,12 @@ func (e *Docker) writeFiles(dir string, files Files) error {
if name == "" {
name = e.cmd.Entry
}
path := filepath.Join(dir, name)
var path string
path, err = fileio.JoinDir(dir, name)
if err != nil {
err = NewArgumentError(fmt.Sprintf("files[%s]", name), err)
return false
}
err = fileio.WriteFile(path, content, 0444)
return err == nil
})

View File

@@ -1,6 +1,7 @@
package engine
import (
"fmt"
"strings"
"testing"
@@ -231,6 +232,29 @@ func TestDockerRun(t *testing.T) {
t.Errorf("Stderr: unexpected value: %s", out.Stderr)
}
})
t.Run("directory traversal attack", func(t *testing.T) {
mem.Clear()
const fileName = "../../opt/codapi/codapi"
engine := NewDocker(dockerCfg, "python", "run")
req := Request{
ID: "http_42",
Sandbox: "python",
Command: "run",
Files: map[string]string{
"": "print('hello world')",
fileName: "hehe",
},
}
out := engine.Exec(req)
if out.OK {
t.Error("OK: expected false")
}
want := fmt.Sprintf("files[%s]: invalid name", fileName)
if out.Stderr != want {
t.Errorf("Stderr: unexpected value: %s", out.Stderr)
}
})
}
func TestDockerExec(t *testing.T) {

View File

@@ -62,6 +62,25 @@ func (err ExecutionError) Unwrap() error {
return err.inner
}
// An ArgumentError is returned if code execution failed
// due to the invalid value of the request agrument.
type ArgumentError struct {
name string
reason error
}
func NewArgumentError(name string, reason error) ArgumentError {
return ArgumentError{name: name, reason: reason}
}
func (err ArgumentError) Error() string {
return err.name + ": " + err.reason.Error()
}
func (err ArgumentError) Unwrap() error {
return err.reason
}
// Files are a collection of files to be executed by the engine.
type Files map[string]string