* [pve-devel] [PATCH container v2 0/2] oci create: honor `User` from OCI image config
@ 2026-01-21 16:00 Filip Schauer
2026-01-21 16:00 ` [pve-devel] [PATCH container v2 1/2] config: add `lxc.init.uid`/`gid`/`groups` keys Filip Schauer
2026-01-21 16:00 ` [pve-devel] [PATCH container v2 2/2] oci create: honor User from OCI image config Filip Schauer
0 siblings, 2 replies; 3+ messages in thread
From: Filip Schauer @ 2026-01-21 16:00 UTC (permalink / raw)
To: pve-devel
Honor a custom user and group specified for the entrypoint via the OCI
image config `User` field instead of ignoring it.
This requires the following patch for LXC in order to work properly:
https://github.com/lxc/lxc/pull/4626
With these patches applied, docker.io/weblate/weblate starts with the
correct uid and groups instead of the default uid=0(root) gid=0(root)
groups=0(root).
Changes since v1:
* Move OCI User resolving code to separate sub
* chomp $line before interpreting fields
* Prevent rootfs escape when following /etc/passwd & /etc/group symlinks
* Fix $username search in get_supplementary_groups
Filip Schauer (2):
config: add `lxc.init.uid`/`gid`/`groups` keys
oci create: honor User from OCI image config
src/PVE/LXC/Config.pm | 3 ++
src/PVE/LXC/Create.pm | 82 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 85 insertions(+)
--
2.47.3
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 3+ messages in thread
* [pve-devel] [PATCH container v2 1/2] config: add `lxc.init.uid`/`gid`/`groups` keys
2026-01-21 16:00 [pve-devel] [PATCH container v2 0/2] oci create: honor `User` from OCI image config Filip Schauer
@ 2026-01-21 16:00 ` Filip Schauer
2026-01-21 16:00 ` [pve-devel] [PATCH container v2 2/2] oci create: honor User from OCI image config Filip Schauer
1 sibling, 0 replies; 3+ messages in thread
From: Filip Schauer @ 2026-01-21 16:00 UTC (permalink / raw)
To: pve-devel
These config keys allow one to specify the uid, gid and groups of the
init process. This is useful for application containers.
Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
---
No changes since v1
src/PVE/LXC/Config.pm | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/PVE/LXC/Config.pm b/src/PVE/LXC/Config.pm
index 6445528..6f54e9f 100644
--- a/src/PVE/LXC/Config.pm
+++ b/src/PVE/LXC/Config.pm
@@ -711,6 +711,9 @@ my $valid_lxc_conf_keys = {
'lxc.signal.stop' => 1,
'lxc.init.cmd' => 1,
'lxc.init.cwd' => 1,
+ 'lxc.init.uid' => 1,
+ 'lxc.init.gid' => 1,
+ 'lxc.init.groups' => 1,
'lxc.pty.max' => 1,
'lxc.console.logfile' => 1,
'lxc.console.path' => 1,
--
2.47.3
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 3+ messages in thread
* [pve-devel] [PATCH container v2 2/2] oci create: honor User from OCI image config
2026-01-21 16:00 [pve-devel] [PATCH container v2 0/2] oci create: honor `User` from OCI image config Filip Schauer
2026-01-21 16:00 ` [pve-devel] [PATCH container v2 1/2] config: add `lxc.init.uid`/`gid`/`groups` keys Filip Schauer
@ 2026-01-21 16:00 ` Filip Schauer
1 sibling, 0 replies; 3+ messages in thread
From: Filip Schauer @ 2026-01-21 16:00 UTC (permalink / raw)
To: pve-devel
Honor a custom user and group specified for the entrypoint via the OCI
image config `User` field instead of ignoring it.
User and group name lookups, including supplementary groups, are
resolved from /etc/passwd and /etc/group in the container file system.
This behaviour matches the OCI image spec. [0]
[0] https://specs.opencontainers.org/image-spec/config/?v=v1.1.1#properties
Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
Tested-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
---
This requires the following patch for LXC in order to work properly:
https://github.com/lxc/lxc/pull/4626
Changes since v1:
* Move OCI User resolving code to separate sub
* chomp $line before interpreting fields
* Prevent rootfs escape when following /etc/passwd & /etc/group symlinks
* Fix $username search in get_supplementary_groups
src/PVE/LXC/Create.pm | 82 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 82 insertions(+)
diff --git a/src/PVE/LXC/Create.pm b/src/PVE/LXC/Create.pm
index 9956cf9..5ed1c29 100644
--- a/src/PVE/LXC/Create.pm
+++ b/src/PVE/LXC/Create.pm
@@ -3,6 +3,7 @@ package PVE::LXC::Create;
use strict;
use warnings;
+use Cwd qw(abs_path);
use File::Basename;
use File::Path qw(make_path);
use Fcntl;
@@ -768,6 +769,13 @@ sub restore_oci_archive {
}
}
+ if (my $userstr = $oci_config_get_checked_scalar->('User')) {
+ my ($uid, $gid, $groups) = resolve_oci_user($userstr, $rootdir);
+ push $conf->{lxc}->@*, ['lxc.init.uid', $uid] if defined($uid);
+ push $conf->{lxc}->@*, ['lxc.init.gid', $gid] if defined($gid);
+ push $conf->{lxc}->@*, ['lxc.init.groups', $groups] if defined($groups);
+ }
+
if (my $working_dir = $oci_config_get_checked_scalar->('WorkingDir')) {
push $conf->{lxc}->@*, ['lxc.init.cwd', $working_dir];
}
@@ -782,4 +790,78 @@ sub restore_oci_archive {
return $conf; # it's a reference anyway, so return mostly for convenience.
}
+sub resolve_oci_user {
+ my ($userstr, $rootdir) = @_;
+
+ my ($user, $group) = $userstr =~ /^([^:]+)(?::([^:]+))?$/
+ or die "OCI config value for 'User' has an invalid format\n";
+
+ my ($etc_passwd, $etc_group) = @{
+ PVE::Tools::run_fork(sub {
+ # Prevent symlinks from escaping out of container rootdir
+ chroot($rootdir) or die "failed to change root to: $rootdir: $!\n";
+ chdir('/') or die "failed to change to root directory\n";
+ my $etc_passwd = abs_path('/etc/passwd')
+ or die "cannot resolve /etc/passwd path in container rootfs\n";
+ my $etc_group = abs_path('/etc/group')
+ or die "cannot resolve /etc/group path in container rootfs\n";
+
+ return [$rootdir . $etc_passwd, $rootdir . $etc_group];
+ })
+ };
+
+ # Scan file, match column $match_index against $match_val, return value at $ret_index
+ my $lookup_field = sub {
+ my ($file, $match_index, $match_val, $ret_index) = @_;
+
+ open(my $fh, '<', $file) or return undef;
+ while (my $line = <$fh>) {
+ chomp $line;
+ my @fields = split(/:/, $line);
+ if (defined($fields[$match_index]) && $fields[$match_index] eq $match_val) {
+ return $fields[$ret_index];
+ }
+ }
+ return undef;
+ };
+
+ my $get_supplementary_groups = sub {
+ my ($username) = @_;
+
+ my @groups;
+ open(my $fh, '<', $etc_group) or return undef;
+ while (my $line = <$fh>) {
+ chomp $line;
+ my (undef, undef, $gid, $user_list) = split(/:/, $line);
+ next if !defined($gid) || !defined($user_list);
+ my @users = split(/,/, $user_list);
+ push @groups, $gid if grep { $_ eq $username } @users;
+ }
+ return join(',', @groups);
+ };
+
+ my ($uid, $username, $gid, $groups);
+
+ if ($user =~ /^\d+$/) {
+ $uid = $user;
+ $username = $lookup_field->($etc_passwd, 2, $uid, 0);
+ } else {
+ $username = $user;
+ $uid = $lookup_field->($etc_passwd, 0, $username, 2);
+ }
+
+ if (defined($group)) {
+ if ($group =~ /^\d+$/) {
+ $gid = $group;
+ } else {
+ $gid = $lookup_field->($etc_group, 0, $group, 2);
+ }
+ } else {
+ $gid = $lookup_field->($etc_passwd, 2, $uid, 3) if defined($uid);
+ $groups = $get_supplementary_groups->($username) if defined($username);
+ }
+
+ return ($uid, $gid, $groups);
+}
+
1;
--
2.47.3
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-01-21 16:02 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-21 16:00 [pve-devel] [PATCH container v2 0/2] oci create: honor `User` from OCI image config Filip Schauer
2026-01-21 16:00 ` [pve-devel] [PATCH container v2 1/2] config: add `lxc.init.uid`/`gid`/`groups` keys Filip Schauer
2026-01-21 16:00 ` [pve-devel] [PATCH container v2 2/2] oci create: honor User from OCI image config Filip Schauer
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.