apple / apple/container

[Bug]: Possible race in implicit volume creation (`Utility.getOrCreateVolume()`)

Open
#774 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
Swift
Stars
49.9k
Forks
1.8k
Avg merge
1d 20h
Merged PRs (30d)
22

Description

### I have done the following

- [x] I have searched the existing issues
- [x] If possible, I've reproduced the issue using the 'main' branch of this project

### Steps to reproduce

The current implicit volume creation logic in `Utility.getOrCreateVolume()` has a race condition in the create or inspect pattern:

```
do {
volume = try await ClientVolume.create(...)
} catch let error as VolumeError {
guard case .volumeAlreadyExists = error else { throw error }
volume = try await ClientVolume.inspect(parsed.name)
}
```

### Current behavior

1. Container A calls getOrCreateVolume(“vol”) which attempts to create a volume
2. Container B calls getOrCreateVolume(“vol”) which also attempts to create a volume
3. Container A’s create succeeds
4. Container B’s create fails with volumeAlreadyExists
5. Container B calls inspect() to get the volume
6. But between steps 3 and 5, if Container A’s container fails and is cleaned up along with its volume,
Container B’s inspect() will fail with volumeNotFound

### Expected behavior

In practice the race window is small. What I added in ContainersService is a precedent that solves similar races using withContainerList() (see [ContainersService.swift#L122](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Containers/ContainersService.swift#L122)), where we do atomic check-and-create operations within a single lock context.

### Environment

```markdown
N/A
```

### Relevant log output

```shell
N/A
```

### Code of Conduct

- [x] I agree to follow this project's Code of Conduct

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.