Use storage that better supports rootless overlayfs

overlayfs -- the kernel's version, not fuse-overlayfs -- recently learned
(as of linux 5.16.0, I believe) how to support rootless users. Previously,
rootless users had to use these storage.conf(5) settings:

* storage.driver=vfs          (aka STORAGE_DRIVER=vfs), or
* storage.driver=overlay      (aka STORAGE_DRIVER=overlay),
  storage.options.overlay.mount_program=/usr/bin/fuse-overlayfs
                              (aka STORAGE_OPTS=/usr/bin/fuse-overlayfs)

Now that a third backend is available, setting only:

* storage.driver=overlay      (aka STORAGE_DRIVER=overlay)

https://github.com/containers/podman/issues/13123 reported EXDEV errors
during the normal operation of their container. Tracing it out, the
problem turned out to be that their container was being mounted without
'userxattr'; I don't fully understand why, but mount(8) mentions this is
needed for rootless users:

> userxattr
>
>   Use the "user.overlay." xattr namespace instead of "trusted.overlay.".
>   This is useful for unprivileged mounting of overlayfs.

https://github.com/containers/storage/pull/1156 found and fixed the issue
in podman, and this just pulls in that via

    go get github.com/containers/storage@ebc90ab
    go mod vendor
    make vendor

Closes https://github.com/containers/podman/issues/13123

Signed-off-by: Nick Guenther <nick.guenther@polymtl.ca>
This commit is contained in:
Nick Guenther
2022-02-28 12:54:09 -05:00
parent 8bdda91ab7
commit 572e6464f6
31 changed files with 383 additions and 217 deletions

View File

