Skip to content

Re-validate container status under the lock before delete (TOCTOU)#1860

Open
radheradhe01 wants to merge 1 commit into
apple:mainfrom
radheradhe01:fix/delete-toctou-status-recheck
Open

Re-validate container status under the lock before delete (TOCTOU)#1860
radheradhe01 wants to merge 1 commit into
apple:mainfrom
radheradhe01:fix/delete-toctou-status-recheck

Conversation

@radheradhe01

Copy link
Copy Markdown
Contributor

Problem

ContainersService.delete reads the container status outside the lock:

let state = try self._getContainerState(id: id)   // unlocked read
switch state.snapshot.status {
...
default:
    try await self.lock.withLock { context in
        try await self.cleanUp(id: id, context: context)   // no status re-check
    }
}

startProcess holds the same lock while transitioning a container to .running and writing the state back. Between the unlocked read here and acquiring the lock, a container observed as stopped can start. cleanUp only guards on containers[id] == nil, not status, so it then deletes the bundle of a now-running container (TOCTOU).

Fix

Re-read the status inside the lock in the default branch and refuse the delete if the container has since become .running/.stopping, mirroring the existing message used for the non-forced running case.

Notes

Only the non-forced delete path changes; the --force path is unchanged.

### Problem
`ContainersService.delete` reads the container status **outside** the lock:

```swift
let state = try self._getContainerState(id: id)   // unlocked read
switch state.snapshot.status {
...
default:
    try await self.lock.withLock { context in
        try await self.cleanUp(id: id, context: context)   // no status re-check
    }
}
```

`startProcess` holds the same lock while transitioning a container to `.running` and writing the state back. Between the unlocked read here and acquiring the lock, a container observed as stopped can start. `cleanUp` only guards on `containers[id] == nil`, not status, so it then deletes the bundle of a now-running container (TOCTOU).

### Fix
Re-read the status **inside** the lock in the `default` branch and refuse the delete if the container has since become `.running`/`.stopping`, mirroring the existing message used for the non-forced running case.

### Notes
Only the non-forced delete path changes; the `--force` path is unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant