Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for ID map mounts without userns #3943

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 3 additions & 30 deletions libcontainer/configs/validate/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func namespaces(config *configs.Config) error {
return errors.New("USER namespaces aren't enabled in the kernel")
}
} else {
if config.UIDMappings != nil || config.GIDMappings != nil {
if len(config.UIDMappings) != 0 || len(config.GIDMappings) != 0 {
return errors.New("User namespace mappings specified, but USER namespace isn't enabled in the config")
}
}
Expand Down Expand Up @@ -264,14 +264,8 @@ func checkIDMapMounts(config *configs.Config, m *configs.Mount) error {
if config.RootlessEUID {
return fmt.Errorf("gidMappings/uidMappings is not supported when runc is being launched with EUID != 0, needs CAP_SYS_ADMIN on the runc parent's user namespace")
}
if len(config.UIDMappings) == 0 || len(config.GIDMappings) == 0 {
return fmt.Errorf("not yet supported to use gidMappings/uidMappings in a mount without also using a user namespace")
}
if !sameMapping(config.UIDMappings, m.UIDMappings) {
return fmt.Errorf("not yet supported for the mount uidMappings to be different than user namespace uidMapping")
}
if !sameMapping(config.GIDMappings, m.GIDMappings) {
return fmt.Errorf("not yet supported for the mount gidMappings to be different than user namespace gidMapping")
if len(m.UIDMappings) == 0 || len(m.GIDMappings) == 0 {
return fmt.Errorf("id map mount without UID/GID mappings")
}
if !filepath.IsAbs(m.Source) {
return fmt.Errorf("mount source not absolute")
Expand All @@ -298,27 +292,6 @@ func mounts(config *configs.Config) error {
return nil
}

// sameMapping checks if the mappings are the same. If the mappings are the same
// but in different order, it returns false.
func sameMapping(a, b []configs.IDMap) bool {
if len(a) != len(b) {
return false
}

for i := range a {
if a[i].ContainerID != b[i].ContainerID {
return false
}
if a[i].HostID != b[i].HostID {
return false
}
if a[i].Size != b[i].Size {
return false
}
}
return true
}

func isHostNetNS(path string) (bool, error) {
const currentProcessNetns = "/proc/self/ns/net"

Expand Down
9 changes: 3 additions & 6 deletions libcontainer/configs/validate/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -436,8 +436,7 @@ func TestValidateIDMapMounts(t *testing.T) {
},
},
{
name: "idmap mount without userns mappings",
isErr: true,
name: "idmap mount without userns mappings",
config: &configs.Config{
Mounts: []*configs.Mount{
{
Expand All @@ -451,8 +450,7 @@ func TestValidateIDMapMounts(t *testing.T) {
},
},
{
name: "idmap mounts with different userns and mount mappings",
isErr: true,
name: "idmap mounts with different userns and mount mappings",
config: &configs.Config{
UIDMappings: mapping,
GIDMappings: mapping,
Expand All @@ -474,8 +472,7 @@ func TestValidateIDMapMounts(t *testing.T) {
},
},
{
name: "idmap mounts with different userns and mount mappings",
isErr: true,
name: "idmap mounts with different userns and mount mappings",
config: &configs.Config{
UIDMappings: mapping,
GIDMappings: mapping,
Expand Down
32 changes: 27 additions & 5 deletions libcontainer/container_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -558,11 +558,6 @@ func (c *Container) shouldSendIdmapSources() bool {
return false
}

// For the time being we require userns to be in use.
if !c.config.Namespaces.Contains(configs.NEWUSER) {
return false
}

// We need to send sources if there are idmap bind-mounts.
for _, m := range c.config.Mounts {
if m.IsBind() && m.IsIDMapped() {
Expand Down Expand Up @@ -2301,6 +2296,9 @@ func (c *Container) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Namespa
// Idmap mount sources to open.
if it == initStandard && c.shouldSendIdmapSources() {
var mounts []byte
var uidmaps []byte
var gidmaps []byte

for _, m := range c.config.Mounts {
if m.IsBind() && m.IsIDMapped() {
// While other parts of the code check this too (like
Expand All @@ -2310,11 +2308,35 @@ func (c *Container) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Namespa
return nil, fmt.Errorf("mount source string contains null byte: %q", m.Source)
}

uidBytes, err := encodeIDMapping(m.UIDMappings)
if err != nil {
return nil, err
}
gidBytes, err := encodeIDMapping(m.GIDMappings)
if err != nil {
return nil, err
}

uidmaps = append(uidmaps, uidBytes...)
gidmaps = append(gidmaps, gidBytes...)
mounts = append(mounts, []byte(m.Source)...)
}

uidmaps = append(uidmaps, byte(0))
gidmaps = append(gidmaps, byte(0))
mounts = append(mounts, byte(0))
}

r.AddData(&Bytemsg{
Type: IdmapUidmapAttr,
Value: uidmaps,
})

r.AddData(&Bytemsg{
Type: IdmapGidmapAttr,
Value: gidmaps,
})

r.AddData(&Bytemsg{
Type: IdmapSourcesAttr,
Value: mounts,
Expand Down
2 changes: 2 additions & 0 deletions libcontainer/message_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ const (
GidmapPathAttr uint16 = 27289
MountSourcesAttr uint16 = 27290
IdmapSourcesAttr uint16 = 27291
IdmapUidmapAttr uint16 = 27292
IdmapGidmapAttr uint16 = 27293
)

type Int32msg struct {
Expand Down
Loading
Loading