Skip to content

utils: fall back to uid_map on OpenVZ - #2233

Open
giuseppe wants to merge 3 commits into
containers:mainfrom
giuseppe:fix-openvz-detection
Open

utils: fall back to uid_map on OpenVZ#2233
giuseppe wants to merge 3 commits into
containers:mainfrom
giuseppe:fix-openvz-detection

Conversation

@giuseppe

@giuseppe giuseppe commented Sep 8, 2026

Copy link
Copy Markdown
Member

Commit d73e66c ("utils: detect initial user namespace by inode") changed check_running_in_user_namespace() to compare the inode of /proc/self/ns/user against PROC_USER_INIT_INO, so that a user namespace with a full identity mapping -- such as the one systemd >= 260 sets up for PrivateUsers=full -- is no longer mistaken for the initial one.

OpenVZ virtualizes the namespace inode numbers it exposes through procfs, so PROC_USER_INIT_INO does not identify the initial user namespace there and the new check regressed the detection inside OpenVZ containers. This was reported for moby, which made the same change, by Sebastiaan van Stijn in #2150, along with the suggestion to special-case OpenVZ the way moby/sys#255 does:

moby/sys#255

Detect OpenVZ with the same procfs test systemd uses -- /proc/vz is exposed both on the host and inside a container, /proc/bc only on the host -- and fall back to the uid_map heuristic there. The inode check stays the preferred path everywhere else.

@thaJeztah thaJeztah left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thx! I'm not very fluent in C, so only some things that stood out 😅 (perhaps @kolyshkin can give it a peek)

Comment thread src/libcrun/utils.c Outdated
/* OpenVZ virtualizes the namespace inode numbers exposed through procfs, so
PROC_USER_INIT_INO cannot reliably identify the initial user namespace
there. */
if (running_in_openvz ())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if very relevant; in moby/sys, I opted to add a happy-path before falling back to detecting OpenVZ; that was mostly to avoid doing the extra work for a niche case (OpenVZ);

		// The kernel's initial user namespace inode is definitive when it
		// matches. OpenVZ virtualizes namespace inode numbers, so a mismatch
		// must fall back to uid_map-based detection there.
		if st.Ino == procUserInitIno {
			return false
		}
		if runningInOpenVZ() {
			return runningInUserNSFromUIDMap()
		}
		return true

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, that is better! Fixed now

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@giuseppe this might make sense; alas my openvz installation's kernel is too old to have proper userns so I can't test this but purely theoretically it looks fine.

Comment thread src/libcrun/utils.c
return ret;
}

return strstr (buffer, "4294967295") ? 0 : 1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also (comparing with moby/sys); looks like we parse the columns, and compare all (instead of only matching the magic value); probably in practice wouldn't make a difference (?);

	// As per user_namespaces(7), /proc/self/uid_map of
	// the initial user namespace shows 0 0 4294967295.
	initNS := a == 0 && b == 0 && c == 4294967295
	return !initNS

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about it, too, but the crun code was always like this (strstr (buffer, "4294967295") ? 0 : 1) so I guess comparing all three numbers are excessive.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've used strstr (buffer, "4294967295") ? 0 : 1 because the 4294967295 value can be used only with the full mapping and it can't be the initial ID because the mappings need to have at least one ID

@kolyshkin kolyshkin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@giuseppe
giuseppe force-pushed the fix-openvz-detection branch from 01d73dd to 3a67f86 Compare September 8, 2026 20:12
@kolyshkin

kolyshkin commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

One other (unrelated to openvz, related to #2151) thing is, kernels < 3.8 don't have /proc/self/ns/user but still have userns so we need to also fall back to check_running_in_user_namespace_uid_map when stat gives ENOENT.

Unless, of course, we don't support kernels < 3.8 (frankly I dunno if we do).

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
Commit d73e66c ("utils: detect initial user namespace by inode")
changed check_running_in_user_namespace() to compare the inode of
/proc/self/ns/user against PROC_USER_INIT_INO, so that a user namespace
with a full identity mapping -- such as the one systemd >= 260 sets up
for PrivateUsers=full -- is no longer mistaken for the initial one.

OpenVZ virtualizes the namespace inode numbers it exposes through procfs,
so PROC_USER_INIT_INO does not identify the initial user namespace there
and the new check regressed the detection inside OpenVZ containers.  This
was reported for moby, which made the same change, by Sebastiaan van
Stijn in containers#2150, along with the
suggestion to special-case OpenVZ the way moby/sys#255 does:

  moby/sys#255

Detect OpenVZ with the same procfs test systemd uses -- /proc/vz is
exposed both on the host and inside a container, /proc/bc only on the
host -- and fall back to the uid_map heuristic there.  The inode check
stays the preferred path everywhere else.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
Commit d73e66c ("utils: detect initial user namespace by inode")
took a missing /proc/self/ns/user to mean that the kernel does not
support user namespaces at all.  The file was added in Linux 3.8, and
kernels older than that can still be in a user namespace, which
/proc/self/uid_map does describe.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
@giuseppe

giuseppe commented Sep 9, 2026

Copy link
Copy Markdown
Member Author

One other (unrelated to openvz, related to #2151) thing is, kernels < 3.8 don't have /proc/self/ns/user but still have userns so we need to also fall back to check_running_in_user_namespace_uid_map when stat gives ENOENT.

Unless, of course, we don't support kernels < 3.8 (frankly I dunno if we do).

ok this was easy to fix, so I've added a patch.

@giuseppe
giuseppe force-pushed the fix-openvz-detection branch from 3a67f86 to 2f58fd6 Compare September 9, 2026 09:18
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.

3 participants