Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
7f37fbd
quadlet: allow empty Entrypoint to clear image default
umut-polat Mar 12, 2026
28a39dd
libpod: Don't dereference ctrSpec.Linux if it is nil
dfr Mar 18, 2026
759df25
new image sfx for debian 14
Nov 10, 2025
1a9ae9d
update fedoral base image to 43 and related tests
Nov 21, 2025
d49a920
cirrus: ensure NOTIFY_SOCKET is properly unset for all tests
Luap99 Dec 12, 2025
26047f4
New images 2026-03-19
Luap99 Mar 19, 2026
c91cd99
test: relax rootless runc pid namespace assertion
ricardobranco777 Mar 21, 2026
e5fe3fd
api: fix missing return after error in SystemCheck handler
crawfordxx Mar 24, 2026
15a2a7d
Remote build: `nTar` secrets with relative paths and ignore bypass
Honny1 Mar 23, 2026
51b5c59
Consolidate build secret tests and assert no podman-build-secret leak
Honny1 Mar 25, 2026
7250b06
libpod: fix data race on deferredErr in attachExecHTTP
crawfordxx Mar 29, 2026
e9fe245
Fix shell driver DriverOpts cross-contamination in secret creation
jdoss Mar 30, 2026
75820dd
Add e2e test for shell driver DriverOpts cross-contamination fix
jdoss Mar 30, 2026
9c26273
Fix Quadlet `Lookup()` stripping unmatched quotes
Honny1 Mar 30, 2026
0fa3043
add missing O_CLOEXEC to open calls
Luap99 Apr 2, 2026
92cd249
fix symlink handling in checkpoint restore
Luap99 Apr 8, 2026
a49ad4b
use chrootarchive over plain archive package
Luap99 Apr 8, 2026
add385e
bindings: artifact extract reject invalid names
Luap99 Apr 8, 2026
d1cf366
Remove iptables references in upgrade tests
l0rd Nov 18, 2025
f13de01
cirrus: bump linux machine aarch64 test timeout
Luap99 Mar 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 7 additions & 11 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ env:
####
#### Cache-image names to test with (double-quotes around names are critical)
####
FEDORA_NAME: "fedora-42"
FEDORA_NAME: "fedora-43"
FEDORA_AARCH64_NAME: "${FEDORA_NAME}-aarch64"
PRIOR_FEDORA_NAME: "fedora-41"
PRIOR_FEDORA_NAME: "fedora-42"
RAWHIDE_NAME: "rawhide"
DEBIAN_NAME: "debian-13"
DEBIAN_NAME: "debian-14"

# Image identifiers
IMAGE_SUFFIX: "c20250910t092246z-f42f41d13"
IMAGE_SUFFIX: "c20260319t182308z-f43f42d14"

