podman: add uid and gid options to keep-id

add two new options to the keep-id user namespace option:

- uid: allow to override the UID used inside the container.
- gid: allow to override the GID used inside the container.

For example, the following command will map the rootless user (that
has UID=0 inside the rootless user namespace) to the UID=11 inside the
container user namespace:

$ podman run --userns=keep-id:uid=11 --rm -ti  fedora cat /proc/self/uid_map
         0          1         11
        11          0          1
        12         12      65525

Closes: https://github.com/containers/podman/issues/15294

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
Giuseppe Scrivano
2022-08-19 15:15:47 +02:00
parent cd62606046
commit e015c9e3f7
8 changed files with 103 additions and 5 deletions

View File

@ -21,6 +21,14 @@ const (
slirpType = "slirp4netns"
)
// KeepIDUserNsOptions defines how to keepIDmatically create a user namespace.
type KeepIDUserNsOptions struct {
// UID is the target uid in the user namespace.
UID *uint32
// GID is the target uid in the user namespace.
GID *uint32
}
// CgroupMode represents cgroup mode in the container.
type CgroupMode string
@ -93,7 +101,8 @@ func (n UsernsMode) IsHost() bool {
// IsKeepID indicates whether container uses a mapping where the (uid, gid) on the host is kept inside of the namespace.
func (n UsernsMode) IsKeepID() bool {
return n == "keep-id"
parts := strings.Split(string(n), ":")
return parts[0] == "keep-id"
}
// IsNoMap indicates whether container uses a mapping where the (uid, gid) on the host is not present in the namespace.
@ -154,6 +163,44 @@ func (n UsernsMode) GetAutoOptions() (*types.AutoUserNsOptions, error) {
return &options, nil
}
// GetKeepIDOptions returns a KeepIDUserNsOptions with the settings to keepIDmatically set up
// a user namespace.
func (n UsernsMode) GetKeepIDOptions() (*KeepIDUserNsOptions, error) {
parts := strings.SplitN(string(n), ":", 2)
if parts[0] != "keep-id" {
return nil, fmt.Errorf("wrong user namespace mode")
}
options := KeepIDUserNsOptions{}
if len(parts) == 1 {
return &options, nil
}
for _, o := range strings.Split(parts[1], ",") {
v := strings.SplitN(o, "=", 2)
if len(v) != 2 {
return nil, fmt.Errorf("invalid option specified: %q", o)
}
switch v[0] {
case "uid":
s, err := strconv.ParseUint(v[1], 10, 32)
if err != nil {
return nil, err
}
v := uint32(s)
options.UID = &v
case "gid":
s, err := strconv.ParseUint(v[1], 10, 32)
if err != nil {
return nil, err
}
v := uint32(s)
options.GID = &v
default:
return nil, fmt.Errorf("unknown option specified: %q", v[0])
}
}
return &options, nil
}
// IsPrivate indicates whether the container uses the a private userns.
func (n UsernsMode) IsPrivate() bool {
return !(n.IsHost() || n.IsContainer())