diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/api/handlers/libpod/manifests.go | 18 | ||||
-rw-r--r-- | pkg/api/server/register_manifest.go | 4 | ||||
-rw-r--r-- | pkg/bindings/containers/attach.go | 2 | ||||
-rw-r--r-- | pkg/bindings/containers/term_unix.go | 8 | ||||
-rw-r--r-- | pkg/bindings/containers/term_windows.go | 10 | ||||
-rw-r--r-- | pkg/bindings/test/images_test.go | 18 | ||||
-rw-r--r-- | pkg/bindings/test/secrets_test.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/abi/terminal/terminal_linux.go | 6 | ||||
-rw-r--r-- | pkg/domain/infra/runtime_libpod.go | 67 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/pods.go | 4 | ||||
-rw-r--r-- | pkg/machine/fcos.go | 4 | ||||
-rw-r--r-- | pkg/namespaces/namespaces.go | 7 | ||||
-rw-r--r-- | pkg/specgen/container_validate.go | 7 | ||||
-rw-r--r-- | pkg/specgen/generate/kube/kube.go | 6 | ||||
-rw-r--r-- | pkg/specgen/generate/namespaces.go | 26 | ||||
-rw-r--r-- | pkg/specgen/namespaces.go | 53 | ||||
-rw-r--r-- | pkg/systemd/dbus.go | 3 | ||||
-rw-r--r-- | pkg/terminal/util.go | 6 | ||||
-rw-r--r-- | pkg/util/utils.go | 109 |
19 files changed, 216 insertions, 144 deletions
diff --git a/pkg/api/handlers/libpod/manifests.go b/pkg/api/handlers/libpod/manifests.go index b823a56b6..15d4b9f89 100644 --- a/pkg/api/handlers/libpod/manifests.go +++ b/pkg/api/handlers/libpod/manifests.go @@ -100,10 +100,10 @@ func ManifestCreate(w http.ResponseWriter, r *http.Request) { // gather all images for manifest list var images []string if len(query.Images) > 0 { - images = append(query.Images) + images = query.Images } if len(body.Images) > 0 { - images = append(body.Images) + images = body.Images } id, err := imageEngine.ManifestAdd(r.Context(), query.Name, images, body.ManifestAddOptions) @@ -153,10 +153,10 @@ func ManifestInspect(w http.ResponseWriter, r *http.Request) { utils.WriteResponse(w, http.StatusOK, schema2List) } -// ManifestAdd remove digest from manifest list +// ManifestAddV3 remove digest from manifest list // -// Deprecated: As of 4.0.0 use ManifestModify instead -func ManifestAdd(w http.ResponseWriter, r *http.Request) { +// As of 4.0.0 use ManifestModify instead +func ManifestAddV3(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) // Wrapper to support 3.x with 4.x libpod @@ -206,10 +206,10 @@ func ManifestAdd(w http.ResponseWriter, r *http.Request) { utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: newID}) } -// ManifestRemoveDigest remove digest from manifest list +// ManifestRemoveDigestV3 remove digest from manifest list // -// Deprecated: As of 4.0.0 use ManifestModify instead -func ManifestRemoveDigest(w http.ResponseWriter, r *http.Request) { +// As of 4.0.0 use ManifestModify instead +func ManifestRemoveDigestV3(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder) query := struct { @@ -242,7 +242,7 @@ func ManifestRemoveDigest(w http.ResponseWriter, r *http.Request) { // ManifestPushV3 push image to registry // -// Deprecated: As of 4.0.0 use ManifestPush instead +// As of 4.0.0 use ManifestPush instead func ManifestPushV3(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder) diff --git a/pkg/api/server/register_manifest.go b/pkg/api/server/register_manifest.go index 58def109e..50a49bc1e 100644 --- a/pkg/api/server/register_manifest.go +++ b/pkg/api/server/register_manifest.go @@ -167,7 +167,7 @@ func (s *APIServer) registerManifestHandlers(r *mux.Router) error { // $ref: "#/responses/BadParamError" // 500: // $ref: "#/responses/InternalError" - v3.Handle("/{name:.*}/add", s.APIHandler(libpod.ManifestAdd)).Methods(http.MethodPost) + v3.Handle("/{name:.*}/add", s.APIHandler(libpod.ManifestAddV3)).Methods(http.MethodPost) // swagger:operation DELETE /libpod/manifests/{name} manifests ManifestDeleteV3Libpod // --- // summary: Remove image from a manifest list @@ -197,7 +197,7 @@ func (s *APIServer) registerManifestHandlers(r *mux.Router) error { // $ref: "#/responses/NoSuchManifest" // 500: // $ref: "#/responses/InternalError" - v3.Handle("/{name:.*}", s.APIHandler(libpod.ManifestRemoveDigest)).Methods(http.MethodDelete) + v3.Handle("/{name:.*}", s.APIHandler(libpod.ManifestRemoveDigestV3)).Methods(http.MethodDelete) // swagger:operation DELETE /libpod/manifests/{name} manifests ManifestDeleteLibpod // --- // summary: Delete manifest list diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go index 80702ea98..d84b47052 100644 --- a/pkg/bindings/containers/attach.go +++ b/pkg/bindings/containers/attach.go @@ -20,7 +20,7 @@ import ( "github.com/moby/term" "github.com/pkg/errors" "github.com/sirupsen/logrus" - "golang.org/x/crypto/ssh/terminal" + terminal "golang.org/x/term" ) // The CloseWriter interface is used to determine whether we can do a one-sided diff --git a/pkg/bindings/containers/term_unix.go b/pkg/bindings/containers/term_unix.go index 2c976393f..e14f50813 100644 --- a/pkg/bindings/containers/term_unix.go +++ b/pkg/bindings/containers/term_unix.go @@ -9,11 +9,11 @@ import ( "os/signal" sig "github.com/containers/podman/v4/pkg/signal" - "golang.org/x/crypto/ssh/terminal" + "golang.org/x/term" ) -func makeRawTerm(stdin *os.File) (*terminal.State, error) { - return terminal.MakeRaw(int(stdin.Fd())) +func makeRawTerm(stdin *os.File) (*term.State, error) { + return term.MakeRaw(int(stdin.Fd())) } func notifyWinChange(ctx context.Context, winChange chan os.Signal, stdin *os.File, stdout *os.File) { @@ -21,5 +21,5 @@ func notifyWinChange(ctx context.Context, winChange chan os.Signal, stdin *os.Fi } func getTermSize(stdin *os.File, stdout *os.File) (width, height int, err error) { - return terminal.GetSize(int(stdin.Fd())) + return term.GetSize(int(stdin.Fd())) } diff --git a/pkg/bindings/containers/term_windows.go b/pkg/bindings/containers/term_windows.go index 11d4bd50d..e710e2998 100644 --- a/pkg/bindings/containers/term_windows.go +++ b/pkg/bindings/containers/term_windows.go @@ -6,12 +6,12 @@ import ( "time" sig "github.com/containers/podman/v4/pkg/signal" - "golang.org/x/crypto/ssh/terminal" "golang.org/x/sys/windows" + "golang.org/x/term" ) -func makeRawTerm(stdin *os.File) (*terminal.State, error) { - state, err := terminal.MakeRaw(int(stdin.Fd())) +func makeRawTerm(stdin *os.File) (*term.State, error) { + state, err := term.MakeRaw(int(stdin.Fd())) if err != nil { return nil, err } @@ -51,7 +51,7 @@ func notifyWinChange(ctx context.Context, winChange chan os.Signal, stdin *os.Fi break } - w, h, err := terminal.GetSize(int(stdout.Fd())) + w, h, err := term.GetSize(int(stdout.Fd())) if err != nil { continue } @@ -65,5 +65,5 @@ func notifyWinChange(ctx context.Context, winChange chan os.Signal, stdin *os.Fi } func getTermSize(stdin *os.File, stdout *os.File) (width, height int, err error) { - return terminal.GetSize(int(stdout.Fd())) + return term.GetSize(int(stdout.Fd())) } diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go index d667a2dee..a005be6ac 100644 --- a/pkg/bindings/test/images_test.go +++ b/pkg/bindings/test/images_test.go @@ -103,7 +103,7 @@ var _ = Describe("Podman images", func() { Expect(len(errs)).To(BeZero()) Expect(inspectData.ID).To(Equal(response.Deleted[0])) - inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil) + _, err = images.GetImage(bt.conn, busybox.shortName, nil) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) @@ -118,7 +118,7 @@ var _ = Describe("Podman images", func() { // try to remove the image "alpine". This should fail since we are not force // deleting hence image cannot be deleted until the container is deleted. - response, errs = images.Remove(bt.conn, []string{alpine.shortName}, nil) + _, errs = images.Remove(bt.conn, []string{alpine.shortName}, nil) code, _ = bindings.CheckResponseCode(errs[0]) // FIXME FIXME FIXME: #12441: another invalid error // FIXME FIXME FIXME: this time msg="Image used by SHA: ..." @@ -126,7 +126,7 @@ var _ = Describe("Podman images", func() { // Removing the image "alpine" where force = true options := new(images.RemoveOptions).WithForce(true) - response, errs = images.Remove(bt.conn, []string{alpine.shortName}, options) + _, errs = images.Remove(bt.conn, []string{alpine.shortName}, options) Expect(errs).To(Or(HaveLen(0), BeNil())) // To be extra sure, check if the previously created container // is gone as well. @@ -135,11 +135,11 @@ var _ = Describe("Podman images", func() { Expect(code).To(BeNumerically("==", http.StatusNotFound)) // Now make sure both images are gone. - inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil) + _, err = images.GetImage(bt.conn, busybox.shortName, nil) code, _ = bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) - inspectData, err = images.GetImage(bt.conn, alpine.shortName, nil) + _, err = images.GetImage(bt.conn, alpine.shortName, nil) code, _ = bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) }) @@ -230,8 +230,8 @@ var _ = Describe("Podman images", func() { Expect(err).ToNot(HaveOccurred()) Expect(exists).To(BeFalse()) f, err := os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) - defer f.Close() Expect(err).ToNot(HaveOccurred()) + defer f.Close() names, err := images.Load(bt.conn, f) Expect(err).ToNot(HaveOccurred()) Expect(names.Names[0]).To(Equal(alpine.name)) @@ -252,8 +252,6 @@ var _ = Describe("Podman images", func() { Expect(names.Names[0]).To(Equal(alpine.name)) // load with a bad repo name should trigger a 500 - f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) - Expect(err).ToNot(HaveOccurred()) _, errs = images.Remove(bt.conn, []string{alpine.name}, nil) Expect(len(errs)).To(BeZero()) exists, err = images.Exists(bt.conn, alpine.name, nil) @@ -265,8 +263,8 @@ var _ = Describe("Podman images", func() { // Export an image exportPath := filepath.Join(bt.tempDirPath, alpine.tarballName) w, err := os.Create(filepath.Join(bt.tempDirPath, alpine.tarballName)) - defer w.Close() Expect(err).ToNot(HaveOccurred()) + defer w.Close() err = images.Export(bt.conn, []string{alpine.name}, w, nil) Expect(err).ToNot(HaveOccurred()) _, err = os.Stat(exportPath) @@ -283,8 +281,8 @@ var _ = Describe("Podman images", func() { Expect(err).ToNot(HaveOccurred()) Expect(exists).To(BeFalse()) f, err := os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) - defer f.Close() Expect(err).ToNot(HaveOccurred()) + defer f.Close() changes := []string{"CMD /bin/foobar"} testMessage := "test_import" options := new(images.ImportOptions).WithMessage(testMessage).WithChanges(changes).WithReference(alpine.name) diff --git a/pkg/bindings/test/secrets_test.go b/pkg/bindings/test/secrets_test.go index 377f49b2f..b4595f025 100644 --- a/pkg/bindings/test/secrets_test.go +++ b/pkg/bindings/test/secrets_test.go @@ -64,7 +64,7 @@ var _ = Describe("Podman secrets", func() { Expect(data.Spec.Name).To(Equal(name)) // inspecting non-existent secret should fail - data, err = secrets.Inspect(connText, "notasecret", nil) + _, err = secrets.Inspect(connText, "notasecret", nil) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) }) diff --git a/pkg/domain/infra/abi/terminal/terminal_linux.go b/pkg/domain/infra/abi/terminal/terminal_linux.go index 153b19fdb..62d36f28d 100644 --- a/pkg/domain/infra/abi/terminal/terminal_linux.go +++ b/pkg/domain/infra/abi/terminal/terminal_linux.go @@ -10,13 +10,13 @@ import ( "github.com/containers/podman/v4/libpod/define" "github.com/pkg/errors" "github.com/sirupsen/logrus" - "golang.org/x/crypto/ssh/terminal" + "golang.org/x/term" ) // ExecAttachCtr execs and attaches to a container func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, execConfig *libpod.ExecConfig, streams *define.AttachStreams) (int, error) { var resize chan define.TerminalSize - haveTerminal := terminal.IsTerminal(int(os.Stdin.Fd())) + haveTerminal := term.IsTerminal(int(os.Stdin.Fd())) // Check if we are attached to a terminal. If we are, generate resize // events, and set the terminal to raw mode @@ -42,7 +42,7 @@ func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, execConfig *libpo func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys string, sigProxy bool, startContainer bool) error { //nolint: interfacer resize := make(chan define.TerminalSize) - haveTerminal := terminal.IsTerminal(int(os.Stdin.Fd())) + haveTerminal := term.IsTerminal(int(os.Stdin.Fd())) // Check if we are attached to a terminal. If we are, generate resize // events, and set the terminal to raw mode diff --git a/pkg/domain/infra/runtime_libpod.go b/pkg/domain/infra/runtime_libpod.go index dffd90dbe..5fdc252e2 100644 --- a/pkg/domain/infra/runtime_libpod.go +++ b/pkg/domain/infra/runtime_libpod.go @@ -276,46 +276,47 @@ func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []strin if len(subUIDMap) > 0 || len(subGIDMap) > 0 { return nil, errors.New("cannot specify subuidmap or subgidmap with --userns=keep-id") } - if rootless.IsRootless() { - min := func(a, b int) int { - if a < b { - return a - } - return b + if !rootless.IsRootless() { + return nil, errors.New("keep-id is only supported in rootless mode") + } + min := func(a, b int) int { + if a < b { + return a } + return b + } - uid := rootless.GetRootlessUID() - gid := rootless.GetRootlessGID() - - uids, gids, err := rootless.GetConfiguredMappings() - if err != nil { - return nil, errors.Wrapf(err, "cannot read mappings") - } - maxUID, maxGID := 0, 0 - for _, u := range uids { - maxUID += u.Size - } - for _, g := range gids { - maxGID += g.Size - } + uid := rootless.GetRootlessUID() + gid := rootless.GetRootlessGID() - options.UIDMap, options.GIDMap = nil, nil + uids, gids, err := rootless.GetConfiguredMappings() + if err != nil { + return nil, errors.Wrapf(err, "cannot read mappings") + } + maxUID, maxGID := 0, 0 + for _, u := range uids { + maxUID += u.Size + } + for _, g := range gids { + maxGID += g.Size + } - options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(uid, maxUID)}) - options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid, HostID: 0, Size: 1}) - if maxUID > uid { - options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid + 1, HostID: uid + 1, Size: maxUID - uid}) - } + options.UIDMap, options.GIDMap = nil, nil - options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(gid, maxGID)}) - options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid, HostID: 0, Size: 1}) - if maxGID > gid { - options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid + 1, HostID: gid + 1, Size: maxGID - gid}) - } + options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(uid, maxUID)}) + options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid, HostID: 0, Size: 1}) + if maxUID > uid { + options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid + 1, HostID: uid + 1, Size: maxUID - uid}) + } - options.HostUIDMapping = false - options.HostGIDMapping = false + options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(gid, maxGID)}) + options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid, HostID: 0, Size: 1}) + if maxGID > gid { + options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid + 1, HostID: gid + 1, Size: maxGID - gid}) } + + options.HostUIDMapping = false + options.HostGIDMapping = false // Simply ignore the setting and do not setup an inner namespace for root as it is a no-op return &options, nil } diff --git a/pkg/domain/infra/tunnel/pods.go b/pkg/domain/infra/tunnel/pods.go index 4f44e7e4a..2dbdfcf80 100644 --- a/pkg/domain/infra/tunnel/pods.go +++ b/pkg/domain/infra/tunnel/pods.go @@ -42,14 +42,14 @@ func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, opt return reports, nil } -func (ic *ContainerEngine) PodLogs(_ context.Context, nameOrIDs string, options entities.PodLogsOptions) error { +func (ic *ContainerEngine) PodLogs(ctx context.Context, nameOrIDs string, options entities.PodLogsOptions) error { // PodLogsOptions are similar but contains few extra fields like ctrName // So cast other values as is so we can re-use the code containerLogsOpts := entities.PodLogsOptionsToContainerLogsOptions(options) // interface only accepts slice, keep everything consistent name := []string{options.ContainerName} - return ic.ContainerLogs(nil, name, containerLogsOpts) + return ic.ContainerLogs(ctx, name, containerLogsOpts) } func (ic *ContainerEngine) PodPause(ctx context.Context, namesOrIds []string, options entities.PodPauseOptions) ([]*entities.PodPauseReport, error) { diff --git a/pkg/machine/fcos.go b/pkg/machine/fcos.go index 6215ae08f..ad1be15c7 100644 --- a/pkg/machine/fcos.go +++ b/pkg/machine/fcos.go @@ -139,7 +139,7 @@ func getStreamURL(streamType string) url2.URL { // This should get Exported and stay put as it will apply to all fcos downloads // getFCOS parses fedoraCoreOS's stream and returns the image download URL and the release version -func getFCOSDownload(imageStream string) (*fcosDownloadInfo, error) { +func getFCOSDownload(imageStream string) (*fcosDownloadInfo, error) { // nolint:staticcheck var ( fcosstable stream.Stream altMeta release.Release @@ -149,6 +149,8 @@ func getFCOSDownload(imageStream string) (*fcosDownloadInfo, error) { // This is being hard set to testing. Once podman4 is in the // fcos trees, we should remove it and re-release at least on // macs. + // TODO: remove when podman4.0 is in coreos + // nolint:staticcheck imageStream = "podman-testing" switch imageStream { diff --git a/pkg/namespaces/namespaces.go b/pkg/namespaces/namespaces.go index a264a5a0f..bdea7c310 100644 --- a/pkg/namespaces/namespaces.go +++ b/pkg/namespaces/namespaces.go @@ -96,6 +96,11 @@ func (n UsernsMode) IsKeepID() bool { return n == "keep-id" } +// IsNoMap indicates whether container uses a mapping where the (uid, gid) on the host is not present in the namespace. +func (n UsernsMode) IsNoMap() bool { + return n == "nomap" +} + // IsAuto indicates whether container uses the "auto" userns mode. func (n UsernsMode) IsAuto() bool { parts := strings.Split(string(n), ":") @@ -158,7 +163,7 @@ func (n UsernsMode) IsPrivate() bool { func (n UsernsMode) Valid() bool { parts := strings.Split(string(n), ":") switch mode := parts[0]; mode { - case "", privateType, hostType, "keep-id", nsType, "auto": + case "", privateType, hostType, "keep-id", nsType, "auto", "nomap": case containerType: if len(parts) != 2 || parts[1] == "" { return false diff --git a/pkg/specgen/container_validate.go b/pkg/specgen/container_validate.go index 42b70e334..e06cd9a29 100644 --- a/pkg/specgen/container_validate.go +++ b/pkg/specgen/container_validate.go @@ -38,6 +38,13 @@ func (s *SpecGenerator) Validate() error { if len(s.PortMappings) > 0 || s.PublishExposedPorts { return errors.Wrap(define.ErrNetworkOnPodContainer, "published or exposed ports must be defined when the pod is created") } + if len(s.HostAdd) > 0 { + return errors.Wrap(define.ErrNetworkOnPodContainer, "extra host entries must be specified on the pod") + } + } + + if s.NetNS.IsContainer() && len(s.HostAdd) > 0 { + return errors.Wrap(ErrInvalidSpecConfig, "cannot set extra host entries when the container is joined to another containers network namespace") } // diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go index df751a780..51f9fa535 100644 --- a/pkg/specgen/generate/kube/kube.go +++ b/pkg/specgen/generate/kube/kube.go @@ -82,7 +82,7 @@ func ToPodOpt(ctx context.Context, podName string, p entities.PodCreateOptions, } // dns options if options := dnsConfig.Options; len(options) > 0 { - dnsOptions := make([]string, 0) + dnsOptions := make([]string, 0, len(options)) for _, opts := range options { d := opts.Name if opts.Value != nil { @@ -90,6 +90,7 @@ func ToPodOpt(ctx context.Context, podName string, p entities.PodCreateOptions, } dnsOptions = append(dnsOptions, d) } + p.Net.DNSOptions = dnsOptions } } return p, nil @@ -281,9 +282,6 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener annotations = opts.Annotations } if opts.PodInfraID != "" { - if annotations == nil { - - } annotations[ann.SandboxID] = opts.PodInfraID annotations[ann.ContainerType] = ann.ContainerTypeContainer } diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go index 05c2d1741..d8d1ae652 100644 --- a/pkg/specgen/generate/namespaces.go +++ b/pkg/specgen/generate/namespaces.go @@ -165,21 +165,19 @@ func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod. // User switch s.UserNS.NSMode { case specgen.KeepID: - if rootless.IsRootless() { - toReturn = append(toReturn, libpod.WithAddCurrentUserPasswdEntry()) - - // If user is not overridden, set user in the container - // to user running Podman. - if s.User == "" { - _, uid, gid, err := util.GetKeepIDMapping() - if err != nil { - return nil, err - } - toReturn = append(toReturn, libpod.WithUser(fmt.Sprintf("%d:%d", uid, gid))) + if !rootless.IsRootless() { + return nil, errors.New("keep-id is only supported in rootless mode") + } + toReturn = append(toReturn, libpod.WithAddCurrentUserPasswdEntry()) + + // If user is not overridden, set user in the container + // to user running Podman. + if s.User == "" { + _, uid, gid, err := util.GetKeepIDMapping() + if err != nil { + return nil, err } - } else { - // keep-id as root doesn't need a user namespace - s.UserNS.NSMode = specgen.Host + toReturn = append(toReturn, libpod.WithUser(fmt.Sprintf("%d:%d", uid, gid))) } case specgen.FromPod: if pod == nil || infraCtr == nil { diff --git a/pkg/specgen/namespaces.go b/pkg/specgen/namespaces.go index 4412eff29..eaf2daad9 100644 --- a/pkg/specgen/namespaces.go +++ b/pkg/specgen/namespaces.go @@ -55,6 +55,10 @@ const ( // of the namespace itself. // Only used with the user namespace, invalid otherwise. KeepID NamespaceMode = "keep-id" + // NoMap indicates a user namespace to keep the owner uid out + // of the namespace itself. + // Only used with the user namespace, invalid otherwise. + NoMap NamespaceMode = "no-map" // Auto indicates to automatically create a user namespace. // Only used with the user namespace, invalid otherwise. Auto NamespaceMode = "auto" @@ -121,6 +125,11 @@ func (n *Namespace) IsKeepID() bool { return n.NSMode == KeepID } +// IsNoMap indicates the namespace is NoMap +func (n *Namespace) IsNoMap() bool { + return n.NSMode == NoMap +} + func (n *Namespace) String() string { if n.Value != "" { return fmt.Sprintf("%s:%s", n.NSMode, n.Value) @@ -133,7 +142,7 @@ func validateUserNS(n *Namespace) error { return nil } switch n.NSMode { - case Auto, KeepID: + case Auto, KeepID, NoMap: return nil } return n.validate() @@ -299,6 +308,9 @@ func ParseUserNamespace(ns string) (Namespace, error) { case ns == "keep-id": toReturn.NSMode = KeepID return toReturn, nil + case ns == "nomap": + toReturn.NSMode = NoMap + return toReturn, nil case ns == "": toReturn.NSMode = Host return toReturn, nil @@ -548,20 +560,41 @@ func SetupUserNS(idmappings *storage.IDMappingOptions, userns Namespace, g *gene g.SetProcessUID(uint32(uid)) g.SetProcessGID(uint32(gid)) user = fmt.Sprintf("%d:%d", uid, gid) - fallthrough - case Private: - if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), ""); err != nil { + if err := privateUserNamespace(idmappings, g); err != nil { return user, err } - if idmappings == nil || (len(idmappings.UIDMap) == 0 && len(idmappings.GIDMap) == 0) { - return user, errors.Errorf("must provide at least one UID or GID mapping to configure a user namespace") + case NoMap: + mappings, uid, gid, err := util.GetNoMapMapping() + if err != nil { + return user, err } - for _, uidmap := range idmappings.UIDMap { - g.AddLinuxUIDMapping(uint32(uidmap.HostID), uint32(uidmap.ContainerID), uint32(uidmap.Size)) + idmappings = mappings + g.SetProcessUID(uint32(uid)) + g.SetProcessGID(uint32(gid)) + user = fmt.Sprintf("%d:%d", uid, gid) + if err := privateUserNamespace(idmappings, g); err != nil { + return user, err } - for _, gidmap := range idmappings.GIDMap { - g.AddLinuxGIDMapping(uint32(gidmap.HostID), uint32(gidmap.ContainerID), uint32(gidmap.Size)) + case Private: + if err := privateUserNamespace(idmappings, g); err != nil { + return user, err } } return user, nil } + +func privateUserNamespace(idmappings *storage.IDMappingOptions, g *generate.Generator) error { + if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), ""); err != nil { + return err + } + if idmappings == nil || (len(idmappings.UIDMap) == 0 && len(idmappings.GIDMap) == 0) { + return errors.Errorf("must provide at least one UID or GID mapping to configure a user namespace") + } + for _, uidmap := range idmappings.UIDMap { + g.AddLinuxUIDMapping(uint32(uidmap.HostID), uint32(uidmap.ContainerID), uint32(uidmap.Size)) + } + for _, gidmap := range idmappings.GIDMap { + g.AddLinuxGIDMapping(uint32(gidmap.HostID), uint32(gidmap.ContainerID), uint32(gidmap.Size)) + } + return nil +} diff --git a/pkg/systemd/dbus.go b/pkg/systemd/dbus.go index 44feb8308..b35f778ab 100644 --- a/pkg/systemd/dbus.go +++ b/pkg/systemd/dbus.go @@ -1,6 +1,7 @@ package systemd import ( + "context" "fmt" "os" "path/filepath" @@ -140,5 +141,5 @@ func ConnectToDBUS() (*dbus.Conn, error) { if rootless.IsRootless() { return newRootlessConnection() } - return dbus.NewSystemdConnection() + return dbus.NewSystemdConnectionContext(context.Background()) } diff --git a/pkg/terminal/util.go b/pkg/terminal/util.go index 04e12f6b3..0f0968c30 100644 --- a/pkg/terminal/util.go +++ b/pkg/terminal/util.go @@ -14,7 +14,7 @@ import ( "github.com/sirupsen/logrus" "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/knownhosts" - "golang.org/x/crypto/ssh/terminal" + "golang.org/x/term" ) var ( @@ -29,9 +29,9 @@ var ( // Additionally, all input after `<secret>/n` is queued to podman command. func ReadPassword(prompt string) (pw []byte, err error) { fd := int(os.Stdin.Fd()) - if terminal.IsTerminal(fd) { + if term.IsTerminal(fd) { fmt.Fprint(os.Stderr, prompt) - pw, err = terminal.ReadPassword(fd) + pw, err = term.ReadPassword(fd) fmt.Fprintln(os.Stderr) return } diff --git a/pkg/util/utils.go b/pkg/util/utils.go index b89978601..9842a0f73 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -28,7 +28,7 @@ import ( "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" - "golang.org/x/crypto/ssh/terminal" + "golang.org/x/term" ) var containerConfig *config.Config @@ -65,7 +65,7 @@ func ParseRegistryCreds(creds string) (*types.DockerAuthConfig, error) { } if password == "" { fmt.Print("Password: ") - termPassword, err := terminal.ReadPassword(0) + termPassword, err := term.ReadPassword(0) if err != nil { return nil, errors.Wrapf(err, "could not read password from terminal") } @@ -347,55 +347,84 @@ func ParseSignal(rawSignal string) (syscall.Signal, error) { // GetKeepIDMapping returns the mappings and the user to use when keep-id is used func GetKeepIDMapping() (*stypes.IDMappingOptions, int, int, error) { + if !rootless.IsRootless() { + return nil, -1, -1, errors.New("keep-id is only supported in rootless mode") + } options := stypes.IDMappingOptions{ - HostUIDMapping: true, - HostGIDMapping: true, + HostUIDMapping: false, + HostGIDMapping: false, } - uid, gid := 0, 0 - if rootless.IsRootless() { - min := func(a, b int) int { - if a < b { - return a - } - return b + min := func(a, b int) int { + if a < b { + return a } + return b + } - uid = rootless.GetRootlessUID() - gid = rootless.GetRootlessGID() + uid := rootless.GetRootlessUID() + gid := rootless.GetRootlessGID() - uids, gids, err := rootless.GetConfiguredMappings() - if err != nil { - return nil, -1, -1, errors.Wrapf(err, "cannot read mappings") - } - maxUID, maxGID := 0, 0 - for _, u := range uids { - maxUID += u.Size - } - for _, g := range gids { - maxGID += g.Size - } - - options.UIDMap, options.GIDMap = nil, nil + uids, gids, err := rootless.GetConfiguredMappings() + if err != nil { + return nil, -1, -1, errors.Wrapf(err, "cannot read mappings") + } + if len(uids) == 0 || len(gids) == 0 { + return nil, -1, -1, errors.Wrapf(err, "keep-id requires additional UIDs or GIDs defined in /etc/subuid and /etc/subgid to function correctly") + } + maxUID, maxGID := 0, 0 + for _, u := range uids { + maxUID += u.Size + } + for _, g := range gids { + maxGID += g.Size + } - options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(uid, maxUID)}) - options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid, HostID: 0, Size: 1}) - if maxUID > uid { - options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid + 1, HostID: uid + 1, Size: maxUID - uid}) - } + options.UIDMap, options.GIDMap = nil, nil - options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(gid, maxGID)}) - options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid, HostID: 0, Size: 1}) - if maxGID > gid { - options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid + 1, HostID: gid + 1, Size: maxGID - gid}) - } + options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(uid, maxUID)}) + options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid, HostID: 0, Size: 1}) + if maxUID > uid { + options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid + 1, HostID: uid + 1, Size: maxUID - uid}) + } - options.HostUIDMapping = false - options.HostGIDMapping = false + options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(gid, maxGID)}) + options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid, HostID: 0, Size: 1}) + if maxGID > gid { + options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid + 1, HostID: gid + 1, Size: maxGID - gid}) } - // Simply ignore the setting and do not setup an inner namespace for root as it is a no-op + return &options, uid, gid, nil } +// GetNoMapMapping returns the mappings and the user to use when nomap is used +func GetNoMapMapping() (*stypes.IDMappingOptions, int, int, error) { + if !rootless.IsRootless() { + return nil, -1, -1, errors.New("nomap is only supported in rootless mode") + } + options := stypes.IDMappingOptions{ + HostUIDMapping: false, + HostGIDMapping: false, + } + uids, gids, err := rootless.GetConfiguredMappings() + if err != nil { + return nil, -1, -1, errors.Wrapf(err, "cannot read mappings") + } + if len(uids) == 0 || len(gids) == 0 { + return nil, -1, -1, errors.Wrapf(err, "nomap requires additional UIDs or GIDs defined in /etc/subuid and /etc/subgid to function correctly") + } + options.UIDMap, options.GIDMap = nil, nil + uid, gid := 0, 0 + for _, u := range uids { + options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid, HostID: uid + 1, Size: u.Size}) + uid += u.Size + } + for _, g := range gids { + options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid, HostID: gid + 1, Size: g.Size}) + gid += g.Size + } + return &options, 0, 0, nil +} + // ParseIDMapping takes idmappings and subuid and subgid maps and returns a storage mapping func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []string, subUIDMap, subGIDMap string) (*stypes.IDMappingOptions, error) { options := stypes.IDMappingOptions{ @@ -415,7 +444,7 @@ func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []strin options.AutoUserNsOpts = *opts return &options, nil } - if mode.IsKeepID() { + if mode.IsKeepID() || mode.IsNoMap() { options.HostUIDMapping = false options.HostGIDMapping = false return &options, nil |