@@ -28,11 +28,13 @@ import (
2828 "syscall"
2929 "time"
3030
31+ "github.com/containerd/containerd"
3132 "github.com/containerd/containerd/log"
3233 "github.com/containerd/containerd/mount"
3334 "github.com/containerd/containerd/pkg/apparmor"
3435 "github.com/containerd/containerd/pkg/seccomp"
3536 "github.com/containerd/containerd/pkg/seutil"
37+ "github.com/containerd/containerd/snapshots"
3638 "github.com/moby/sys/mountinfo"
3739 "github.com/opencontainers/runtime-spec/specs-go"
3840 "github.com/opencontainers/selinux/go-selinux/label"
@@ -275,3 +277,92 @@ func modifyProcessLabel(runtimeType string, spec *specs.Spec) error {
275277 spec .Process .SelinuxLabel = l
276278 return nil
277279}
280+
281+ func parseUsernsIDMap (runtimeIDMap []* runtime.IDMapping ) ([]specs.LinuxIDMapping , error ) {
282+ var m []specs.LinuxIDMapping
283+
284+ if len (runtimeIDMap ) == 0 {
285+ return m , nil
286+ }
287+
288+ if len (runtimeIDMap ) > 1 {
289+ // We only accept 1 line, because containerd.WithRemappedSnapshot() only supports that.
290+ return m , fmt .Errorf ("only one mapping line supported, got %v mapping lines" , len (runtimeIDMap ))
291+ }
292+
293+ // We know len is 1 now.
294+ if runtimeIDMap [0 ] == nil {
295+ return m , nil
296+ }
297+ uidMap := * runtimeIDMap [0 ]
298+
299+ if uidMap .Length < 1 {
300+ return m , fmt .Errorf ("invalid mapping length: %v" , uidMap .Length )
301+ }
302+
303+ m = []specs.LinuxIDMapping {
304+ {
305+ ContainerID : uidMap .ContainerId ,
306+ HostID : uidMap .HostId ,
307+ Size : uidMap .Length ,
308+ },
309+ }
310+
311+ return m , nil
312+ }
313+
314+ func parseUsernsIDs (userns * runtime.UserNamespace ) (uids , gids []specs.LinuxIDMapping , retErr error ) {
315+ if userns == nil {
316+ // If userns is not set, the kubelet doesn't support this option
317+ // and we should just fallback to no userns. This is completely
318+ // valid.
319+ return nil , nil , nil
320+ }
321+
322+ uidRuntimeMap := userns .GetUids ()
323+ gidRuntimeMap := userns .GetGids ()
324+
325+ uids , err := parseUsernsIDMap (uidRuntimeMap )
326+ if err != nil {
327+ return nil , nil , fmt .Errorf ("UID mapping: %w" , err )
328+ }
329+
330+ gids , err = parseUsernsIDMap (gidRuntimeMap )
331+ if err != nil {
332+ return nil , nil , fmt .Errorf ("GID mapping: %w" , err )
333+ }
334+
335+ switch mode := userns .GetMode (); mode {
336+ case runtime .NamespaceMode_NODE :
337+ if len (uids ) != 0 || len (gids ) != 0 {
338+ return nil , nil , fmt .Errorf ("can't use user namespace mode %q with mappings. Got %v UID mappings and %v GID mappings" , mode , len (uids ), len (gids ))
339+ }
340+ case runtime .NamespaceMode_POD :
341+ // This is valid, we will handle it in WithPodNamespaces().
342+ if len (uids ) == 0 || len (gids ) == 0 {
343+ return nil , nil , fmt .Errorf ("can't use user namespace mode %q without UID and GID mappings" , mode )
344+ }
345+ default :
346+ return nil , nil , fmt .Errorf ("unsupported user namespace mode: %q" , mode )
347+ }
348+
349+ return uids , gids , nil
350+ }
351+
352+ func snapshotterRemapOpts (nsOpts * runtime.NamespaceOption ) ([]snapshots.Opt , error ) {
353+ snapshotOpt := []snapshots.Opt {}
354+ usernsOpts := nsOpts .GetUsernsOptions ()
355+ if usernsOpts == nil {
356+ return snapshotOpt , nil
357+ }
358+
359+ uids , gids , err := parseUsernsIDs (usernsOpts )
360+ if err != nil {
361+ return nil , fmt .Errorf ("user namespace configuration: %w" , err )
362+ }
363+
364+ if usernsOpts .GetMode () == runtime .NamespaceMode_POD {
365+ snapshotOpt = append (snapshotOpt , containerd .WithRemapperLabels (0 , uids [0 ].HostID , 0 , gids [0 ].HostID , uids [0 ].Size ))
366+ }
367+ return snapshotOpt , nil
368+ }
0 commit comments