func (s *DockerSuite) TestInspectApiImageResponse(c *check.C) { dockerCmd(c, "tag", "busybox:latest", "busybox:mytag") endpoint := "/images/busybox/json" status, body, err := sockRequest("GET", endpoint, nil) c.Assert(err, checker.IsNil) c.Assert(status, checker.Equals, http.StatusOK) var imageJSON types.ImageInspect err = json.Unmarshal(body, &imageJSON) c.Assert(err, checker.IsNil, check.Commentf("Unable to unmarshal body for latest version")) c.Assert(imageJSON.RepoTags, checker.HasLen, 2) c.Assert(stringutils.InSlice(imageJSON.RepoTags, "busybox:latest"), checker.Equals, true) c.Assert(stringutils.InSlice(imageJSON.RepoTags, "busybox:mytag"), checker.Equals, true) }
func (s *DockerSuite) TestInspectApiImageResponse(c *check.C) { dockerCmd(c, "tag", "busybox:latest", "busybox:mytag") endpoint := "/images/busybox/json" status, body, err := sockRequest("GET", endpoint, nil) c.Assert(err, check.IsNil) c.Assert(status, check.Equals, http.StatusOK) var imageJSON types.ImageInspect if err = json.Unmarshal(body, &imageJSON); err != nil { c.Fatalf("unable to unmarshal body for latest version: %v", err) } c.Assert(len(imageJSON.Tags), check.Equals, 2) c.Assert(stringutils.InSlice(imageJSON.Tags, "busybox:latest"), check.Equals, true) c.Assert(stringutils.InSlice(imageJSON.Tags, "busybox:mytag"), check.Equals, true) }
func dropList(drops []string) ([]string, error) { if stringutils.InSlice(drops, "all") { var newCaps []string for _, capName := range execdriver.GetAllCapabilities() { cap := execdriver.GetCapability(capName) logrus.Debugf("drop cap %s\n", cap.Key) numCap := fmt.Sprintf("%d", cap.Value) newCaps = append(newCaps, numCap) } return newCaps, nil } return []string{}, nil }
// TweakCapabilities can tweak capabilities by adding or dropping capabilities // based on the basics capabilities. func TweakCapabilities(basics, adds, drops []string) ([]string, error) { var ( newCaps []string allCaps = GetAllCapabilities() ) // FIXME(tonistiigi): docker format is without CAP_ prefix, oci is with prefix // Currently they are mixed in here. We should do conversion in one place. // look for invalid cap in the drop list for _, cap := range drops { if strings.ToLower(cap) == "all" { continue } if !stringutils.InSlice(allCaps, "CAP_"+cap) { return nil, fmt.Errorf("Unknown capability drop: %q", cap) } } // handle --cap-add=all if stringutils.InSlice(adds, "all") { basics = allCaps } if !stringutils.InSlice(drops, "all") { for _, cap := range basics { // skip `all` already handled above if strings.ToLower(cap) == "all" { continue } // if we don't drop `all`, add back all the non-dropped caps if !stringutils.InSlice(drops, cap[4:]) { newCaps = append(newCaps, strings.ToUpper(cap)) } } } for _, cap := range adds { // skip `all` already handled above if strings.ToLower(cap) == "all" { continue } cap = "CAP_" + cap if !stringutils.InSlice(allCaps, cap) { return nil, fmt.Errorf("Unknown capability to add: %q", cap) } // add cap if not already in the list if !stringutils.InSlice(newCaps, cap) { newCaps = append(newCaps, strings.ToUpper(cap)) } } return newCaps, nil }
// TweakCapabilities can tweak capabilities by adding or dropping capabilities // based on the basics capabilities. func TweakCapabilities(basics, adds, drops []string) ([]string, error) { var ( newCaps []string allCaps = GetAllCapabilities() ) // look for invalid cap in the drop list for _, cap := range drops { if strings.ToLower(cap) == "all" { continue } if !stringutils.InSlice(allCaps, cap) { return nil, fmt.Errorf("Unknown capability drop: %q", cap) } } // handle --cap-add=all if stringutils.InSlice(adds, "all") { basics = allCaps } if !stringutils.InSlice(drops, "all") { for _, cap := range basics { // skip `all` aready handled above if strings.ToLower(cap) == "all" { continue } // if we don't drop `all`, add back all the non-dropped caps if !stringutils.InSlice(drops, cap) { newCaps = append(newCaps, strings.ToUpper(cap)) } } } for _, cap := range adds { // skip `all` aready handled above if strings.ToLower(cap) == "all" { continue } if !stringutils.InSlice(allCaps, cap) { return nil, fmt.Errorf("Unknown capability to add: %q", cap) } // add cap if not already in the list if !stringutils.InSlice(newCaps, cap) { newCaps = append(newCaps, strings.ToUpper(cap)) } } return newCaps, nil }
func (s *DockerRegistrySuite) TestInspectImageWithDigests(c *check.C) { digest, err := setupImage(c) c.Assert(err, check.IsNil, check.Commentf("error setting up image")) imageReference := fmt.Sprintf("%s@%s", repoName, digest) // pull from the registry using the <name>@<digest> reference dockerCmd(c, "pull", imageReference) out, _ := dockerCmd(c, "inspect", imageReference) var imageJSON []types.ImageInspect err = json.Unmarshal([]byte(out), &imageJSON) c.Assert(err, checker.IsNil) c.Assert(imageJSON, checker.HasLen, 1) c.Assert(imageJSON[0].RepoDigests, checker.HasLen, 1) c.Assert(stringutils.InSlice(imageJSON[0].RepoDigests, imageReference), checker.Equals, true) }
func (s *DockerRegistrySuite) TestInspectImageWithDigests(c *check.C) { digest, err := setupImage(c) c.Assert(err, check.IsNil, check.Commentf("error setting up image: %v", err)) imageReference := fmt.Sprintf("%s@%s", repoName, digest) // pull from the registry using the <name>@<digest> reference dockerCmd(c, "pull", imageReference) out, _ := dockerCmd(c, "inspect", imageReference) var imageJSON []types.ImageInspect if err = json.Unmarshal([]byte(out), &imageJSON); err != nil { c.Fatalf("unable to unmarshal body for latest version: %v", err) } c.Assert(len(imageJSON), check.Equals, 1) c.Assert(len(imageJSON[0].RepoDigests), check.Equals, 1) c.Assert(stringutils.InSlice(imageJSON[0].RepoDigests, imageReference), check.Equals, true) }
func setMounts(daemon *Daemon, s *specs.Spec, c *container.Container, mounts []container.Mount) error { userMounts := make(map[string]struct{}) for _, m := range mounts { userMounts[m.Destination] = struct{}{} } // Filter out mounts that are overridden by user supplied mounts var defaultMounts []specs.Mount _, mountDev := userMounts["/dev"] for _, m := range s.Mounts { if _, ok := userMounts[m.Destination]; !ok { if mountDev && strings.HasPrefix(m.Destination, "/dev/") { continue } defaultMounts = append(defaultMounts, m) } } s.Mounts = defaultMounts for _, m := range mounts { for _, cm := range s.Mounts { if cm.Destination == m.Destination { return fmt.Errorf("Duplicate mount point '%s'", m.Destination) } } if m.Source == "tmpfs" { data := c.HostConfig.Tmpfs[m.Destination] options := []string{"noexec", "nosuid", "nodev", string(volume.DefaultPropagationMode)} if data != "" { options = append(options, strings.Split(data, ",")...) } merged, err := mount.MergeTmpfsOptions(options) if err != nil { return err } s.Mounts = append(s.Mounts, specs.Mount{Destination: m.Destination, Source: m.Source, Type: "tmpfs", Options: merged}) continue } mt := specs.Mount{Destination: m.Destination, Source: m.Source, Type: "bind"} // Determine property of RootPropagation based on volume // properties. If a volume is shared, then keep root propagation // shared. This should work for slave and private volumes too. // // For slave volumes, it can be either [r]shared/[r]slave. // // For private volumes any root propagation value should work. pFlag := mountPropagationMap[m.Propagation] if pFlag == mount.SHARED || pFlag == mount.RSHARED { if err := ensureShared(m.Source); err != nil { return err } rootpg := mountPropagationMap[s.Linux.RootfsPropagation] if rootpg != mount.SHARED && rootpg != mount.RSHARED { s.Linux.RootfsPropagation = mountPropagationReverseMap[mount.SHARED] } } else if pFlag == mount.SLAVE || pFlag == mount.RSLAVE { if err := ensureSharedOrSlave(m.Source); err != nil { return err } rootpg := mountPropagationMap[s.Linux.RootfsPropagation] if rootpg != mount.SHARED && rootpg != mount.RSHARED && rootpg != mount.SLAVE && rootpg != mount.RSLAVE { s.Linux.RootfsPropagation = mountPropagationReverseMap[mount.RSLAVE] } } opts := []string{"rbind"} if !m.Writable { opts = append(opts, "ro") } if pFlag != 0 { opts = append(opts, mountPropagationReverseMap[pFlag]) } mt.Options = opts s.Mounts = append(s.Mounts, mt) } if s.Root.Readonly { for i, m := range s.Mounts { switch m.Destination { case "/proc", "/dev/pts", "/dev/mqueue": // /dev is remounted by runc continue } if _, ok := userMounts[m.Destination]; !ok { if !stringutils.InSlice(m.Options, "ro") { s.Mounts[i].Options = append(s.Mounts[i].Options, "ro") } } } } if c.HostConfig.Privileged { if !s.Root.Readonly { // clear readonly for /sys for i := range s.Mounts { if s.Mounts[i].Destination == "/sys" { clearReadOnly(&s.Mounts[i]) } } } s.Linux.ReadonlyPaths = nil s.Linux.MaskedPaths = nil } // TODO: until a kernel/mount solution exists for handling remount in a user namespace, // we must clear the readonly flag for the cgroups mount (@mrunalp concurs) if uidMap, _ := daemon.GetUIDGIDMaps(); uidMap != nil || c.HostConfig.Privileged { for i, m := range s.Mounts { if m.Type == "cgroup" { clearReadOnly(&s.Mounts[i]) } } } return nil }
func setupSeccomp(config *types.Seccomp, rs *specs.Spec) (*specs.Seccomp, error) { if config == nil { return nil, nil } // No default action specified, no syscalls listed, assume seccomp disabled if config.DefaultAction == "" && len(config.Syscalls) == 0 { return nil, nil } newConfig := &specs.Seccomp{} var arch string var native, err = libseccomp.GetNativeArch() if err == nil { arch = native.String() } if len(config.Architectures) != 0 && len(config.ArchMap) != 0 { return nil, errors.New("'architectures' and 'archMap' were specified in the seccomp profile, use either 'architectures' or 'archMap'") } // if config.Architectures == 0 then libseccomp will figure out the architecture to use if len(config.Architectures) != 0 { for _, a := range config.Architectures { newConfig.Architectures = append(newConfig.Architectures, specs.Arch(a)) } } if len(config.ArchMap) != 0 { for _, a := range config.ArchMap { seccompArch, ok := nativeToSeccomp[arch] if ok { if a.Arch == seccompArch { newConfig.Architectures = append(newConfig.Architectures, specs.Arch(a.Arch)) for _, sa := range a.SubArches { newConfig.Architectures = append(newConfig.Architectures, specs.Arch(sa)) } break } } } } newConfig.DefaultAction = specs.Action(config.DefaultAction) Loop: // Loop through all syscall blocks and convert them to libcontainer format after filtering them for _, call := range config.Syscalls { if len(call.Excludes.Arches) > 0 { if stringutils.InSlice(call.Excludes.Arches, arch) { continue Loop } } if len(call.Excludes.Caps) > 0 { for _, c := range call.Excludes.Caps { if stringutils.InSlice(rs.Process.Capabilities, c) { continue Loop } } } if len(call.Includes.Arches) > 0 { if !stringutils.InSlice(call.Includes.Arches, arch) { continue Loop } } if len(call.Includes.Caps) > 0 { for _, c := range call.Includes.Caps { if !stringutils.InSlice(rs.Process.Capabilities, c) { continue Loop } } } if call.Name != "" && len(call.Names) != 0 { return nil, errors.New("'name' and 'names' were specified in the seccomp profile, use either 'name' or 'names'") } if call.Name != "" { newConfig.Syscalls = append(newConfig.Syscalls, createSpecsSyscall(call.Name, call.Action, call.Args)) } for _, n := range call.Names { newConfig.Syscalls = append(newConfig.Syscalls, createSpecsSyscall(n, call.Action, call.Args)) } } return newConfig, nil }