Fix two daemon bugs: Firecracker context and sessionControllers init

vm.go: Firecracker was launched with context.Background() instead of
the incoming request ctx. A cancelled or timed-out VM creation request
could not stop mid-flight Firecracker process spawning, leaving an
orphaned process and leaked resources. Replace the four firecrackerCtx
uses with ctx directly; the local variable is removed.

guest_sessions.go / daemon.go: sessionControllers map was lazily
initialized with a nil-check inside every mutating method. With d.mu
held this isn't a data race, but the pattern is fragile — any new
method that writes to the map without copying the guard can panic.
Initialize the map once in Open() alongside the other daemon maps and
channels, and remove the redundant nil-checks from setGuestSessionController
and claimGuestSessionController.
This commit is contained in:
Thales Maciel 2026-04-14 19:53:26 -03:00
parent 43dfda14f8
commit 0e764b0571
No known key found for this signature in database
GPG key ID: 33112E6833C34679
3 changed files with 12 additions and 18 deletions

View file

@ -80,13 +80,14 @@ func Open(ctx context.Context) (d *Daemon, err error) {
return nil, err
}
d = &Daemon{
layout: layout,
config: cfg,
store: db,
runner: system.NewRunner(),
logger: logger,
closing: make(chan struct{}),
pid: os.Getpid(),
layout: layout,
config: cfg,
store: db,
runner: system.NewRunner(),
logger: logger,
closing: make(chan struct{}),
pid: os.Getpid(),
sessionControllers: make(map[string]*guestSessionController),
}
d.ensureVMSSHClientConfig()
d.logger.Info("daemon opened", "socket", layout.SocketPath, "state_dir", layout.StateDir, "log_level", cfg.LogLevel)

View file

@ -494,18 +494,12 @@ func (d *Daemon) BeginGuestSessionAttach(ctx context.Context, params api.GuestSe
func (d *Daemon) setGuestSessionController(id string, controller *guestSessionController) {
d.mu.Lock()
defer d.mu.Unlock()
if d.sessionControllers == nil {
d.sessionControllers = make(map[string]*guestSessionController)
}
d.sessionControllers[id] = controller
}
func (d *Daemon) claimGuestSessionController(id string, controller *guestSessionController) bool {
d.mu.Lock()
defer d.mu.Unlock()
if d.sessionControllers == nil {
d.sessionControllers = make(map[string]*guestSessionController)
}
if d.sessionControllers[id] != nil {
return false
}

View file

@ -298,7 +298,6 @@ func (d *Daemon) startVMLocked(ctx context.Context, vm model.VMRecord, image mod
}
op.stage("firecracker_launch", "log_path", vm.Runtime.LogPath, "metrics_path", vm.Runtime.MetricsPath)
vmCreateStage(ctx, "boot_firecracker", "starting firecracker")
firecrackerCtx := context.Background()
machineConfig := firecracker.MachineConfig{
BinaryPath: fcPath,
VMID: vm.ID,
@ -322,15 +321,15 @@ func (d *Daemon) startVMLocked(ctx context.Context, vm model.VMRecord, image mod
Logger: d.logger,
}
d.contributeMachineConfig(&machineConfig, vm, image)
machine, err := firecracker.NewMachine(firecrackerCtx, machineConfig)
machine, err := firecracker.NewMachine(ctx, machineConfig)
if err != nil {
return cleanupOnErr(err)
}
if err := machine.Start(firecrackerCtx); err != nil {
vm.Runtime.PID = d.resolveFirecrackerPID(firecrackerCtx, machine, apiSock)
if err := machine.Start(ctx); err != nil {
vm.Runtime.PID = d.resolveFirecrackerPID(ctx, machine, apiSock)
return cleanupOnErr(err)
}
vm.Runtime.PID = d.resolveFirecrackerPID(firecrackerCtx, machine, apiSock)
vm.Runtime.PID = d.resolveFirecrackerPID(ctx, machine, apiSock)
op.debugStage("firecracker_started", "pid", vm.Runtime.PID)
op.stage("socket_access", "api_socket", apiSock)
if err := d.ensureSocketAccess(ctx, apiSock, "firecracker api socket"); err != nil {