@ -26,6 +26,7 @@ import (
"archive/tar"
"bytes"
"compress/gzip"
"errors"
"fmt"
"io"
"io/ioutil"
@ -38,7 +39,6 @@ import (
"github.com/containerd/stargz-snapshotter/estargz/errorutil"
"github.com/klauspost/compress/zstd"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
)
@ -142,7 +142,7 @@ func Build(tarBlob *io.SectionReader, opt ...Option) (_ *Blob, rErr error) {
defer func() {
if rErr != nil {
if err := layerFiles.CleanupAll(); err != nil {
rErr = errors.Wrapf(rErr, "failed to cleanup tmp files: %v", err)
rErr = fmt.Errorf("failed to cleanup tmp files: %v: %w", err, rErr)
}
}
}()
@ -307,7 +307,7 @@ func sortEntries(in io.ReaderAt, prioritized []string, missedPrioritized *[]stri
// Import tar file.
intar, err := importTar(in)
if err != nil {
return nil, errors.Wrap(err, "failed to sort")
return nil, fmt.Errorf("failed to sort: %w", err)
}
// Sort the tar file respecting to the prioritized files list.
@ -318,7 +318,7 @@ func sortEntries(in io.ReaderAt, prioritized []string, missedPrioritized *[]stri
*missedPrioritized = append(*missedPrioritized, l)
continue // allow not found
}
return nil, errors.Wrap(err, "failed to sort tar entries")
return nil, fmt.Errorf("failed to sort tar entries: %w", err)
}
}
if len(prioritized) == 0 {
@ -371,7 +371,7 @@ func importTar(in io.ReaderAt) (*tarFile, error) {
tf := &tarFile{}
pw, err := newCountReader(in)
if err != nil {
return nil, errors.Wrap(err, "failed to make position watcher")
return nil, fmt.Errorf("failed to make position watcher: %w", err)
}
tr := tar.NewReader(pw)
@ -383,7 +383,7 @@ func importTar(in io.ReaderAt) (*tarFile, error) {
if err == io.EOF {
break
} else {
return nil, errors.Wrap(err, "failed to parse tar file")
return nil, fmt.Errorf("failed to parse tar file, %w", err)
}
}
switch cleanEntryName(h.Name) {
@ -420,7 +420,7 @@ func moveRec(name string, in *tarFile, out *tarFile) error {
_, okIn := in.get(name)
_, okOut := out.get(name)
if !okIn && !okOut {
return errors.Wrapf(errNotFound, "file: %q", name)
return fmt.Errorf("file: %q: %w", name, errNotFound)
}
parent, _ := path.Split(strings.TrimSuffix(name, "/"))

View File

@ -27,6 +27,7 @@ import (
"bytes"
"compress/gzip"
"crypto/sha256"
"errors"
"fmt"
"hash"
"io"
@ -40,7 +41,6 @@ import (
"github.com/containerd/stargz-snapshotter/estargz/errorutil"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/vbatts/tar-split/archive/tar"
)
@ -385,8 +385,7 @@ func (r *Reader) Verifiers() (TOCEntryVerifier, error) {
if e.Digest != "" {
d, err := digest.Parse(e.Digest)
if err != nil {
return nil, errors.Wrapf(err,
"failed to parse regular file digest %q", e.Digest)
return nil, fmt.Errorf("failed to parse regular file digest %q: %w", e.Digest, err)
}
regDigestMap[e.Offset] = d
} else {
@ -401,8 +400,7 @@ func (r *Reader) Verifiers() (TOCEntryVerifier, error) {
if e.ChunkDigest != "" {
d, err := digest.Parse(e.ChunkDigest)
if err != nil {
return nil, errors.Wrapf(err,
"failed to parse chunk digest %q", e.ChunkDigest)
return nil, fmt.Errorf("failed to parse chunk digest %q: %w", e.ChunkDigest, err)
}
chunkDigestMap[e.Offset] = d
} else {
@ -647,7 +645,7 @@ func Unpack(sr *io.SectionReader, c Decompressor) (io.ReadCloser, error) {
}
blobPayloadSize, _, _, err := c.ParseFooter(footer)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse footer")
return nil, fmt.Errorf("failed to parse footer: %w", err)
}
return c.Reader(io.LimitReader(sr, blobPayloadSize))
}

View File

@ -3,9 +3,8 @@ module github.com/containerd/stargz-snapshotter/estargz
go 1.16
require (
github.com/klauspost/compress v1.14.2
github.com/klauspost/compress v1.14.3
github.com/opencontainers/go-digest v1.0.0
github.com/pkg/errors v0.9.1
github.com/vbatts/tar-split v0.11.2
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
)

View File

@ -1,12 +1,10 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/klauspost/compress v1.14.2 h1:S0OHlFk/Gbon/yauFJ4FfJJF5V0fc5HbBTJazi28pRw=
github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.14.3 h1:DQv1WP+iS4srNjibdnHtqu8JNWCDMluj5NzPnFJsnvk=
github.com/klauspost/compress v1.14.3/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=

View File

@ -34,7 +34,6 @@ import (
"strconv"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
)
type gzipCompression struct {
@ -150,7 +149,7 @@ func (gz *GzipDecompressor) ParseFooter(p []byte) (blobPayloadSize, tocOffset, t
}
tocOffset, err = strconv.ParseInt(string(subfield[:16]), 16, 64)
if err != nil {
return 0, 0, 0, errors.Wrapf(err, "legacy: failed to parse toc offset")
return 0, 0, 0, fmt.Errorf("legacy: failed to parse toc offset: %w", err)
}
return tocOffset, tocOffset, 0, nil
}
@ -179,7 +178,7 @@ func (gz *LegacyGzipDecompressor) ParseFooter(p []byte) (blobPayloadSize, tocOff
}
zr, err := gzip.NewReader(bytes.NewReader(p))
if err != nil {
return 0, 0, 0, errors.Wrapf(err, "legacy: failed to get footer gzip reader")
return 0, 0, 0, fmt.Errorf("legacy: failed to get footer gzip reader: %w", err)
}
defer zr.Close()
extra := zr.Header.Extra
@ -191,7 +190,7 @@ func (gz *LegacyGzipDecompressor) ParseFooter(p []byte) (blobPayloadSize, tocOff
}
tocOffset, err = strconv.ParseInt(string(extra[:16]), 16, 64)
if err != nil {
return 0, 0, 0, errors.Wrapf(err, "legacy: failed to parse toc offset")
return 0, 0, 0, fmt.Errorf("legacy: failed to parse toc offset: %w", err)
}
return tocOffset, tocOffset, 0, nil
}

View File

@ -28,6 +28,7 @@ import (
"compress/gzip"
"crypto/sha256"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
@ -41,7 +42,6 @@ import (
"github.com/containerd/stargz-snapshotter/estargz/errorutil"
"github.com/klauspost/compress/zstd"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
)
// TestingController is Compression with some helper methods necessary for testing.
@ -1062,18 +1062,18 @@ func parseStargz(sgz *io.SectionReader, controller TestingController) (decodedJT
fSize := controller.FooterSize()
footer := make([]byte, fSize)
if _, err := sgz.ReadAt(footer, sgz.Size()-fSize); err != nil {
return nil, 0, errors.Wrap(err, "error reading footer")
return nil, 0, fmt.Errorf("error reading footer: %w", err)
}
_, tocOffset, _, err := controller.ParseFooter(footer[positive(int64(len(footer))-fSize):])
if err != nil {
return nil, 0, errors.Wrapf(err, "failed to parse footer")
return nil, 0, fmt.Errorf("failed to parse footer: %w", err)
}
// Decode the TOC JSON
tocReader := io.NewSectionReader(sgz, tocOffset, sgz.Size()-tocOffset-fSize)
decodedJTOC, _, err = controller.ParseTOC(tocReader)
if err != nil {
return nil, 0, errors.Wrap(err, "failed to parse TOC")
return nil, 0, fmt.Errorf("failed to parse TOC: %w", err)
}
return decodedJTOC, tocOffset, nil
}