Skip to content

cpu: fail closed when --max_cpus exceeds available CPUs - #324

Open
h1-mrz wants to merge 1 commit into
google:masterfrom
h1-mrz:harden-cpu-max-cpus
Open

h1-mrz wants to merge 1 commit into
google:masterfrom
h1-mrz:harden-cpu-max-cpus

Conversation

@h1-mrz

@h1-mrz h1-mrz commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Summary

When --max_cpus is larger than the number of available CPUs, initCpu() used to log a warning and return success WITHOUT setting any CPU affinity mask. The sandbox then ran on all available CPUs, silently defeating the user-requested CPU cap. Convert the warning to an error and fail closed so nsjail aborts loudly instead of launching with a less-restrictive cap than requested.

Repro (before fix)

$ nsjail --max_cpus 9999 -- /usr/bin/bash -c 'taskset -p $$'
[W] initCpu(): Number of requested CPUs is bigger than number of available CPUs (9999 > 6)
pid 1's current affinity mask: 3f            # all 6 CPUs, not 9999

Repro (after fix)

$ nsjail --max_cpus 9999 -- /usr/bin/bash -c 'taskset -p $$'
[E] initCpu(): Number of requested CPUs is bigger than number of available CPUs (9999 > 6)
[F] runChild(): Launching child process failed
$                                              # nsjail exits 255

Runtime-verified on nsjail HEAD (f100fd9) on 6-core Linux.

Fix

 	if (nsj->njc.max_cpus() > available_cpus) {
-		LOG_W(
+		LOG_E(
 		    "Number of requested CPUs is bigger than number of available CPUs (%zu > %zu)",
 		    (size_t)nsj->njc.max_cpus(), available_cpus);
-		return true;
+		return false;
 	}

2 insertions, 2 deletions. cpu.cc only. No behavior change for valid operator use cases.

Impact

Defense-in-depth hardening. A silent downgrade of a user-requested resource cap is the same family of defect as the silent zero-filter seccomp launch fixed in PR #285. Same threat model: the user requested a stronger isolation than nsjail actually delivered, and nsjail reported success.

Notes

When --max_cpus is larger than the number of available CPUs,
initCpu() used to log a warning and return success WITHOUT setting
any CPU affinity mask. The sandbox then ran on all available CPUs,
silently defeating the user-requested CPU cap.

Fix: convert LOG_W to LOG_E and return false so nsjail aborts loudly
instead of launching with a less-restrictive cap than requested.

Repro (before fix):
  $ nsjail --max_cpus 9999 -- /usr/bin/bash -c 'taskset -p $$'
  [W] initCpu(): Number of requested CPUs is bigger than ...
  pid 1's current affinity mask: 3f          # all 6 CPUs, not 9999

Repro (after fix):
  $ nsjail --max_cpus 9999 -- /usr/bin/bash -c 'taskset -p $$'
  [E] initCpu(): Number of requested CPUs is bigger than ...
  [F] runChild(): Launching child process failed
  $                                          # nsjail exits 255

Runtime-verified on nsjail HEAD (f100fd9) on 6-core Linux.

Matches the same 'fail closed on user-requested cap violation' pattern
as the merged PRs google#283, google#284, google#285 (and PR google#310 / fail-closed-setsid
by carrerasdarren-cell). A silent downgrade of a user-requested cap
is the same family of defect as a silent zero-filter seccomp launch
(PR google#285).
@h1-mrz

h1-mrz commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

Following up on this PR — it's been open for two weeks without review. The change is narrow (two lines, one file) and introduces no behavior change for valid configurations; it follows the same silent-downgrade hardening pattern as #285, which was merged on 2026-08-26. Please let me know if any changes are needed, or if this can be reviewed when convenient.

@h1-mrz

h1-mrz commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

Hi, just checking in on this. It's been open since Sep 3.

This branch has not been deployed

No deployments
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