Pre-create become file with O_EXCL
CodeQL / Analyze (go) (push) Has been cancelled
build / build (push) Has been cancelled
Test fzf on macOS / build (push) Has been cancelled

Prevents another user on a shared TMPDIR from planting a file or a
symbolic link at the predictable path while fzf is running, like the
exit status file of the floating pane. Reject an empty become command.
This commit is contained in:
Junegunn Choi
2026-07-05 22:00:55 +09:00
parent eee92b1b2a
commit f7392a8b63
2 changed files with 20 additions and 3 deletions
+13 -3
View File
@@ -138,6 +138,17 @@ func runProxy(commandPrefix string, cmdBuilder func(temp string, needBash bool)
temp := WriteTemporaryFile(append(exports, command), "\n")
defer os.Remove(temp)
// Pre-create the become file so that another user on a shared TMPDIR
// cannot plant a file or a symbolic link at the predictable path while
// fzf is running
becomeFile := temp + becomeSuffix
becomeF, err := os.OpenFile(becomeFile, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o600)
if err != nil {
return ExitError, err
}
becomeF.Close()
defer os.Remove(becomeFile)
cmd, err := cmdBuilder(temp, needBash)
if err != nil {
return ExitError, err
@@ -155,16 +166,15 @@ func runProxy(commandPrefix string, cmdBuilder func(temp string, needBash bool)
if exitError, ok := err.(*exec.ExitError); ok {
code := exitError.ExitCode()
if code == ExitBecome {
becomeFile := temp + becomeSuffix
data, err := os.ReadFile(becomeFile)
os.Remove(becomeFile)
if err != nil {
return ExitError, err
}
elems := strings.Split(string(data), "\x00")
if len(elems) < 1 {
if len(data) == 0 {
return ExitError, errors.New("invalid become command")
}
elems := strings.Split(string(data), "\x00")
command := elems[0]
env := []string{}
if len(elems) > 1 {