diff --git a/pkg/sentry/control/lifecycle.go b/pkg/sentry/control/lifecycle.go index 56eb3d2c5..0ad94378b 100644 --- a/pkg/sentry/control/lifecycle.go +++ b/pkg/sentry/control/lifecycle.go @@ -114,6 +114,9 @@ type StartContainerArgs struct { // ContainerID is the container for the process being executed. ContainerID string `json:"container_id"` + // InitialCgroups is the set of cgroup controllers container needs to be initialised to. + InitialCgroups map[kernel.CgroupControllerType]string `json:"initial_cgroups"` + // Limits is the limit set for the process being executed. Limits map[string]limits.Limit `json:"limits"` @@ -294,6 +297,18 @@ func (l *Lifecycle) StartContainer(args *StartContainerArgs, _ *uint32) error { } }() + initialCgroups := make(map[kernel.Cgroup]struct{}, len(args.InitialCgroups)) + cgroupRegistry := l.Kernel.CgroupRegistry() + // path is relative to the container's cgroup controller of specified type. + for initialCgroupController, path := range args.InitialCgroups { + cg, err := cgroupRegistry.FindCgroup(ctx, initialCgroupController, path) + if err != nil { + return fmt.Errorf("FindCgroup can't locate cgroup controller: %v err: %v", initialCgroupController, err) + } + initialCgroups[cg] = struct{}{} + } + initArgs.InitialCgroups = initialCgroups + tg, _, err := l.Kernel.CreateProcess(initArgs) if err != nil { return err diff --git a/pkg/sentry/kernel/kernel.go b/pkg/sentry/kernel/kernel.go index e6ce47083..c41cd69f0 100644 --- a/pkg/sentry/kernel/kernel.go +++ b/pkg/sentry/kernel/kernel.go @@ -716,6 +716,9 @@ type CreateProcessArgs struct { // ContainerID is the container that the process belongs to. ContainerID string + + // InitialCgroups are the cgroups the container is initialized to. + InitialCgroups map[Cgroup]struct{} } // NewContext returns a context.Context that represents the task that will be @@ -911,6 +914,7 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID, AbstractSocketNamespace: args.AbstractSocketNamespace, MountNamespace: mntns, ContainerID: args.ContainerID, + InitialCgroups: args.InitialCgroups, UserCounters: k.GetUserCounters(args.Credentials.RealKUID), } config.NetworkNamespace.IncRef() diff --git a/pkg/sentry/kernel/task_cgroup.go b/pkg/sentry/kernel/task_cgroup.go index 37084e7d9..ca577061d 100644 --- a/pkg/sentry/kernel/task_cgroup.go +++ b/pkg/sentry/kernel/task_cgroup.go @@ -25,13 +25,18 @@ import ( ) // EnterInitialCgroups moves t into an initial set of cgroups. +// If initCgroups is not nil, the new task will be placed in the specified cgroups. +// Otherwise, if parent is not nil, the new task will be placed in the parent's cgroups. +// If neither is specified, the new task will be in the root cgroups. // // This is analogous to Linux's kernel/cgroup/cgroup.c:cgroup_css_set_fork(). // // Precondition: t isn't in any cgroups yet, t.cgroups is empty. -func (t *Task) EnterInitialCgroups(parent *Task) { +func (t *Task) EnterInitialCgroups(parent *Task, initCgroups map[Cgroup]struct{}) { var inherit map[Cgroup]struct{} - if parent != nil { + if initCgroups != nil { + inherit = initCgroups + } else if parent != nil { parent.mu.Lock() defer parent.mu.Unlock() inherit = parent.cgroups diff --git a/pkg/sentry/kernel/task_start.go b/pkg/sentry/kernel/task_start.go index f8a525bcb..ae8f70ad9 100644 --- a/pkg/sentry/kernel/task_start.go +++ b/pkg/sentry/kernel/task_start.go @@ -97,6 +97,9 @@ type TaskConfig struct { // ContainerID is the container the new task belongs to. ContainerID string + // InitialCgroups are the cgroups the container is initialised to. + InitialCgroups map[Cgroup]struct{} + // UserCounters is user resource counters. UserCounters *userCounters } @@ -237,8 +240,11 @@ func (ts *TaskSet) newTask(ctx context.Context, cfg *TaskConfig) (*Task, error) t.parent.children[t] = struct{}{} } - // srcT may be nil, in which case we default to root cgroups. - t.EnterInitialCgroups(srcT) + // If InitialCgroups is not nil, the new task will be placed in the + // specified cgroups. Otherwise, if srcT is not nil, the new task will + // be placed in the srcT's cgroups. If neither is specified, the new task + // will be in the root cgroups. + t.EnterInitialCgroups(srcT, cfg.InitialCgroups) committed = true if tg.leader == nil {