summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/apparmor/apparmor_linux.go13
-rw-r--r--pkg/spec/spec.go34
-rw-r--r--pkg/trust/trust.go122
-rw-r--r--pkg/util/utils.go44
-rw-r--r--pkg/varlinkapi/containers.go17
-rw-r--r--pkg/varlinkapi/containers_create.go2
-rw-r--r--pkg/varlinkapi/images.go33
-rw-r--r--pkg/varlinkapi/mount.go4
-rw-r--r--pkg/varlinkapi/transfers.go75
9 files changed, 199 insertions, 145 deletions
diff --git a/pkg/apparmor/apparmor_linux.go b/pkg/apparmor/apparmor_linux.go
index 0787b3fa5..2c5022c1f 100644
--- a/pkg/apparmor/apparmor_linux.go
+++ b/pkg/apparmor/apparmor_linux.go
@@ -214,8 +214,15 @@ func CheckProfileAndLoadDefault(name string) (string, error) {
return name, nil
}
- if name != "" && rootless.IsRootless() {
- return "", errors.Wrapf(ErrApparmorRootless, "cannot load AppArmor profile %q", name)
+ // AppArmor is not supported in rootless mode as it requires root
+ // privileges. Return an error in case a specific profile is specified.
+ if rootless.IsRootless() {
+ if name != "" {
+ return "", errors.Wrapf(ErrApparmorRootless, "cannot load AppArmor profile %q", name)
+ } else {
+ logrus.Debug("skipping loading default AppArmor profile (rootless mode)")
+ return "", nil
+ }
}
if name != "" && !runcaa.IsEnabled() {
@@ -230,7 +237,7 @@ func CheckProfileAndLoadDefault(name string) (string, error) {
return "", err
}
if !isLoaded {
- return "", fmt.Errorf("AppArmor profile %q specified but not loaded")
+ return "", fmt.Errorf("AppArmor profile %q specified but not loaded", name)
}
return name, nil
}
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
index 46105af4a..76b8963ff 100644
--- a/pkg/spec/spec.go
+++ b/pkg/spec/spec.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/storage/pkg/mount"
"github.com/docker/docker/daemon/caps"
"github.com/docker/go-units"
+ "github.com/opencontainers/runc/libcontainer/user"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/pkg/errors"
@@ -45,6 +46,18 @@ func supercedeUserMounts(mounts []spec.Mount, configMount []spec.Mount) []spec.M
return configMount
}
+func getAvailableGids() (int64, error) {
+ idMap, err := user.ParseIDMapFile("/proc/self/gid_map")
+ if err != nil {
+ return 0, err
+ }
+ count := int64(0)
+ for _, r := range idMap {
+ count += r.Count
+ }
+ return count, nil
+}
+
// CreateConfigToOCISpec parses information needed to create a container into an OCI runtime spec
func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint
cgroupPerm := "ro"
@@ -91,14 +104,21 @@ func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint
g.AddMount(sysMnt)
}
if isRootless {
- g.RemoveMount("/dev/pts")
- devPts := spec.Mount{
- Destination: "/dev/pts",
- Type: "devpts",
- Source: "devpts",
- Options: []string{"rprivate", "nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620"},
+ nGids, err := getAvailableGids()
+ if err != nil {
+ return nil, err
+ }
+ if nGids < 5 {
+ // If we have no GID mappings, the gid=5 default option would fail, so drop it.
+ g.RemoveMount("/dev/pts")
+ devPts := spec.Mount{
+ Destination: "/dev/pts",
+ Type: "devpts",
+ Source: "devpts",
+ Options: []string{"rprivate", "nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620"},
+ }
+ g.AddMount(devPts)
}
- g.AddMount(devPts)
}
if inUserNS && config.IpcMode.IsHost() {
g.RemoveMount("/dev/mqueue")
diff --git a/pkg/trust/trust.go b/pkg/trust/trust.go
index 31e41903e..9a75474ae 100644
--- a/pkg/trust/trust.go
+++ b/pkg/trust/trust.go
@@ -175,43 +175,30 @@ func CreateTmpFile(dir, pattern string, content []byte) (string, error) {
return tmpfile.Name(), nil
}
-func getGPGIdFromKeyPath(path []string) []string {
- var uids []string
- for _, k := range path {
- cmd := exec.Command("gpg2", "--with-colons", k)
- results, err := cmd.Output()
- if err != nil {
- logrus.Warnf("error get key identity: %s", err)
- continue
- }
- uids = append(uids, parseUids(results)...)
+// GetGPGIdFromKeyPath return user keyring from key path
+func GetGPGIdFromKeyPath(path string) []string {
+ cmd := exec.Command("gpg2", "--with-colons", path)
+ results, err := cmd.Output()
+ if err != nil {
+ logrus.Errorf("error getting key identity: %s", err)
+ return nil
}
- return uids
+ return parseUids(results)
}
-func getGPGIdFromKeyData(keys []string) []string {
- var uids []string
- for _, k := range keys {
- decodeKey, err := base64.StdEncoding.DecodeString(k)
- if err != nil {
- logrus.Warnf("error decoding key data")
- continue
- }
- tmpfileName, err := CreateTmpFile("", "", decodeKey)
- if err != nil {
- logrus.Warnf("error creating key date temp file %s", err)
- }
- defer os.Remove(tmpfileName)
- k = tmpfileName
- cmd := exec.Command("gpg2", "--with-colons", k)
- results, err := cmd.Output()
- if err != nil {
- logrus.Warnf("error get key identity: %s", err)
- continue
- }
- uids = append(uids, parseUids(results)...)
+// GetGPGIdFromKeyData return user keyring from keydata
+func GetGPGIdFromKeyData(key string) []string {
+ decodeKey, err := base64.StdEncoding.DecodeString(key)
+ if err != nil {
+ logrus.Errorf("%s, error decoding key data", err)
+ return nil
}
- return uids
+ tmpfileName, err := CreateTmpFile("", "", decodeKey)
+ if err != nil {
+ logrus.Errorf("error creating key date temp file %s", err)
+ }
+ defer os.Remove(tmpfileName)
+ return GetGPGIdFromKeyPath(tmpfileName)
}
func parseUids(colonDelimitKeys []byte) []string {
@@ -234,68 +221,15 @@ func parseUids(colonDelimitKeys []byte) []string {
return parseduids
}
-var typeDescription = map[string]string{"insecureAcceptAnything": "accept", "signedBy": "signed", "reject": "reject"}
-
-func trustTypeDescription(trustType string) string {
- trustDescription, exist := typeDescription[trustType]
- if !exist {
- logrus.Warnf("invalid trust type %s", trustType)
- }
- return trustDescription
-}
-
-// GetPolicy return the struct to show policy.json in json format and a map (reponame, ShowOutput) pair for image trust show command
-func GetPolicy(policyContentStruct PolicyContent, systemRegistriesDirPath string) (map[string]map[string]interface{}, map[string]ShowOutput, error) {
- registryConfigs, err := LoadAndMergeConfig(systemRegistriesDirPath)
+// GetPolicy parse policy.json into PolicyContent struct
+func GetPolicy(policyPath string) (PolicyContent, error) {
+ var policyContentStruct PolicyContent
+ policyContent, err := ioutil.ReadFile(policyPath)
if err != nil {
- return nil, nil, err
+ return policyContentStruct, errors.Wrapf(err, "unable to read policy file %s", policyPath)
}
-
- trustShowOutputMap := make(map[string]ShowOutput)
- policyJSON := make(map[string]map[string]interface{})
- if len(policyContentStruct.Default) > 0 {
- policyJSON["* (default)"] = make(map[string]interface{})
- policyJSON["* (default)"]["type"] = policyContentStruct.Default[0].Type
-
- var defaultPolicyStruct ShowOutput
- defaultPolicyStruct.Repo = "default"
- defaultPolicyStruct.Trusttype = trustTypeDescription(policyContentStruct.Default[0].Type)
- trustShowOutputMap["* (default)"] = defaultPolicyStruct
- }
- for transname, transval := range policyContentStruct.Transports {
- for repo, repoval := range transval {
- tempTrustShowOutput := ShowOutput{
- Repo: repo,
- Trusttype: repoval[0].Type,
- }
- policyJSON[repo] = make(map[string]interface{})
- policyJSON[repo]["type"] = repoval[0].Type
- policyJSON[repo]["transport"] = transname
- keyDataArr := []string{}
- keyPathArr := []string{}
- keyarr := []string{}
- for _, repoele := range repoval {
- if len(repoele.KeyPath) > 0 {
- keyarr = append(keyarr, repoele.KeyPath)
- keyPathArr = append(keyPathArr, repoele.KeyPath)
- }
- if len(repoele.KeyData) > 0 {
- keyarr = append(keyarr, string(repoele.KeyData))
- keyDataArr = append(keyDataArr, string(repoele.KeyData))
- }
- }
- policyJSON[repo]["keys"] = keyarr
- uids := append(getGPGIdFromKeyPath(keyPathArr), getGPGIdFromKeyData(keyDataArr)...)
- tempTrustShowOutput.GPGid = strings.Join(uids, ",")
-
- policyJSON[repo]["sigstore"] = ""
- registryNamespace := HaveMatchRegistry(repo, registryConfigs)
- if registryNamespace != nil {
- policyJSON[repo]["sigstore"] = registryNamespace.SigStore
- tempTrustShowOutput.Sigstore = registryNamespace.SigStore
- }
- trustShowOutputMap[repo] = tempTrustShowOutput
- }
+ if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil {
+ return policyContentStruct, errors.Wrapf(err, "could not parse trust policies")
}
- return policyJSON, trustShowOutputMap, nil
+ return policyContentStruct, nil
}
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index e0b94b011..52f431881 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -301,36 +301,36 @@ func getTomlStorage(storeOptions *storage.StoreOptions) *tomlConfig {
// for the volume API
// It also returns the path where all named volumes will be created using the volume API
func GetDefaultStoreOptions() (storage.StoreOptions, string, error) {
+ var (
+ defaultRootlessRunRoot string
+ defaultRootlessGraphRoot string
+ err error
+ )
storageOpts := storage.DefaultStoreOptions
volumePath := "/var/lib/containers/storage"
+
if rootless.IsRootless() {
- var err error
storageOpts, err = GetRootlessStorageOpts()
if err != nil {
return storageOpts, volumePath, err
}
+
volumePath, err = GetRootlessVolumeInfo()
if err != nil {
return storageOpts, volumePath, err
}
+ }
- storageConf := StorageConfigFile()
- if _, err := os.Stat(storageConf); err == nil {
- defaultRootlessRunRoot := storageOpts.RunRoot
- defaultRootlessGraphRoot := storageOpts.GraphRoot
- storageOpts = storage.StoreOptions{}
- storage.ReloadConfigurationFile(storageConf, &storageOpts)
+ storageConf := StorageConfigFile()
+ if _, err = os.Stat(storageConf); err == nil {
+ defaultRootlessRunRoot = storageOpts.RunRoot
+ defaultRootlessGraphRoot = storageOpts.GraphRoot
+ storageOpts = storage.StoreOptions{}
+ storage.ReloadConfigurationFile(storageConf, &storageOpts)
+ }
- // If the file did not specify a graphroot or runroot,
- // set sane defaults so we don't try and use root-owned
- // directories
- if storageOpts.RunRoot == "" {
- storageOpts.RunRoot = defaultRootlessRunRoot
- }
- if storageOpts.GraphRoot == "" {
- storageOpts.GraphRoot = defaultRootlessGraphRoot
- }
- } else if os.IsNotExist(err) {
+ if rootless.IsRootless() {
+ if os.IsNotExist(err) {
os.MkdirAll(filepath.Dir(storageConf), 0755)
file, err := os.OpenFile(storageConf, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
if err != nil {
@@ -343,6 +343,16 @@ func GetDefaultStoreOptions() (storage.StoreOptions, string, error) {
if err := enc.Encode(tomlConfiguration); err != nil {
os.Remove(storageConf)
}
+ } else if err == nil {
+ // If the file did not specify a graphroot or runroot,
+ // set sane defaults so we don't try and use root-owned
+ // directories
+ if storageOpts.RunRoot == "" {
+ storageOpts.RunRoot = defaultRootlessRunRoot
+ }
+ if storageOpts.GraphRoot == "" {
+ storageOpts.GraphRoot = defaultRootlessGraphRoot
+ }
}
}
return storageOpts, volumePath, nil
diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go
index a01e3cc2b..737e2dd96 100644
--- a/pkg/varlinkapi/containers.go
+++ b/pkg/varlinkapi/containers.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "io/ioutil"
"os"
"syscall"
"time"
@@ -194,15 +195,25 @@ func (i *LibpodAPI) ListContainerChanges(call iopodman.VarlinkCall, name string)
}
// ExportContainer ...
-func (i *LibpodAPI) ExportContainer(call iopodman.VarlinkCall, name, path string) error {
+func (i *LibpodAPI) ExportContainer(call iopodman.VarlinkCall, name, outPath string) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
return call.ReplyContainerNotFound(name)
}
- if err := ctr.Export(path); err != nil {
+ outputFile, err := ioutil.TempFile("", "varlink_recv")
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+
+ defer outputFile.Close()
+ if outPath == "" {
+ outPath = outputFile.Name()
+ }
+ if err := ctr.Export(outPath); err != nil {
return call.ReplyErrorOccurred(err.Error())
}
- return call.ReplyExportContainer(path)
+ return call.ReplyExportContainer(outPath)
+
}
// GetContainerStats ...
diff --git a/pkg/varlinkapi/containers_create.go b/pkg/varlinkapi/containers_create.go
index d72eaeb18..cc707b11f 100644
--- a/pkg/varlinkapi/containers_create.go
+++ b/pkg/varlinkapi/containers_create.go
@@ -25,7 +25,7 @@ func (i *LibpodAPI) CreateContainer(call iopodman.VarlinkCall, config iopodman.C
rtc := i.Runtime.GetConfig()
ctx := getContext()
- newImage, err := i.Runtime.ImageRuntime().New(ctx, config.Image, rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false)
+ newImage, err := i.Runtime.ImageRuntime().New(ctx, config.Image, rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false, nil)
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index 744f031c0..5e0889645 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -500,7 +500,7 @@ func (i *LibpodAPI) Commit(call iopodman.VarlinkCall, name, imageName string, ch
}
// ImportImage imports an image from a tarball to the image store
-func (i *LibpodAPI) ImportImage(call iopodman.VarlinkCall, source, reference, message string, changes []string) error {
+func (i *LibpodAPI) ImportImage(call iopodman.VarlinkCall, source, reference, message string, changes []string, delete bool) error {
configChanges, err := util.GetImageConfig(changes)
if err != nil {
return call.ReplyErrorOccurred(err.Error())
@@ -516,6 +516,12 @@ func (i *LibpodAPI) ImportImage(call iopodman.VarlinkCall, source, reference, me
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
+ if delete {
+ if err := os.Remove(source); err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ }
+
return call.ReplyImportImage(newImage.ID())
}
@@ -573,7 +579,7 @@ func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string, certDir, c
}
imageID = newImage[0].ID()
} else {
- newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, signaturePolicy, "", nil, &dockerRegistryOptions, so, false)
+ newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, signaturePolicy, "", nil, &dockerRegistryOptions, so, false, nil)
if err != nil {
return call.ReplyErrorOccurred(fmt.Sprintf("unable to pull %s: %s", name, err.Error()))
}
@@ -610,15 +616,15 @@ func (i *LibpodAPI) ContainerRunlabel(call iopodman.VarlinkCall, input iopodman.
runLabel, imageName, err := shared.GetRunlabel(input.Label, input.Image, ctx, i.Runtime, input.Pull, input.Creds, dockerRegistryOptions, input.Authfile, input.SignaturePolicyPath, nil)
if err != nil {
- return err
+ return call.ReplyErrorOccurred(err.Error())
}
if runLabel == "" {
- return nil
+ return call.ReplyErrorOccurred(fmt.Sprintf("%s does not contain the label %s", input.Image, input.Label))
}
cmd, env, err := shared.GenerateRunlabelCommand(runLabel, imageName, input.Name, input.Opts, input.ExtraArgs)
if err != nil {
- return err
+ return call.ReplyErrorOccurred(err.Error())
}
if err := utils.ExecCmdWithStdStreams(stdIn, stdOut, stdErr, env, cmd[0], cmd[1:]...); err != nil {
return call.ReplyErrorOccurred(err.Error())
@@ -627,19 +633,10 @@ func (i *LibpodAPI) ContainerRunlabel(call iopodman.VarlinkCall, input iopodman.
}
// ImagesPrune ....
-func (i *LibpodAPI) ImagesPrune(call iopodman.VarlinkCall) error {
- var (
- pruned []string
- )
- pruneImages, err := i.Runtime.ImageRuntime().GetPruneImages()
+func (i *LibpodAPI) ImagesPrune(call iopodman.VarlinkCall, all bool) error {
+ prunedImages, err := i.Runtime.ImageRuntime().PruneImages(all)
if err != nil {
- return err
- }
- for _, i := range pruneImages {
- if err := i.Remove(true); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- pruned = append(pruned, i.ID())
+ return call.ReplyErrorOccurred(err.Error())
}
- return call.ReplyImagesPrune(pruned)
+ return call.ReplyImagesPrune(prunedImages)
}
diff --git a/pkg/varlinkapi/mount.go b/pkg/varlinkapi/mount.go
index 84e6b2709..3b4fe87e3 100644
--- a/pkg/varlinkapi/mount.go
+++ b/pkg/varlinkapi/mount.go
@@ -6,7 +6,7 @@ import (
// ListContainerMounts ...
func (i *LibpodAPI) ListContainerMounts(call iopodman.VarlinkCall) error {
- var mounts []string
+ mounts := make(map[string]string)
allContainers, err := i.Runtime.GetAllContainers()
if err != nil {
return call.ReplyErrorOccurred(err.Error())
@@ -17,7 +17,7 @@ func (i *LibpodAPI) ListContainerMounts(call iopodman.VarlinkCall) error {
return call.ReplyErrorOccurred(err.Error())
}
if mounted {
- mounts = append(mounts, mountPoint)
+ mounts[container.ID()] = mountPoint
}
}
return call.ReplyListContainerMounts(mounts)
diff --git a/pkg/varlinkapi/transfers.go b/pkg/varlinkapi/transfers.go
new file mode 100644
index 000000000..0cb7e5e2e
--- /dev/null
+++ b/pkg/varlinkapi/transfers.go
@@ -0,0 +1,75 @@
+package varlinkapi
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+
+ "github.com/containers/libpod/cmd/podman/varlink"
+)
+
+// SendFile allows a client to send a file to the varlink server
+func (i *LibpodAPI) SendFile(call iopodman.VarlinkCall, ftype string, length int64) error {
+ if !call.WantsUpgrade() {
+ return call.ReplyErrorOccurred("client must use upgraded connection to send files")
+ }
+
+ outputFile, err := ioutil.TempFile("", "varlink_send")
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ defer outputFile.Close()
+
+ if err = call.ReplySendFile(outputFile.Name()); err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+
+ writer := bufio.NewWriter(outputFile)
+ defer writer.Flush()
+
+ reader := call.Call.Reader
+ if _, err := io.CopyN(writer, reader, length); err != nil {
+ return err
+ }
+
+ // Send an ACK to the client
+ call.Call.Writer.WriteString(fmt.Sprintf("%s:", outputFile.Name()))
+ call.Call.Writer.Flush()
+ return nil
+
+}
+
+// ReceiveFile allows the varlink server to send a file to a client
+func (i *LibpodAPI) ReceiveFile(call iopodman.VarlinkCall, filepath string, delete bool) error {
+ if !call.WantsUpgrade() {
+ return call.ReplyErrorOccurred("client must use upgraded connection to send files")
+ }
+ fs, err := os.Open(filepath)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ fileInfo, err := fs.Stat()
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+
+ // Send the file length down to client
+ // Varlink connection upraded
+ if err = call.ReplyReceiveFile(fileInfo.Size()); err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+
+ reader := bufio.NewReader(fs)
+ _, err = reader.WriteTo(call.Writer)
+ if err != nil {
+ return err
+ }
+ if delete {
+ if err := os.Remove(filepath); err != nil {
+ return err
+ }
+ }
+ return call.Writer.Flush()
+}