forward-port: write size cap + crypto/rand temp suffixes in fs sandbox
Re-applies two hardening changes from the deleted pkg/tools/filesystem.go to upstream's pkg/tools/fs/filesystem.go (sandboxFs.WriteFile): 1. Reject writes larger than MaxWriteFileSize (20 MB) before opening any file. Prevents runaway writes from a misbehaving caller filling disk. 2. Replace time.Now().UnixNano() temp suffixes with crypto/rand-generated hex. Eliminates predictable temp paths under concurrent or hostile filesystem scenarios; the prior nanosecond stamp could collide on high-resolution clocks across goroutines. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
94d28c1b86
commit
cd1720f40b
1 changed files with 16 additions and 3 deletions
|
|
@ -4,6 +4,8 @@ import (
|
|||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
|
@ -15,14 +17,16 @@ import (
|
|||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/sipeed/picoclaw/pkg/fileutil"
|
||||
"github.com/sipeed/picoclaw/pkg/logger"
|
||||
)
|
||||
|
||||
const MaxReadFileSize = 64 * 1024 // 64KB limit to avoid context overflow
|
||||
const (
|
||||
MaxReadFileSize = 64 * 1024 // 64KB limit to avoid context overflow
|
||||
MaxWriteFileSize = 20 * 1024 * 1024 // 20MB cap on a single write to avoid runaway writes
|
||||
)
|
||||
|
||||
func ValidatePathWithAllowPaths(
|
||||
path, workspace string,
|
||||
|
|
@ -1089,6 +1093,9 @@ func (r *sandboxFs) ReadFile(path string) ([]byte, error) {
|
|||
}
|
||||
|
||||
func (r *sandboxFs) WriteFile(path string, data []byte) error {
|
||||
if len(data) > MaxWriteFileSize {
|
||||
return fmt.Errorf("write rejected: %d bytes exceeds %d-byte cap", len(data), MaxWriteFileSize)
|
||||
}
|
||||
return r.execute(path, func(root *os.Root, relPath string) error {
|
||||
dir := filepath.Dir(relPath)
|
||||
if dir != "." && dir != "/" {
|
||||
|
|
@ -1099,7 +1106,13 @@ func (r *sandboxFs) WriteFile(path string, data []byte) error {
|
|||
|
||||
// Use atomic write pattern with explicit sync for flash storage reliability.
|
||||
// Using 0o600 (owner read/write only) for secure default permissions.
|
||||
tmpRelPath := fmt.Sprintf(".tmp-%d-%d", os.Getpid(), time.Now().UnixNano())
|
||||
// Random suffix prevents collisions and avoids predictable temp names that
|
||||
// could be exploited in concurrent or hostile filesystem scenarios.
|
||||
var rnd [8]byte
|
||||
if _, err := rand.Read(rnd[:]); err != nil {
|
||||
return fmt.Errorf("failed to generate temp file suffix: %w", err)
|
||||
}
|
||||
tmpRelPath := fmt.Sprintf(".tmp-%d-%s", os.Getpid(), hex.EncodeToString(rnd[:]))
|
||||
|
||||
tmpFile, err := root.OpenFile(tmpRelPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o600)
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue