Files
Privatae d62da8adb4
ci / personal-data (push) Successful in 4s
ci / fuzz (push) Successful in 2m44s
ci / test (push) Successful in 2m11s
bastion 0.54.0
2026-10-21 22:29:10 +00:00

43 lines
1.3 KiB
Go

//go:build linux
package main
import (
"os"
"strconv"
"golang.org/x/sys/unix"
)
// mcpOpenRegular opens path for reading only if what it names, after any
// symlinks, is a regular file, without ever opening anything else. The first
// open is O_PATH: it resolves the path and pins the inode but does not open
// the file (no driver runs, a FIFO does not wait). Only once fstat says
// regular is that same inode reopened for reading through /proc/self/fd, so
// swapping the path between the look and the read reaches nothing new.
func mcpOpenRegular(path string) (*os.File, string, error) {
pfd, err := unix.Open(path, unix.O_PATH|unix.O_CLOEXEC, 0)
if err != nil {
return nil, "", &os.PathError{Op: "open", Path: path, Err: err}
}
defer unix.Close(pfd)
var st unix.Stat_t
if err := unix.Fstat(pfd, &st); err != nil {
return nil, "", &os.PathError{Op: "fstat", Path: path, Err: err}
}
if st.Mode&unix.S_IFMT != unix.S_IFREG {
return nil, "", errMCPNotRegular
}
fd, err := unix.Open("/proc/self/fd/"+strconv.Itoa(pfd), unix.O_RDONLY|unix.O_CLOEXEC|unix.O_NOCTTY|unix.O_NONBLOCK, 0)
if err != nil {
return nil, "", &os.PathError{Op: "reopen", Path: path, Err: err}
}
f := os.NewFile(uintptr(fd), path)
fi, err := f.Stat()
if err != nil || !fi.Mode().IsRegular() {
f.Close()
return nil, "", errMCPNotRegular
}
return f, mcpFileOwner(fi), nil
}