Unpacking a crafted image layer with a long(invalid) file name crashes the unpacking process
Impact
An attacker who can supply a container image layer for a victim to unpack — via a malicious or compromised registry, a poisoned base image, or a pull request that changes which image gets fetched — can crash the process performing the unpack with no privileges beyond getting the victim to pull or run the crafted image reference.
The trigger is a single tar entry whose file, directory, or symlink name exceeds 255 UTF-8 bytes. When ContainerizationEXT4 writes that entry into the ext4 rootfs it is building, an unchecked UInt8 conversion of the name length traps and aborts the process.
Details
EXT4.Formatter.writeDirEntry() writes each directory entry's name length into the ext4 on-disk DirectoryEntry.nameLength field, which is a UInt8:
```swift
// Sources/ContainerizationEXT4/EXT4+Formatter.swift
nameLength: UInt8(nameData.count), // traps if nameData.count > 255
`
Swift's UInt8.init(_:) traps at runtime (aborting the process) when the source value does not fit in 8 bits.
The name is fully attacker-controlled and reaches this conversion with no length validation anywhere along the path.
255 bytes is the maximum length of a single path component on a real Linux filesystem, so a layer produced by tarring an actual directory tree can never contain a name this long. The tar format itself imposes no such limit, so a deliberately crafted archive (one...
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| apple/container Product | < 1.3.0 | 1.3.0 |
| apple/containerization Product | < 0.41.0 | 0.41.0 |
Details and references
## Impact An attacker who can supply a container image layer for a victim to unpack — via a malicious or compromised registry, a poisoned base image, or a pull request that changes which image gets fetched — can crash the process performing the unpack with no privileges beyond getting the victim to pull or run the crafted image reference. The trigger is a single tar entry whose file, directory, or symlink name exceeds 255 UTF-8 bytes. When `ContainerizationEXT4` writes that entry into the ext4 rootfs it is building, an unchecked `UInt8` conversion of the name length traps and aborts the process. ## Details `EXT4.Formatter.writeDirEntry()` writes each directory entry's name length into the ext4 on-disk `DirectoryEntry.nameLength` field, which is a `UInt8`: ```swift // Sources/ContainerizationEXT4/EXT4+Formatter.swift nameLength: UInt8(nameData.count), // traps if nameData.count > 255 ``` Swift's `UInt8.init(_:)` traps at runtime (aborting the process) when the source value does not fit in 8 bits. The name is fully attacker-controlled and reaches this conversion with no length validation anywhere along the path. 255 bytes is the maximum length of a single path component on a real Linux filesystem, so a layer produced by tarring an actual directory tree can never contain a name this long. The tar format itself imposes no such limit, so a deliberately crafted archive (one that was never the tar of a real filesystem) can trivially contain one. ## Affected code - `EXT4.Formatter.writeDirEntry()` in `Sources/ContainerizationEXT4/EXT4+Formatter.swift` — fixed to reject a name whose UTF-8 length exceeds `UInt8.max` (255) before the conversion, throwing `EXT4.Formatter.Error.invalidName` instead of trapping. The same guard also protects the entry's `recordLength` (`UInt16`), which is derived from the name length and would only overflow with a far longer name. - Any consumer of `ContainerizationEXT4` that formats an ext4 filesystem from untrusted tar/OCI layer input reaches the same conversion. ## Mitigations 1. Upgrade to the version of `apple/containerization` containing the fix. 2. Do not unpack, pull, or run container images from untrusted sources — the registry, base image, or CI step that supplies a layer is part of the trust boundary, not just the resulting container's contents. 3. In CI/CD, avoid pulling or running an image reference that a pull request or other external input can influence on a runner shared with other jobs, since the crash disrupts every concurrent image operation on that host. ## Verifying whether you are affected Inspect a layer tar for any path component longer than 255 bytes before unpacking it: ```bash cd <content-store-path> for f in *; do tar -tf "$f" 2>/dev/null | awk -F/ -v file="$f" \ '{ for (i=1;i<=NF;i++) if (length($i) > 255) print file": "$0 }' done ``` Any output indicates an entry that would trigger the trap on an affected version. ## References Fix: apple/containerization#898, commit [cd29b8a734abd972d73d4b3eaba12af946f55f9b](https://github.com/apple/containerization/pull/898/commits/cd29b8a734abd972d73d4b3eaba12af946f55f9b)
- Severity from
- GitHub (reviewed advisory)