Skip to content

Commit 9adeda8

Browse files
committed
more install hardening - toctou
1 parent b9a89c3 commit 9adeda8

File tree

2 files changed

+37
-10
lines changed

2 files changed

+37
-10
lines changed

cmd/agent/install.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -524,20 +524,30 @@ func installCron(agentPath, _, _ string) error {
524524

525525
// Get the directory where the agent is installed
526526
agentDir := filepath.Dir(agentPath)
527-
agentBinary := filepath.Base(agentPath)
528527

529-
// Use nohup with shell to properly background the process
530-
// Change to the agent directory first so PID file and logs are created in the right place
531-
// The & is crucial for detaching from the parent process
532-
shellCmd := fmt.Sprintf("cd %s && %s ./%s > /dev/null 2>&1 &", agentDir, nohupPath, agentBinary)
533-
cmd = exec.Command("sh", "-c", shellCmd) //nolint:noctx // agent spawns its own context
528+
// Start the agent directly with nohup, avoiding shell interpretation
529+
cmd = exec.Command(nohupPath, agentPath) //nolint:noctx // agent spawns its own context
530+
cmd.Dir = agentDir // Set working directory for PID file and logs
534531

535-
if err := cmd.Run(); err != nil {
532+
// Redirect output to /dev/null
533+
devNull, err := os.Open("/dev/null")
534+
if err == nil {
535+
cmd.Stdout = devNull
536+
cmd.Stderr = devNull
537+
defer func() { _ = devNull.Close() }() //nolint:errcheck // defer close
538+
}
539+
540+
if err := cmd.Start(); err != nil {
536541
log.Printf("[WARN] Failed to start agent with nohup: %v (will start via cron in 15 minutes)", err)
537542
return nil
538543
}
539544

540-
log.Print("[INFO] Agent started successfully in background using nohup")
545+
// Detach from the process
546+
if err := cmd.Process.Release(); err != nil {
547+
log.Printf("[WARN] Failed to release process: %v", err)
548+
}
549+
550+
log.Printf("[INFO] Agent started successfully in background using nohup (PID: %d)", cmd.Process.Pid)
541551

542552
// Give it a moment to start
543553
time.Sleep(500 * time.Millisecond)

cmd/agent/main.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,13 +312,30 @@ func checkAndCreatePIDFile() (exists bool, cleanup func()) {
312312
}
313313
}
314314

315-
// Write our PID
315+
// Write our PID atomically using O_EXCL to prevent race conditions
316316
pid := os.Getpid()
317-
if err := os.WriteFile(pidPath, []byte(strconv.Itoa(pid)), 0o600); err != nil {
317+
pidFile, err := os.OpenFile(pidPath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o600)
318+
if err != nil {
319+
if os.IsExist(err) {
320+
// Another process created the file between our check and now
321+
log.Print("[WARN] PID file was created by another process, exiting")
322+
return false, func() {}
323+
}
324+
log.Printf("[WARN] Failed to create PID file: %v", err)
325+
return true, func() {} // Continue without PID file
326+
}
327+
328+
if _, err := pidFile.WriteString(strconv.Itoa(pid)); err != nil {
329+
_ = pidFile.Close() //nolint:errcheck // best effort cleanup
330+
_ = os.Remove(pidPath) //nolint:errcheck // best effort cleanup
318331
log.Printf("[WARN] Failed to write PID file: %v", err)
319332
return true, func() {} // Continue without PID file
320333
}
321334

335+
if err := pidFile.Close(); err != nil {
336+
log.Printf("[WARN] Failed to close PID file: %v", err)
337+
}
338+
322339
log.Printf("[INFO] Created PID file with PID %d", pid)
323340

324341
// Return cleanup function

0 commit comments

Comments
 (0)