google / google/gvisor

runsc Doesn't Skip Empty BlockIO

Open Beginner friendly
#14,738 0 comments 0 reactions 0 assignees View on GitHub
type: bug
Dominant language
Go
Stars
19.3k
Forks
2k
Avg merge
3d 5h
Merged PRs (30d)
264

Description

### Description

#### Symptom

**runsc** fails on a kernel with
- cgroup v1, and
- `CONFIG_BLK_CGROUP` disabled

#### Root Cause

[992a840889](https://github.com/google/gvisor/commit/992a840889ae0eff8ebed811c54020be8487621d) intends to make cgroup blkio optional. But it skips iff the `BlockIO` struct is nil.

Docker always populates that struct, even when no I/O limit was requested.
- [v24.0.2](https://github.com/moby/moby/blob/v24.0.2/daemon/oci_linux.go#L959-L973) effectively emits `"blockIO":{"weight":0}`
- [newer version](https://github.com/moby/moby/blob/235d2876f80fff1ee13378646a4d41a4c670a052/daemon/oci_linux.go#L958-L968) effectively emits `"blockIO":{}`

##### Inspect Container Config

```bash
docker run --rm -v /run:/rc:ro alpine sh -c 'grep -o "\"blockIO\":{[^}]*}" $(find /rc -path "*/io.containerd.runtime.v2.task/moby/$(hostname)*/config.json")'
```

Output
```
// Docker v24.0.2
"blockIO":{"weight":0}

// Newer Docker
"blockIO":{}
```

#### Proposal

In addition to nil check, [blockIO.skip()](https://github.com/google/gvisor/blob/f737bb92f276d3339e391891e92e46f3d26c2e3d/runsc/cgroup/cgroup.go#L932) checks whether all fields of [LinuxBlockIO](https://pkg.go.dev/github.com/opencontainers/runtime-spec@v1.2.1/specs-go#LinuxBlockIO) are default.

```go
func (*blockIO) skip(spec *specs.LinuxResources) error {
if spec == nil || spec.BlockIO == nil {
return nil
}

b := spec.BlockIO
if (b.Weight != nil && *b.Weight != 0) ||
(b.LeafWeight != nil && *b.LeafWeight != 0) ||
len(b.WeightDevice) > 0 ||
len(b.ThrottleReadBpsDevice) > 0 ||
len(b.ThrottleWriteBpsDevice) > 0 ||
len(b.ThrottleReadIOPSDevice) > 0 ||
len(b.ThrottleWriteIOPSDevice) > 0 {
return fmt.Errorf("blkio controller is missing but limits are set in OCI spec")
}
return nil
}
```

### Steps to reproduce

#### Docker Runtime Failure

Requirements (if infeasible, try `Unit Test Failure` instead)
- cgroup v1
- `CONFIG_BLK_CGROUP` disabled. i.e. build the kernel with `CONFIG_BLK_CGROUP=n`

Command
```bash
docker run --rm --runtime runsc alpine true
```

Error
```
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: creating container: cannot set up cgroup for root: configuring cgroup: stat /sys/fs/cgroup/blkio: no such file or directory: unknown.
```

#### Unit Test Failure

Add `extraValid` to [TestOptional](https://github.com/google/gvisor/blob/2eeb2f0065a0e8c7b40eede3c54bcff9cd2e7346/runsc/cgroup/cgroup_test.go#L936)

```
{
name: "blkio",
ctrlr: &blockIO{},
extraValid: []*specs.LinuxResources{
{BlockIO: &specs.LinuxBlockIO{}}, // Docker 29
{BlockIO: &specs.LinuxBlockIO{Weight: uint16Ptr(0)}}, // Docker ≤ 24
},
invalid: []struct {
name string
spec *specs.LinuxResources
err string
}{
{
name: "weight",
spec: &specs.LinuxResources{BlockIO: &specs.LinuxBlockIO{Weight: uint16Ptr(1)}},
err: "blkio controller is missing but limits are set in OCI spec",
},
},
},
```

The test fails with the current [skip()](https://github.com/google/gvisor/blob/2eeb2f0065a0e8c7b40eede3c54bcff9cd2e7346/runsc/cgroup/cgroup.go#L932).

The proposal fixes it.

Combined with `Inspect Container Config`, this shows that the current implementation does not skip `BlockIO` as expected.

### runsc version

```shell
runsc version VERSION_MISSING
spec: 1.2.1

Built from source at release-20260817.0-43-g80336ad54
```

### docker version (if using docker)

```shell
Client:
Version: 24.0.2
API version: 1.43
Go version: go1.20.4
Git commit: 610b8d0
Built: Thu Sep 25 10:08:01 2025
OS/Arch: linux/amd64
Context: default

Server:
Engine:
Version: 24.0.2
API version: 1.43 (minimum version 1.12)
Go version: go1.20.4
Git commit: bd0a34d
Built: Thu Sep 25 10:09:08 2025
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v1.7.1
GitCommit: fea6458b8abe502f6228eab2e5a6678fcb5c3fb0
runc:
Version: v1.1.7
GitCommit: 0320c58
docker-init:
Version: 0.19.0
GitCommit: ed96d00
```

### uname

Linux 5.10.55+ SMP x86_64 GNU/Linux

### kubectl (if using Kubernetes)

```shell

```

### repo state (if built from source)

fatal: No names found, cannot describe anything.

### runsc debug logs (if available)

```shell
Not applicable: the failure happens in runsc create before the sandbox starts
```

Contributor guide

Open the contributing guide

Research direction

Start with runsc/cgroup/cgroup.go at blockIO.skip() and runsc/cgroup/cgroup_test.go at TestOptional. Add the reported empty and zero-valued BlockIO cases, then run the cgroup unit tests; done means empty/default BlockIO is skipped while non-default limits still report the missing controller.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, go, linux
Domain
operating-systems
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
84/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.