github.com/containerd/Containerd@v1.4.13/container_opts_unix.go (about) 1 // +build !windows 2 3 /* 4 Copyright The containerd Authors. 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 */ 18 19 package containerd 20 21 import ( 22 "context" 23 "fmt" 24 "os" 25 "path/filepath" 26 "syscall" 27 28 "github.com/containerd/containerd/containers" 29 "github.com/containerd/containerd/errdefs" 30 "github.com/containerd/containerd/mount" 31 "github.com/opencontainers/image-spec/identity" 32 ) 33 34 // WithRemappedSnapshot creates a new snapshot and remaps the uid/gid for the 35 // filesystem to be used by a container with user namespaces 36 func WithRemappedSnapshot(id string, i Image, uid, gid uint32) NewContainerOpts { 37 return withRemappedSnapshotBase(id, i, uid, gid, false) 38 } 39 40 // WithRemappedSnapshotView is similar to WithRemappedSnapshot but rootfs is mounted as read-only. 41 func WithRemappedSnapshotView(id string, i Image, uid, gid uint32) NewContainerOpts { 42 return withRemappedSnapshotBase(id, i, uid, gid, true) 43 } 44 45 func withRemappedSnapshotBase(id string, i Image, uid, gid uint32, readonly bool) NewContainerOpts { 46 return func(ctx context.Context, client *Client, c *containers.Container) error { 47 diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), client.platform) 48 if err != nil { 49 return err 50 } 51 52 var ( 53 parent = identity.ChainID(diffIDs).String() 54 usernsID = fmt.Sprintf("%s-%d-%d", parent, uid, gid) 55 ) 56 c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter) 57 if err != nil { 58 return err 59 } 60 snapshotter, err := client.getSnapshotter(ctx, c.Snapshotter) 61 if err != nil { 62 return err 63 } 64 if _, err := snapshotter.Stat(ctx, usernsID); err == nil { 65 if _, err := snapshotter.Prepare(ctx, id, usernsID); err == nil { 66 c.SnapshotKey = id 67 c.Image = i.Name() 68 return nil 69 } else if !errdefs.IsNotFound(err) { 70 return err 71 } 72 } 73 mounts, err := snapshotter.Prepare(ctx, usernsID+"-remap", parent) 74 if err != nil { 75 return err 76 } 77 if err := remapRootFS(ctx, mounts, uid, gid); err != nil { 78 snapshotter.Remove(ctx, usernsID) 79 return err 80 } 81 if err := snapshotter.Commit(ctx, usernsID, usernsID+"-remap"); err != nil { 82 return err 83 } 84 if readonly { 85 _, err = snapshotter.View(ctx, id, usernsID) 86 } else { 87 _, err = snapshotter.Prepare(ctx, id, usernsID) 88 } 89 if err != nil { 90 return err 91 } 92 c.SnapshotKey = id 93 c.Image = i.Name() 94 return nil 95 } 96 } 97 98 func remapRootFS(ctx context.Context, mounts []mount.Mount, uid, gid uint32) error { 99 return mount.WithTempMount(ctx, mounts, func(root string) error { 100 return filepath.Walk(root, incrementFS(root, uid, gid)) 101 }) 102 } 103 104 func incrementFS(root string, uidInc, gidInc uint32) filepath.WalkFunc { 105 return func(path string, info os.FileInfo, err error) error { 106 if err != nil { 107 return err 108 } 109 var ( 110 stat = info.Sys().(*syscall.Stat_t) 111 u, g = int(stat.Uid + uidInc), int(stat.Gid + gidInc) 112 ) 113 // be sure the lchown the path as to not de-reference the symlink to a host file 114 return os.Lchown(path, u, g) 115 } 116 }