# EC2 images
FEDORA_AMI: "fedora-aws-${IMAGE_SUFFIX}"
Expand Down Expand Up @@ -810,7 +810,7 @@ podman_machine_aarch64_task:
depends_on: *build
ec2_instance:
<<: *standard_build_ec2_aarch64
timeout_in: 40m
timeout_in: 60m
env:
TEST_FLAVOR: "machine-linux"
TEST_BUILD_TAGS: ""
Expand Down Expand Up @@ -1099,13 +1099,9 @@ upgrade_test_task:
depends_on: *build
matrix:
- env:
# 2024-02: as long as possible/reasonable, try to keep
# one version < 4.8 so we can test boltdb. v4.3.1 is
# the lowest we can go right now, builds before that
# have netavark <1.4 which hangs on f39 kernel (#21863).
PODMAN_UPGRADE_FROM: v4.3.1
PODMAN_UPGRADE_FROM: v5.3.1
- env:
PODMAN_UPGRADE_FROM: v4.8.0
PODMAN_UPGRADE_FROM: v5.6.2
gce_instance: *standardvm
env:
TEST_FLAVOR: upgrade_test
Expand Down
2 changes: 1 addition & 1 deletion cmd/rootlessport/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ outer:
_ = os.Remove(socketfile)
// workaround to bypass the 108 char socket path limit
// open the fd and use the path to the fd as bind argument
fd, err := unix.Open(socketDir, unix.O_PATH, 0)
fd, err := unix.Open(socketDir, unix.O_PATH|unix.O_CLOEXEC, 0)
if err != nil {
return err
}
Expand Down
24 changes: 13 additions & 11 deletions libpod/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -1442,18 +1442,20 @@ func (c *Container) NetworkMode() string {
// If there is none, it's host networking.
// If there is one and it has a path, it's "ns:".
foundNetNS := false
for _, ns := range ctrSpec.Linux.Namespaces {
if ns.Type == spec.NetworkNamespace {
foundNetNS = true
if ns.Path != "" {
networkMode = fmt.Sprintf("ns:%s", ns.Path)
} else {
// We're making a network ns, but not
// configuring with Slirp or CNI. That
// means it's --net=none
networkMode = "none"
if ctrSpec.Linux != nil {
for _, ns := range ctrSpec.Linux.Namespaces {
if ns.Type == spec.NetworkNamespace {
foundNetNS = true
if ns.Path != "" {
networkMode = fmt.Sprintf("ns:%s", ns.Path)
} else {
// We're making a network ns, but not
// configuring with Slirp or CNI. That
// means it's --net=none
networkMode = "none"
}
break
}
break
}
}
if !foundNetNS {
Expand Down
22 changes: 11 additions & 11 deletions libpod/container_internal_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import (
"go.podman.io/common/pkg/umask"
is "go.podman.io/image/v5/storage"
"go.podman.io/storage/pkg/archive"
"go.podman.io/storage/pkg/chrootarchive"
"go.podman.io/storage/pkg/fileutils"
"go.podman.io/storage/pkg/idtools"
"go.podman.io/storage/pkg/lockfile"
Expand Down Expand Up @@ -1207,11 +1208,10 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
if mp == "" {
return fmt.Errorf("volume %s is not mounted, cannot export: %w", volume.Name(), define.ErrInternal)
}

input, err := archive.TarWithOptions(mp, &archive.TarOptions{
input, err := chrootarchive.Tar(mp, &archive.TarOptions{
Compression: archive.Uncompressed,
IncludeSourceDir: true,
})
}, mp)
if err != nil {
return fmt.Errorf("reading volume directory %q: %w", v.Dest, err)
}
Expand All @@ -1226,12 +1226,12 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
}
}

input, err := archive.TarWithOptions(c.bundlePath(), &archive.TarOptions{
bundle := c.bundlePath()
input, err := chrootarchive.Tar(bundle, &archive.TarOptions{
Compression: options.Compression,
IncludeSourceDir: true,
IncludeFiles: includeFiles,
})

}, bundle)
if err != nil {
return fmt.Errorf("reading checkpoint directory %q: %w", c.ID(), err)
}
Expand Down Expand Up @@ -1312,10 +1312,10 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
}
defer shmDirTarFile.Close()

input, err := archive.TarWithOptions(c.config.ShmDir, &archive.TarOptions{
input, err := chrootarchive.Tar(c.config.ShmDir, &archive.TarOptions{
Compression: archive.Uncompressed,
IncludeSourceDir: true,
})
}, c.config.ShmDir)
if err != nil {
return nil, 0, err
}
Expand Down Expand Up @@ -1488,7 +1488,7 @@ func (c *Container) importPreCheckpoint(input string) error {

defer archiveFile.Close()

err = archive.Untar(archiveFile, c.bundlePath(), nil)
err = chrootarchive.Untar(archiveFile, c.bundlePath(), nil)
if err != nil {
return fmt.Errorf("unpacking of pre-checkpoint archive %s failed: %w", input, err)
}
Expand Down Expand Up @@ -1751,7 +1751,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
}
defer shmDirTarFile.Close()

if err := archive.UntarUncompressed(shmDirTarFile, c.config.ShmDir, nil); err != nil {
if err := chrootarchive.UntarUncompressed(shmDirTarFile, c.config.ShmDir, nil); err != nil {
return nil, 0, err
}
}
Expand Down Expand Up @@ -1791,7 +1791,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
if mountPoint == "" {
return nil, 0, fmt.Errorf("unable to import volume %s as it is not mounted: %w", volume.Name(), err)
}
if err := archive.UntarUncompressed(volumeFile, mountPoint, nil); err != nil {
if err := chrootarchive.UntarUncompressed(volumeFile, mountPoint, nil); err != nil {
return nil, 0, fmt.Errorf("failed to extract volume %s to %s: %w", volumeFilePath, mountPoint, err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion libpod/oci_conmon_attach_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

func openUnixSocket(path string) (*net.UnixConn, error) {
fd, err := unix.Open(path, unix.O_PATH, 0)
fd, err := unix.Open(path, unix.O_PATH|unix.O_CLOEXEC, 0)
if err != nil {
return nil, err
}
Expand Down
13 changes: 12 additions & 1 deletion libpod/oci_conmon_exec_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,13 @@ func attachExecHTTP(c *Container, sessionID string, r *http.Request, w http.Resp
return err
}

// errCh receives deferredErr after all deferred cleanup in this function
// has completed. The goroutine below reads from errCh so that it never
// races with the deferred functions that may still be writing deferredErr
// when holdConnOpen is closed by the caller.
errCh := make(chan error, 1)
defer func() { errCh <- deferredErr }()

defer func() {
if !pipes.startClosed {
errorhandling.CloseQuiet(pipes.startPipe)
Expand Down Expand Up @@ -608,7 +615,11 @@ func attachExecHTTP(c *Container, sessionID string, r *http.Request, w http.Resp
// Can't be a defer, because this would block the function from
// returning.
<-holdConnOpen
hijackWriteErrorAndClose(deferredErr, c.ID(), isTerminal, httpCon, httpBuf)
// Block until all deferred cleanups in attachExecHTTP have run and
// the final deferredErr value has been sent to errCh. This avoids
// the data race that would occur if we read deferredErr directly
// while deferred functions in this function may still be writing it.
hijackWriteErrorAndClose(<-errCh, c.ID(), isTerminal, httpCon, httpBuf)
}()

stdoutChan := make(chan error)
Expand Down
4 changes: 2 additions & 2 deletions libpod/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/containers/podman/v5/libpod/plugin"
"github.com/containers/podman/v5/utils"
"github.com/sirupsen/logrus"
"go.podman.io/storage/pkg/archive"
"go.podman.io/storage/pkg/chrootarchive"
"go.podman.io/storage/pkg/directory"
)

Expand Down Expand Up @@ -342,7 +342,7 @@ func (v *Volume) Import(r io.Reader) error {
}
}()

if err := archive.Untar(r, mountPoint, nil); err != nil {
if err := chrootarchive.Untar(r, mountPoint, nil); err != nil {
return fmt.Errorf("extracting into volume %s: %w", v.Name(), err)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/api/handlers/compat/images_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -1237,6 +1237,6 @@ func extractTarFile(anchorDir string, r io.ReadCloser) (string, error) {
return "", err
}

err = archive.Untar(r, buildDir, nil)
err = chrootarchive.Untar(r, buildDir, nil)
return buildDir, err
}
5 changes: 2 additions & 3 deletions pkg/api/handlers/libpod/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import (
"os"
"path/filepath"

"go.podman.io/storage/pkg/archive"

"github.com/containers/podman/v5/libpod"
"github.com/containers/podman/v5/pkg/api/handlers/utils"
api "github.com/containers/podman/v5/pkg/api/types"
Expand All @@ -23,6 +21,7 @@ import (
"github.com/gorilla/schema"
"github.com/sirupsen/logrus"
"go.podman.io/image/v5/types"
"go.podman.io/storage/pkg/chrootarchive"
)

// ExtractPlayReader provide an io.Reader given a http.Request object
Expand Down Expand Up @@ -52,7 +51,7 @@ func extractPlayReader(anchorDir string, r *http.Request) (io.Reader, error) {
reader = r.Body
case "application/x-tar":
// un-tar the content
err := archive.Untar(r.Body, anchorDir, nil)
err := chrootarchive.Untar(r.Body, anchorDir, nil)
if err != nil {
return nil, err
}
Expand Down
5 changes: 2 additions & 3 deletions pkg/api/handlers/libpod/quadlets.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import (
"path/filepath"
"strings"

"go.podman.io/storage/pkg/archive"

"github.com/containers/podman/v5/libpod"
"github.com/containers/podman/v5/libpod/define"
"github.com/containers/podman/v5/pkg/api/handlers/utils"
Expand All @@ -23,6 +21,7 @@ import (
"github.com/containers/podman/v5/pkg/util"
"github.com/gorilla/schema"
"github.com/sirupsen/logrus"
"go.podman.io/storage/pkg/chrootarchive"
)

func ListQuadlets(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -94,7 +93,7 @@ func extractQuadletFiles(tempDir string, r io.ReadCloser) ([]string, error) {
return nil, err
}

err = archive.Untar(r, quadletDir, nil)
err = chrootarchive.Untar(r, quadletDir, nil)
if err != nil {
return nil, err
}
Expand Down
1 change: 1 addition & 0 deletions pkg/api/handlers/libpod/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ func SystemCheck(w http.ResponseWriter, r *http.Request) {
if err != nil {
utils.Error(w, http.StatusBadRequest,
fmt.Errorf("failed to parse unreferenced_layer_max_age parameter %q for %s: %w", query.UnreferencedLayerMaximumAge, r.URL.String(), err))
return
}
unreferencedLayerMaximumAge = &duration
}
Expand Down
9 changes: 8 additions & 1 deletion pkg/bindings/artifacts/extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,14 @@ func Extract(ctx context.Context, artifactName string, target string, options *E
// If destination isn't a file, extract to target/filename
fileTarget := target
if targetIsDirectory {
fileTarget = filepath.Join(target, header.Name)
filename := header.Name
// This matches the logic from generateArtifactBlobName().
for i := range len(filename) {
if os.IsPathSeparator(filename[i]) {
return fmt.Errorf("invalid filename: %q cannot contain %c", filename, filename[i])
}
}
fileTarget = filepath.Join(target, filename)
}

if header.Typeflag == tar.TypeReg {
Expand Down
18 changes: 17 additions & 1 deletion pkg/bindings/images/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,10 @@ func build(ctx context.Context, containerFiles []string, options types.BuildOpti
return processBuildResponse(response, stdout, saveFormat)
}

// nTar builds a gzip-compressed tar of sources and returns it as a ReadCloser.
// sources[0] is the build context directory (walked recursively). Remaining entries
// are extra regular files (e.g. secrets) that are always archived; exclude patterns
// apply only to the first source.
func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
pm, err := fileutils.NewPatternMatcher(excludes)
if err != nil {
Expand All @@ -1104,13 +1108,17 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
defer gw.Close()
defer tw.Close()
seen := make(map[devino]string)
firstSourceAbs := ""
for i, src := range sources {
source, err := filepath.Abs(src)
if err != nil {
logrus.Errorf("Cannot stat one of source context: %v", err)
merr = multierror.Append(merr, err)
return
}
if i == 0 {
firstSourceAbs = source
}
err = filepath.WalkDir(source, func(path string, dentry fs.DirEntry, err error) error {
if err != nil {
return err
Expand Down Expand Up @@ -1144,7 +1152,15 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
if !dentry.Type().IsRegular() {
return fmt.Errorf("path %s must be a regular file", path)
}
name = filepath.ToSlash(path)
// Additional sources are absolute host paths (Containerfiles passed by path, or
// temp files such as secrets placed under the context directory). Strip the
// resolved context directory so tar member names are relative to that root,
// like entries from the primary walk (i == 0). Using the raw absolute path would
// produce members that unpack as a spurious host path tree (e.g. Users/...)
// instead of files beside the Dockerfile.
// https://github.com/containers/podman/issues/28334
after, _ := strings.CutPrefix(path, firstSourceAbs)
name = filepath.ToSlash(after)
}
// If name is absolute path, then it has to be containerfile outside of build context.
// If not, we should check it for being excluded via pattern matcher.
Expand Down
Loading