From 520e2a81aabfabfb4b80de5d8243e175467e38a3 Mon Sep 17 00:00:00 2001
From: jianli-97 <lijian2@kylinos.cn>
Date: Mon, 14 Apr 2025 08:06:20 +0000
Subject: [PATCH 1/1] fix CVE-2024-3727
.../common/pkg/config/containers.conf | 9 ++
.../containers/common/pkg/config/default.go | 8 ++
.../containers/image/v5/copy/progress_bars.go | 7 +-
.../containers/image/v5/copy/single.go | 39 ++++--
.../image/v5/directory/directory_dest.go | 22 ++-
.../image/v5/directory/directory_src.go | 17 ++-
.../image/v5/directory/directory_transport.go | 25 ++--
.../image/v5/docker/docker_client.go | 20 ++-
.../image/v5/docker/docker_image_dest.go | 22 ++-
.../image/v5/docker/docker_image_src.go | 18 ++-
.../image/v5/docker/internal/tarfile/dest.go | 12 +-
.../v5/docker/internal/tarfile/writer.go | 34 ++++-
.../image/v5/docker/registries_d.go | 7 +-
.../image/v5/openshift/openshift_src.go | 3 +
.../containers/image/v5/ostree/ostree_dest.go | 10 ++
.../containers/image/v5/ostree/ostree_src.go | 4 +-
.../image/v5/pkg/blobcache/blobcache.go | 12 +-
.../containers/image/v5/pkg/blobcache/dest.go | 93 +++++++------
.../containers/image/v5/pkg/blobcache/src.go | 16 ++-
.../image/v5/storage/storage_dest.go | 32 +++--
.../image/v5/storage/storage_image.go | 14 +-
.../image/v5/storage/storage_reference.go | 10 +-
.../image/v5/storage/storage_src.go | 19 ++-
.../containers/image/v5/version/version.go | 2 +-
.../ocicrypt/keywrap/jwe/keywrapper_jwe.go | 17 ++-
.../containers/ocicrypt/utils/testing.go | 13 +-
.../go-jose/go-jose/v3/asymmetric.go | 3 +
.../github.com/go-jose/go-jose/v3/crypter.go | 99 ++++++++++----
.../github.com/go-jose/go-jose/v3/encoding.go | 35 ++++-
vendor/github.com/go-jose/go-jose/v3/jwe.go | 14 +-
vendor/github.com/go-jose/go-jose/v3/jwk.go | 18 ++-
vendor/github.com/go-jose/go-jose/v3/jws.go | 13 +-
.../github.com/go-jose/go-jose/v3/signing.go | 59 +++++++--
.../go-jose/go-jose/v3/symmetric.go | 15 ++-
vendor/golang.org/x/sys/unix/mkerrors.sh | 2 +-
vendor/golang.org/x/sys/unix/zerrors_linux.go | 36 ++++-
.../x/sys/unix/zerrors_linux_386.go | 3 +
.../x/sys/unix/zerrors_linux_amd64.go | 3 +
.../x/sys/unix/zerrors_linux_arm.go | 3 +
.../x/sys/unix/zerrors_linux_arm64.go | 3 +
.../x/sys/unix/zerrors_linux_loong64.go | 3 +
.../x/sys/unix/zerrors_linux_mips.go | 3 +
.../x/sys/unix/zerrors_linux_mips64.go | 3 +
.../x/sys/unix/zerrors_linux_mips64le.go | 3 +
.../x/sys/unix/zerrors_linux_mipsle.go | 3 +
.../x/sys/unix/zerrors_linux_ppc.go | 3 +
.../x/sys/unix/zerrors_linux_ppc64.go | 3 +
.../x/sys/unix/zerrors_linux_ppc64le.go | 3 +
.../x/sys/unix/zerrors_linux_riscv64.go | 3 +
.../x/sys/unix/zerrors_linux_s390x.go | 3 +
.../x/sys/unix/zerrors_linux_sparc64.go | 3 +
.../x/sys/unix/zsysnum_linux_386.go | 4 +
.../x/sys/unix/zsysnum_linux_amd64.go | 3 +
.../x/sys/unix/zsysnum_linux_arm.go | 4 +
.../x/sys/unix/zsysnum_linux_arm64.go | 4 +
.../x/sys/unix/zsysnum_linux_loong64.go | 4 +
.../x/sys/unix/zsysnum_linux_mips.go | 4 +
.../x/sys/unix/zsysnum_linux_mips64.go | 4 +
.../x/sys/unix/zsysnum_linux_mips64le.go | 4 +
.../x/sys/unix/zsysnum_linux_mipsle.go | 4 +
.../x/sys/unix/zsysnum_linux_ppc.go | 4 +
.../x/sys/unix/zsysnum_linux_ppc64.go | 4 +
.../x/sys/unix/zsysnum_linux_ppc64le.go | 4 +
.../x/sys/unix/zsysnum_linux_riscv64.go | 4 +
.../x/sys/unix/zsysnum_linux_s390x.go | 4 +
.../x/sys/unix/zsysnum_linux_sparc64.go | 4 +
vendor/golang.org/x/sys/unix/ztypes_linux.go | 125 +++++++++---------
.../golang.org/x/sys/windows/env_windows.go | 17 ++-
.../x/sys/windows/syscall_windows.go | 3 +-
69 files changed, 785 insertions(+), 243 deletions(-)
@@ -729,6 +729,15 @@ default_sysctls = [
# "/run/current-system/sw/bin/crun",
#]
+#crun-vm = [
+# "/usr/bin/crun-vm",
+# "/usr/local/bin/crun-vm",
+# "/usr/local/sbin/crun-vm",
+# "/sbin/crun-vm",
+# "/bin/crun-vm",
+# "/run/current-system/sw/bin/crun-vm",
+#]
+
#kata = [
# "/usr/bin/kata-runtime",
# "/usr/sbin/kata-runtime",
@@ -363,6 +363,14 @@ func defaultEngineConfig() (*EngineConfig, error) {
"/bin/crun",
"/run/current-system/sw/bin/crun",
},
+ "crun-vm": {
+ "/usr/bin/crun-vm",
+ "/usr/local/bin/crun-vm",
+ "/usr/local/sbin/crun-vm",
+ "/sbin/crun-vm",
+ "/bin/crun-vm",
+ "/run/current-system/sw/bin/crun-vm",
+ },
"crun-wasm": {
"/usr/bin/crun-wasm",
"/usr/sbin/crun-wasm",
@@ -48,10 +48,13 @@ type progressBar struct {
// As a convention, most users of progress bars should call mark100PercentComplete on full success;
// by convention, we don't leave progress bars in partial state when fully done
// (even if we copied much less data than anticipated).
-func (c *copier) createProgressBar(pool *mpb.Progress, partial bool, info types.BlobInfo, kind string, onComplete string) *progressBar {
+func (c *copier) createProgressBar(pool *mpb.Progress, partial bool, info types.BlobInfo, kind string, onComplete string) (*progressBar, error) { // shortDigestLen is the length of the digest used for blobs.
// shortDigestLen is the length of the digest used for blobs.
const shortDigestLen = 12
+ if err := info.Digest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, so validate explicitly.
+ return nil, err
+ }
prefix := fmt.Sprintf("Copying %s %s", kind, info.Digest.Encoded())
// Truncate the prefix (chopping of some part of the digest) to make all progress bars aligned in a column.
maxPrefixLen := len("Copying blob ") + shortDigestLen
@@ -104,7 +107,7 @@ func (c *copier) createProgressBar(pool *mpb.Progress, partial bool, info types.
return &progressBar{
Bar: bar,
originalSize: info.Size,
- }
+ }, nil
}
// printCopyInfo prints a "Copying ..." message on the copier if the output is
@@ -599,7 +599,10 @@ func (ic *imageCopier) copyConfig(ctx context.Context, src types.Image) error {
destInfo, err := func() (types.BlobInfo, error) { // A scope for defer
progressPool := ic.c.newProgressPool()
defer progressPool.Wait()
- bar := ic.c.createProgressBar(progressPool, false, srcInfo, "config", "done")
+ bar, err := ic.c.createProgressBar(progressPool, false, srcInfo, "config", "done")
+ if err != nil {
+ return types.BlobInfo{}, err
+ }
defer bar.Abort(false)
ic.c.printCopyInfo("config", srcInfo)
@@ -707,11 +710,17 @@ func (ic *imageCopier) copyLayer(ctx context.Context, srcInfo types.BlobInfo, to
}
if reused {
logrus.Debugf("Skipping blob %s (already present):", srcInfo.Digest)
- func() { // A scope for defer
- bar := ic.c.createProgressBar(pool, false, types.BlobInfo{Digest: reusedBlob.Digest, Size: 0}, "blob", "skipped: already exists")
+ if err := func() error { // A scope for defer
+ bar, err := ic.c.createProgressBar(pool, false, types.BlobInfo{Digest: reusedBlob.Digest, Size: 0}, "blob", "skipped: already exists")
+ if err != nil {
+ return err
+ }
defer bar.Abort(false)
bar.mark100PercentComplete()
- }()
+ return nil
+ }(); err != nil {
+ return types.BlobInfo{}, "", err
+ }
// Throw an event that the layer has been skipped
if ic.c.options.Progress != nil && ic.c.options.ProgressInterval > 0 {
@@ -730,8 +739,11 @@ func (ic *imageCopier) copyLayer(ctx context.Context, srcInfo types.BlobInfo, to
// Attempt a partial only when the source allows to retrieve a blob partially and
// the destination has support for it.
if canAvoidProcessingCompleteLayer && ic.c.rawSource.SupportsGetBlobAt() && ic.c.dest.SupportsPutBlobPartial() {
- if reused, blobInfo := func() (bool, types.BlobInfo) { // A scope for defer
- bar := ic.c.createProgressBar(pool, true, srcInfo, "blob", "done")
+ reused, blobInfo, err := func() (bool, types.BlobInfo, error) { // A scope for defer
+ bar, err := ic.c.createProgressBar(pool, true, srcInfo, "blob", "done")
+ if err != nil {
+ return false, types.BlobInfo{}, err
+ }
hideProgressBar := true
defer func() { // Note that this is not the same as defer bar.Abort(hideProgressBar); we need hideProgressBar to be evaluated lazily.
bar.Abort(hideProgressBar)
@@ -751,18 +763,25 @@ func (ic *imageCopier) copyLayer(ctx context.Context, srcInfo types.BlobInfo, to
bar.mark100PercentComplete()
hideProgressBar = false
logrus.Debugf("Retrieved partial blob %v", srcInfo.Digest)
- return true, updatedBlobInfoFromUpload(srcInfo, uploadedBlob)
+ return true, updatedBlobInfoFromUpload(srcInfo, uploadedBlob), nil
}
logrus.Debugf("Failed to retrieve partial blob: %v", err)
- return false, types.BlobInfo{}
- }(); reused {
+ return false, types.BlobInfo{}, nil
+ }()
+ if err != nil {
+ return types.BlobInfo{}, "", err
+ }
+ if reused {
return blobInfo, cachedDiffID, nil
}
}
// Fallback: copy the layer, computing the diffID if we need to do so
return func() (types.BlobInfo, digest.Digest, error) { // A scope for defer
- bar := ic.c.createProgressBar(pool, false, srcInfo, "blob", "done")
+ bar, err := ic.c.createProgressBar(pool, false, srcInfo, "blob", "done")
+ if err != nil {
+ return types.BlobInfo{}, "", err
+ }
defer bar.Abort(false)
srcStream, srcBlobSize, err := ic.c.rawSource.GetBlob(ctx, srcInfo, ic.c.blobInfoCache)
@@ -173,7 +173,10 @@ func (d *dirImageDestination) PutBlobWithOptions(ctx context.Context, stream io.
}
}
- blobPath := d.ref.layerPath(blobDigest)
+ blobPath, err := d.ref.layerPath(blobDigest)
+ if err != nil {
+ return private.UploadedBlob{}, err
+ }
// need to explicitly close the file, since a rename won't otherwise not work on Windows
blobFile.Close()
explicitClosed = true
@@ -196,7 +199,10 @@ func (d *dirImageDestination) TryReusingBlobWithOptions(ctx context.Context, inf
if info.Digest == "" {
return false, private.ReusedBlob{}, fmt.Errorf("Can not check for a blob with unknown digest")
}
- blobPath := d.ref.layerPath(info.Digest)
+ blobPath, err := d.ref.layerPath(info.Digest)
+ if err != nil {
+ return false, private.ReusedBlob{}, err
+ }
finfo, err := os.Stat(blobPath)
if err != nil && os.IsNotExist(err) {
return false, private.ReusedBlob{}, nil
@@ -216,7 +222,11 @@ func (d *dirImageDestination) TryReusingBlobWithOptions(ctx context.Context, inf
// If the destination is in principle available, refuses this manifest type (e.g. it does not recognize the schema),
// but may accept a different manifest type, the returned error must be an ManifestTypeRejectedError.
func (d *dirImageDestination) PutManifest(ctx context.Context, manifest []byte, instanceDigest *digest.Digest) error {
- return os.WriteFile(d.ref.manifestPath(instanceDigest), manifest, 0644)
+ path, err := d.ref.manifestPath(instanceDigest)
+ if err != nil {
+ return err
+ }
+ return os.WriteFile(path, manifest, 0644)
}
// PutSignaturesWithFormat writes a set of signatures to the destination.
@@ -229,7 +239,11 @@ func (d *dirImageDestination) PutSignaturesWithFormat(ctx context.Context, signa
if err != nil {
return err
}
- if err := os.WriteFile(d.ref.signaturePath(i, instanceDigest), blob, 0644); err != nil {
+ path, err := d.ref.signaturePath(i, instanceDigest)
+ if err != nil {
+ return err
+ }
+ if err := os.WriteFile(path, blob, 0644); err != nil {
return err
}
}
@@ -55,7 +55,11 @@ func (s *dirImageSource) Close() error {
// If instanceDigest is not nil, it contains a digest of the specific manifest instance to retrieve (when the primary manifest is a manifest list);
// this never happens if the primary manifest is not a manifest list (e.g. if the source never returns manifest lists).
func (s *dirImageSource) GetManifest(ctx context.Context, instanceDigest *digest.Digest) ([]byte, string, error) {
- m, err := os.ReadFile(s.ref.manifestPath(instanceDigest))
+ path, err := s.ref.manifestPath(instanceDigest)
+ if err != nil {
+ return nil, "", err
+ }
+ m, err := os.ReadFile(path)
if err != nil {
return nil, "", err
}
@@ -66,7 +70,11 @@ func (s *dirImageSource) GetManifest(ctx context.Context, instanceDigest *digest
// The Digest field in BlobInfo is guaranteed to be provided, Size may be -1 and MediaType may be optionally provided.
// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location.
func (s *dirImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (io.ReadCloser, int64, error) {
- r, err := os.Open(s.ref.layerPath(info.Digest))
+ path, err := s.ref.layerPath(info.Digest)
+ if err != nil {
+ return nil, -1, err
+ }
+ r, err := os.Open(path)
if err != nil {
return nil, -1, err
}
@@ -84,7 +92,10 @@ func (s *dirImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache
func (s *dirImageSource) GetSignaturesWithFormat(ctx context.Context, instanceDigest *digest.Digest) ([]signature.Signature, error) {
signatures := []signature.Signature{}
for i := 0; ; i++ {
- path := s.ref.signaturePath(i, instanceDigest)
+ path, err := s.ref.signaturePath(i, instanceDigest)
+ if err != nil {
+ return nil, err
+ }
sigBlob, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
@@ -161,25 +161,34 @@ func (ref dirReference) DeleteImage(ctx context.Context, sys *types.SystemContex
}
// manifestPath returns a path for the manifest within a directory using our conventions.
-func (ref dirReference) manifestPath(instanceDigest *digest.Digest) string {
+func (ref dirReference) manifestPath(instanceDigest *digest.Digest) (string, error) {
if instanceDigest != nil {
- return filepath.Join(ref.path, instanceDigest.Encoded()+".manifest.json")
+ if err := instanceDigest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, and could possibly result in a path with ../, so validate explicitly.
+ return "", err
+ }
+ return filepath.Join(ref.path, instanceDigest.Encoded()+".manifest.json"), nil
}
- return filepath.Join(ref.path, "manifest.json")
+ return filepath.Join(ref.path, "manifest.json"), nil
}
// layerPath returns a path for a layer tarball within a directory using our conventions.
-func (ref dirReference) layerPath(digest digest.Digest) string {
+func (ref dirReference) layerPath(digest digest.Digest) (string, error) {
+ if err := digest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, and could possibly result in a path with ../, so validate explicitly.
+ return "", err
+ }
// FIXME: Should we keep the digest identification?
- return filepath.Join(ref.path, digest.Encoded())
+ return filepath.Join(ref.path, digest.Encoded()), nil
}
// signaturePath returns a path for a signature within a directory using our conventions.
-func (ref dirReference) signaturePath(index int, instanceDigest *digest.Digest) string {
+func (ref dirReference) signaturePath(index int, instanceDigest *digest.Digest) (string, error) {
if instanceDigest != nil {
- return filepath.Join(ref.path, fmt.Sprintf(instanceDigest.Encoded()+".signature-%d", index+1))
+ if err := instanceDigest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, and could possibly result in a path with ../, so validate explicitly.
+ return "", err
+ }
+ return filepath.Join(ref.path, fmt.Sprintf(instanceDigest.Encoded()+".signature-%d", index+1)), nil
}
- return filepath.Join(ref.path, fmt.Sprintf("signature-%d", index+1))
+ return filepath.Join(ref.path, fmt.Sprintf("signature-%d", index+1)), nil
}
// versionPath returns a path for the version file within a directory using our conventions.
@@ -952,6 +952,8 @@ func (c *dockerClient) detectProperties(ctx context.Context) error {
return c.detectPropertiesError
}
+// fetchManifest fetches a manifest for (the repo of ref) + tagOrDigest.
+// The caller is responsible for ensuring tagOrDigest uses the expected format.
func (c *dockerClient) fetchManifest(ctx context.Context, ref dockerReference, tagOrDigest string) ([]byte, string, error) {
path := fmt.Sprintf(manifestPath, reference.Path(ref.ref), tagOrDigest)
headers := map[string][]string{
@@ -1034,6 +1036,9 @@ func (c *dockerClient) getBlob(ctx context.Context, ref dockerReference, info ty
}
}
+ if err := info.Digest.Validate(); err != nil { // Make sure info.Digest.String() does not contain any unexpected characters
+ return nil, 0, err
+ }
path := fmt.Sprintf(blobsPath, reference.Path(ref.ref), info.Digest.String())
logrus.Debugf("Downloading %s", path)
res, err := c.makeRequest(ctx, http.MethodGet, path, nil, nil, v2Auth, nil)
@@ -1097,7 +1102,10 @@ func isManifestUnknownError(err error) bool {
// digest in ref.
// It returns (nil, nil) if the manifest does not exist.
func (c *dockerClient) getSigstoreAttachmentManifest(ctx context.Context, ref dockerReference, digest digest.Digest) (*manifest.OCI1, error) {
- tag := sigstoreAttachmentTag(digest)
+ tag, err := sigstoreAttachmentTag(digest)
+ if err != nil {
+ return nil, err
+ }
sigstoreRef, err := reference.WithTag(reference.TrimNamed(ref.ref), tag)
if err != nil {
return nil, err
@@ -1130,6 +1138,9 @@ func (c *dockerClient) getSigstoreAttachmentManifest(ctx context.Context, ref do
// getExtensionsSignatures returns signatures from the X-Registry-Supports-Signatures API extension,
// using the original data structures.
func (c *dockerClient) getExtensionsSignatures(ctx context.Context, ref dockerReference, manifestDigest digest.Digest) (*extensionSignatureList, error) {
+ if err := manifestDigest.Validate(); err != nil { // Make sure manifestDigest.String() does not contain any unexpected characters
+ return nil, err
+ }
path := fmt.Sprintf(extensionsSignaturePath, reference.Path(ref.ref), manifestDigest)
res, err := c.makeRequest(ctx, http.MethodGet, path, nil, nil, v2Auth, nil)
if err != nil {
@@ -1153,8 +1164,11 @@ func (c *dockerClient) getExtensionsSignatures(ctx context.Context, ref dockerRe
}
// sigstoreAttachmentTag returns a sigstore attachment tag for the specified digest.
-func sigstoreAttachmentTag(d digest.Digest) string {
- return strings.Replace(d.String(), ":", "-", 1) + ".sig"
+func sigstoreAttachmentTag(d digest.Digest) (string, error) {
+ if err := d.Validate(); err != nil { // Make sure d.String() doesn’t contain any unexpected characters
+ return "", err
+ }
+ return strings.Replace(d.String(), ":", "-", 1) + ".sig", nil
}
// Close removes resources associated with an initialized dockerClient, if any.
@@ -229,6 +229,9 @@ func (d *dockerImageDestination) PutBlobWithOptions(ctx context.Context, stream
// If the destination does not contain the blob, or it is unknown, blobExists ordinarily returns (false, -1, nil);
// it returns a non-nil error only on an unexpected failure.
func (d *dockerImageDestination) blobExists(ctx context.Context, repo reference.Named, digest digest.Digest, extraScope *authScope) (bool, int64, error) {
+ if err := digest.Validate(); err != nil { // Make sure digest.String() does not contain any unexpected characters
+ return false, -1, err
+ }
checkPath := fmt.Sprintf(blobsPath, reference.Path(repo), digest.String())
logrus.Debugf("Checking %s", checkPath)
res, err := d.c.makeRequest(ctx, http.MethodHead, checkPath, nil, nil, v2Auth, extraScope)
@@ -466,6 +469,7 @@ func (d *dockerImageDestination) PutManifest(ctx context.Context, m []byte, inst
// particular instance.
refTail = instanceDigest.String()
// Double-check that the manifest we've been given matches the digest we've been given.
+ // This also validates the format of instanceDigest.
matches, err := manifest.MatchesDigest(m, *instanceDigest)
if err != nil {
return fmt.Errorf("digesting manifest in PutManifest: %w", err)
@@ -632,11 +636,13 @@ func (d *dockerImageDestination) putSignaturesToLookaside(signatures []signature
// NOTE: Keep this in sync with docs/signature-protocols.md!
for i, signature := range signatures {
- sigURL := lookasideStorageURL(d.c.signatureBase, manifestDigest, i)
- err := d.putOneSignature(sigURL, signature)
+ sigURL, err := lookasideStorageURL(d.c.signatureBase, manifestDigest, i)
if err != nil {
return err
}
+ if err := d.putOneSignature(sigURL, signature); err != nil {
+ return err
+ }
}
// Remove any other signatures, if present.
// We stop at the first missing signature; if a previous deleting loop aborted
@@ -644,7 +650,10 @@ func (d *dockerImageDestination) putSignaturesToLookaside(signatures []signature
// is enough for dockerImageSource to stop looking for other signatures, so that
// is sufficient.
for i := len(signatures); ; i++ {
- sigURL := lookasideStorageURL(d.c.signatureBase, manifestDigest, i)
+ sigURL, err := lookasideStorageURL(d.c.signatureBase, manifestDigest, i)
+ if err != nil {
+ return err
+ }
missing, err := d.c.deleteOneSignature(sigURL)
if err != nil {
return err
@@ -775,8 +784,12 @@ func (d *dockerImageDestination) putSignaturesToSigstoreAttachments(ctx context.
if err != nil {
return err
}
+ attachmentTag, err := sigstoreAttachmentTag(manifestDigest)
+ if err != nil {
+ return err
+ }
logrus.Debugf("Uploading sigstore attachment manifest")
- return d.uploadManifest(ctx, manifestBlob, sigstoreAttachmentTag(manifestDigest))
+ return d.uploadManifest(ctx, manifestBlob, attachmentTag)
}
func layerMatchesSigstoreSignature(layer imgspecv1.Descriptor, mimeType string,
@@ -892,6 +905,7 @@ func (d *dockerImageDestination) putSignaturesToAPIExtension(ctx context.Context
return err
}
+ // manifestDigest is known to be valid because it was not rejected by getExtensionsSignatures above.
path := fmt.Sprintf(extensionsSignaturePath, reference.Path(d.ref.ref), manifestDigest.String())
res, err := d.c.makeRequest(ctx, http.MethodPut, path, nil, bytes.NewReader(body), v2Auth, nil)
if err != nil {
@@ -194,6 +194,9 @@ func simplifyContentType(contentType string) string {
// this never happens if the primary manifest is not a manifest list (e.g. if the source never returns manifest lists).
func (s *dockerImageSource) GetManifest(ctx context.Context, instanceDigest *digest.Digest) ([]byte, string, error) {
if instanceDigest != nil {
+ if err := instanceDigest.Validate(); err != nil { // Make sure instanceDigest.String() does not contain any unexpected characters
+ return nil, "", err
+ }
return s.fetchManifest(ctx, instanceDigest.String())
}
err := s.ensureManifestIsLoaded(ctx)
@@ -203,6 +206,8 @@ func (s *dockerImageSource) GetManifest(ctx context.Context, instanceDigest *dig
return s.cachedManifest, s.cachedManifestMIMEType, nil
}
+// fetchManifest fetches a manifest for tagOrDigest.
+// The caller is responsible for ensuring tagOrDigest uses the expected format.
func (s *dockerImageSource) fetchManifest(ctx context.Context, tagOrDigest string) ([]byte, string, error) {
return s.c.fetchManifest(ctx, s.physicalRef, tagOrDigest)
}
@@ -352,6 +357,9 @@ func (s *dockerImageSource) GetBlobAt(ctx context.Context, info types.BlobInfo,
return nil, nil, fmt.Errorf("external URLs not supported with GetBlobAt")
}
+ if err := info.Digest.Validate(); err != nil { // Make sure info.Digest.String() does not contain any unexpected characters
+ return nil, nil, err
+ }
path := fmt.Sprintf(blobsPath, reference.Path(s.physicalRef.ref), info.Digest.String())
logrus.Debugf("Downloading %s", path)
res, err := s.c.makeRequest(ctx, http.MethodGet, path, headers, nil, v2Auth, nil)
@@ -462,7 +470,10 @@ func (s *dockerImageSource) getSignaturesFromLookaside(ctx context.Context, inst
return nil, fmt.Errorf("server provided %d signatures, assuming that's unreasonable and a server error", maxLookasideSignatures)
}
- sigURL := lookasideStorageURL(s.c.signatureBase, manifestDigest, i)
+ sigURL, err := lookasideStorageURL(s.c.signatureBase, manifestDigest, i)
+ if err != nil {
+ return nil, err
+ }
signature, missing, err := s.getOneSignature(ctx, sigURL)
if err != nil {
return nil, err
@@ -660,7 +671,10 @@ func deleteImage(ctx context.Context, sys *types.SystemContext, ref dockerRefere
}
for i := 0; ; i++ {
- sigURL := lookasideStorageURL(c.signatureBase, manifestDigest, i)
+ sigURL, err := lookasideStorageURL(c.signatureBase, manifestDigest, i)
+ if err != nil {
+ return err
+ }
missing, err := c.deleteOneSignature(sigURL)
if err != nil {
return err
@@ -111,11 +111,19 @@ func (d *Destination) PutBlobWithOptions(ctx context.Context, stream io.Reader,
return private.UploadedBlob{}, fmt.Errorf("reading Config file stream: %w", err)
}
d.config = buf
- if err := d.archive.sendFileLocked(d.archive.configPath(inputInfo.Digest), inputInfo.Size, bytes.NewReader(buf)); err != nil {
+ configPath, err := d.archive.configPath(inputInfo.Digest)
+ if err != nil {
+ return private.UploadedBlob{}, err
+ }
+ if err := d.archive.sendFileLocked(configPath, inputInfo.Size, bytes.NewReader(buf)); err != nil {
return private.UploadedBlob{}, fmt.Errorf("writing Config file: %w", err)
}
} else {
- if err := d.archive.sendFileLocked(d.archive.physicalLayerPath(inputInfo.Digest), inputInfo.Size, stream); err != nil {
+ layerPath, err := d.archive.physicalLayerPath(inputInfo.Digest)
+ if err != nil {
+ return private.UploadedBlob{}, err
+ }
+ if err := d.archive.sendFileLocked(layerPath, inputInfo.Size, stream); err != nil {
return private.UploadedBlob{}, err
}
}
@@ -95,7 +95,10 @@ func (w *Writer) ensureSingleLegacyLayerLocked(layerID string, layerDigest diges
if !w.legacyLayers.Contains(layerID) {
// Create a symlink for the legacy format, where there is one subdirectory per layer ("image").
// See also the comment in physicalLayerPath.
- physicalLayerPath := w.physicalLayerPath(layerDigest)
+ physicalLayerPath, err := w.physicalLayerPath(layerDigest)
+ if err != nil {
+ return err
+ }
if err := w.sendSymlinkLocked(filepath.Join(layerID, legacyLayerFileName), filepath.Join("..", physicalLayerPath)); err != nil {
return fmt.Errorf("creating layer symbolic link: %w", err)
}
@@ -139,6 +142,9 @@ func (w *Writer) writeLegacyMetadataLocked(layerDescriptors []manifest.Schema2De
}
// This chainID value matches the computation in docker/docker/layer.CreateChainID …
+ if err := l.Digest.Validate(); err != nil { // This should never fail on this code path, still: make sure the chainID computation is unambiguous.
+ return err
+ }
if chainID == "" {
chainID = l.Digest
} else {
@@ -204,12 +210,20 @@ func checkManifestItemsMatch(a, b *ManifestItem) error {
func (w *Writer) ensureManifestItemLocked(layerDescriptors []manifest.Schema2Descriptor, configDigest digest.Digest, repoTags []reference.NamedTagged) error {
layerPaths := []string{}
for _, l := range layerDescriptors {
- layerPaths = append(layerPaths, w.physicalLayerPath(l.Digest))
+ p, err := w.physicalLayerPath(l.Digest)
+ if err != nil {
+ return err
+ }
+ layerPaths = append(layerPaths, p)
}
var item *ManifestItem
+ configPath, err := w.configPath(configDigest)
+ if err != nil {
+ return err
+ }
newItem := ManifestItem{
- Config: w.configPath(configDigest),
+ Config: configPath,
RepoTags: []string{},
Layers: layerPaths,
Parent: "", // We don’t have this information
@@ -294,21 +308,27 @@ func (w *Writer) Close() error {
// configPath returns a path we choose for storing a config with the specified digest.
// NOTE: This is an internal implementation detail, not a format property, and can change
// any time.
-func (w *Writer) configPath(configDigest digest.Digest) string {
- return configDigest.Hex() + ".json"
+func (w *Writer) configPath(configDigest digest.Digest) (string, error) {
+ if err := configDigest.Validate(); err != nil { // digest.Digest.Hex() panics on failure, and could possibly result in unexpected paths, so validate explicitly.
+ return "", err
+ }
+ return configDigest.Hex() + ".json", nil
}
// physicalLayerPath returns a path we choose for storing a layer with the specified digest
// (the actual path, i.e. a regular file, not a symlink that may be used in the legacy format).
// NOTE: This is an internal implementation detail, not a format property, and can change
// any time.
-func (w *Writer) physicalLayerPath(layerDigest digest.Digest) string {
+func (w *Writer) physicalLayerPath(layerDigest digest.Digest) (string, error) {
+ if err := layerDigest.Validate(); err != nil { // digest.Digest.Hex() panics on failure, and could possibly result in unexpected paths, so validate explicitly.
+ return "", err
+ }
// Note that this can't be e.g. filepath.Join(l.Digest.Hex(), legacyLayerFileName); due to the way
// writeLegacyMetadata constructs layer IDs differently from inputinfo.Digest values (as described
// inside it), most of the layers would end up in subdirectories alone without any metadata; (docker load)
// tries to load every subdirectory as an image and fails if the config is missing. So, keep the layers
// in the root of the tarball.
- return layerDigest.Hex() + ".tar"
+ return layerDigest.Hex() + ".tar", nil
}
type tarFI struct {
@@ -286,8 +286,11 @@ func (ns registryNamespace) signatureTopLevel(write bool) string {
// lookasideStorageURL returns an URL usable for accessing signature index in base with known manifestDigest.
// base is not nil from the caller
// NOTE: Keep this in sync with docs/signature-protocols.md!
-func lookasideStorageURL(base lookasideStorageBase, manifestDigest digest.Digest, index int) *url.URL {
+func lookasideStorageURL(base lookasideStorageBase, manifestDigest digest.Digest, index int) (*url.URL, error) {
+ if err := manifestDigest.Validate(); err != nil { // digest.Digest.Hex() panics on failure, and could possibly result in a path with ../, so validate explicitly.
+ return nil, err
+ }
sigURL := *base
sigURL.Path = fmt.Sprintf("%s@%s=%s/signature-%d", sigURL.Path, manifestDigest.Algorithm(), manifestDigest.Hex(), index+1)
- return &sigURL
+ return &sigURL, nil
}
@@ -109,6 +109,9 @@ func (s *openshiftImageSource) GetSignaturesWithFormat(ctx context.Context, inst
}
imageStreamImageName = s.imageStreamImageName
} else {
+ if err := instanceDigest.Validate(); err != nil { // Make sure instanceDigest.String() does not contain any unexpected characters
+ return nil, err
+ }
imageStreamImageName = instanceDigest.String()
}
image, err := s.client.getImage(ctx, imageStreamImageName)
@@ -345,6 +345,10 @@ func (d *ostreeImageDestination) TryReusingBlobWithOptions(ctx context.Context,
}
d.repo = repo
}
+
+ if err := info.Digest.Validate(); err != nil { // digest.Digest.Hex() panics on failure, so validate explicitly.
+ return false, private.ReusedBlob{}, err
+ }
branch := fmt.Sprintf("ociimage/%s", info.Digest.Hex())
found, data, err := readMetadata(d.repo, branch, "docker.uncompressed_digest")
@@ -470,12 +474,18 @@ func (d *ostreeImageDestination) Commit(context.Context, types.UnparsedImage) er
return nil
}
for _, layer := range d.schema.LayersDescriptors {
+ if err := layer.Digest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, so validate explicitly.
+ return err
+ }
hash := layer.Digest.Hex()
if err = checkLayer(hash); err != nil {
return err
}
}
for _, layer := range d.schema.FSLayers {
+ if err := layer.BlobSum.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, so validate explicitly.
+ return err
+ }
hash := layer.BlobSum.Hex()
if err = checkLayer(hash); err != nil {
return err
@@ -286,7 +286,9 @@ func (s *ostreeImageSource) readSingleFile(commit, path string) (io.ReadCloser,
// The Digest field in BlobInfo is guaranteed to be provided, Size may be -1 and MediaType may be optionally provided.
// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location.
func (s *ostreeImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (io.ReadCloser, int64, error) {
-
+ if err := info.Digest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, so validate explicitly.
+ return nil, -1, err
+ }
blob := info.Digest.Hex()
// Ensure s.compressed is initialized. It is build by LayerInfosForCopy.
@@ -78,12 +78,15 @@ func (b *BlobCache) DeleteImage(ctx context.Context, sys *types.SystemContext) e
}
// blobPath returns the path appropriate for storing a blob with digest.
-func (b *BlobCache) blobPath(digest digest.Digest, isConfig bool) string {
+func (b *BlobCache) blobPath(digest digest.Digest, isConfig bool) (string, error) {
+ if err := digest.Validate(); err != nil { // Make sure digest.String() does not contain any unexpected characters
+ return "", err
+ }
baseName := digest.String()
if isConfig {
baseName += ".config"
}
- return filepath.Join(b.directory, baseName)
+ return filepath.Join(b.directory, baseName), nil
}
// findBlob checks if we have a blob for info in cache (whether a config or not)
@@ -95,7 +98,10 @@ func (b *BlobCache) findBlob(info types.BlobInfo) (string, int64, bool, error) {
}
for _, isConfig := range []bool{false, true} {
- path := b.blobPath(info.Digest, isConfig)
+ path, err := b.blobPath(info.Digest, isConfig)
+ if err != nil {
+ return "", -1, false, err
+ }
fileInfo, err := os.Stat(path)
if err == nil && (info.Size == -1 || info.Size == fileInfo.Size()) {
return path, fileInfo.Size(), isConfig, nil
@@ -80,47 +80,58 @@ func (d *blobCacheDestination) IgnoresEmbeddedDockerReference() bool {
// and this new file.
func (d *blobCacheDestination) saveStream(wg *sync.WaitGroup, decompressReader io.ReadCloser, tempFile *os.File, compressedFilename string, compressedDigest digest.Digest, isConfig bool, alternateDigest *digest.Digest) {
defer wg.Done()
- // Decompress from and digest the reading end of that pipe.
- decompressed, err3 := archive.DecompressStream(decompressReader)
+ defer decompressReader.Close()
+
+ succeeded := false
+ defer func() {
+ if !succeeded {
+ // Remove the temporary file.
+ if err := os.Remove(tempFile.Name()); err != nil {
+ logrus.Debugf("error cleaning up temporary file %q for decompressed copy of blob %q: %v", tempFile.Name(), compressedDigest.String(), err)
+ }
+ }
+ }()
+
digester := digest.Canonical.Digester()
- if err3 == nil {
+ if err := func() error { // A scope for defer
+ defer tempFile.Close()
+
+ // Decompress from and digest the reading end of that pipe.
+ decompressed, err := archive.DecompressStream(decompressReader)
+ if err != nil {
+ // Drain the pipe to keep from stalling the PutBlob() thread.
+ if _, err2 := io.Copy(io.Discard, decompressReader); err2 != nil {
+ logrus.Debugf("error draining the pipe: %v", err2)
+ }
+ return err
+ }
+ defer decompressed.Close()
// Read the decompressed data through the filter over the pipe, blocking until the
// writing end is closed.
- _, err3 = io.Copy(io.MultiWriter(tempFile, digester.Hash()), decompressed)
- } else {
- // Drain the pipe to keep from stalling the PutBlob() thread.
- if _, err := io.Copy(io.Discard, decompressReader); err != nil {
- logrus.Debugf("error draining the pipe: %v", err)
- }
+ _, err = io.Copy(io.MultiWriter(tempFile, digester.Hash()), decompressed)
+ return err
+ }(); err != nil {
+ return
}
- decompressReader.Close()
- decompressed.Close()
- tempFile.Close()
+
// Determine the name that we should give to the uncompressed copy of the blob.
- decompressedFilename := d.reference.blobPath(digester.Digest(), isConfig)
- if err3 == nil {
- // Rename the temporary file.
- if err3 = os.Rename(tempFile.Name(), decompressedFilename); err3 != nil {
- logrus.Debugf("error renaming new decompressed copy of blob %q into place at %q: %v", digester.Digest().String(), decompressedFilename, err3)
- // Remove the temporary file.
- if err3 = os.Remove(tempFile.Name()); err3 != nil {
- logrus.Debugf("error cleaning up temporary file %q for decompressed copy of blob %q: %v", tempFile.Name(), compressedDigest.String(), err3)
- }
- } else {
- *alternateDigest = digester.Digest()
- // Note the relationship between the two files.
- if err3 = ioutils.AtomicWriteFile(decompressedFilename+compressedNote, []byte(compressedDigest.String()), 0600); err3 != nil {
- logrus.Debugf("error noting that the compressed version of %q is %q: %v", digester.Digest().String(), compressedDigest.String(), err3)
- }
- if err3 = ioutils.AtomicWriteFile(compressedFilename+decompressedNote, []byte(digester.Digest().String()), 0600); err3 != nil {
- logrus.Debugf("error noting that the decompressed version of %q is %q: %v", compressedDigest.String(), digester.Digest().String(), err3)
- }
- }
- } else {
- // Remove the temporary file.
- if err3 = os.Remove(tempFile.Name()); err3 != nil {
- logrus.Debugf("error cleaning up temporary file %q for decompressed copy of blob %q: %v", tempFile.Name(), compressedDigest.String(), err3)
- }
+ decompressedFilename, err := d.reference.blobPath(digester.Digest(), isConfig)
+ if err != nil {
+ return
+ }
+ // Rename the temporary file.
+ if err := os.Rename(tempFile.Name(), decompressedFilename); err != nil {
+ logrus.Debugf("error renaming new decompressed copy of blob %q into place at %q: %v", digester.Digest().String(), decompressedFilename, err)
+ return
+ }
+ succeeded = true
+ *alternateDigest = digester.Digest()
+ // Note the relationship between the two files.
+ if err := ioutils.AtomicWriteFile(decompressedFilename+compressedNote, []byte(compressedDigest.String()), 0600); err != nil {
+ logrus.Debugf("error noting that the compressed version of %q is %q: %v", digester.Digest().String(), compressedDigest.String(), err)
+ }
+ if err := ioutils.AtomicWriteFile(compressedFilename+decompressedNote, []byte(digester.Digest().String()), 0600); err != nil {
+ logrus.Debugf("error noting that the decompressed version of %q is %q: %v", compressedDigest.String(), digester.Digest().String(), err)
}
}
@@ -145,7 +156,10 @@ func (d *blobCacheDestination) PutBlobWithOptions(ctx context.Context, stream io
needToWait := false
compression := archive.Uncompressed
if inputInfo.Digest != "" {
- filename := d.reference.blobPath(inputInfo.Digest, options.IsConfig)
+ filename, err2 := d.reference.blobPath(inputInfo.Digest, options.IsConfig)
+ if err2 != nil {
+ return private.UploadedBlob{}, err2
+ }
tempfile, err = os.CreateTemp(filepath.Dir(filename), filepath.Base(filename))
if err == nil {
stream = io.TeeReader(stream, tempfile)
@@ -274,7 +288,10 @@ func (d *blobCacheDestination) PutManifest(ctx context.Context, manifestBytes []
if err != nil {
logrus.Warnf("error digesting manifest %q: %v", string(manifestBytes), err)
} else {
- filename := d.reference.blobPath(manifestDigest, false)
+ filename, err := d.reference.blobPath(manifestDigest, false)
+ if err != nil {
+ return err
+ }
if err = ioutils.AtomicWriteFile(filename, manifestBytes, 0600); err != nil {
logrus.Warnf("error saving manifest as %q: %v", filename, err)
}
@@ -56,7 +56,10 @@ func (s *blobCacheSource) Close() error {
func (s *blobCacheSource) GetManifest(ctx context.Context, instanceDigest *digest.Digest) ([]byte, string, error) {
if instanceDigest != nil {
- filename := s.reference.blobPath(*instanceDigest, false)
+ filename, err := s.reference.blobPath(*instanceDigest, false)
+ if err != nil {
+ return nil, "", err
+ }
manifestBytes, err := os.ReadFile(filename)
if err == nil {
s.cacheHits++
@@ -136,8 +139,10 @@ func (s *blobCacheSource) LayerInfosForCopy(ctx context.Context, instanceDigest
replacedInfos := make([]types.BlobInfo, 0, len(infos))
for _, info := range infos {
var replaceDigest []byte
- var err error
- blobFile := s.reference.blobPath(info.Digest, false)
+ blobFile, err := s.reference.blobPath(info.Digest, false)
+ if err != nil {
+ return nil, err
+ }
var alternate string
switch s.reference.compress {
case types.Compress:
@@ -148,7 +153,10 @@ func (s *blobCacheSource) LayerInfosForCopy(ctx context.Context, instanceDigest
replaceDigest, err = os.ReadFile(alternate)
}
if err == nil && digest.Digest(replaceDigest).Validate() == nil {
- alternate = s.reference.blobPath(digest.Digest(replaceDigest), false)
+ alternate, err = s.reference.blobPath(digest.Digest(replaceDigest), false)
+ if err != nil {
+ return nil, err
+ }
fileInfo, err := os.Stat(alternate)
if err == nil {
switch info.MediaType {
@@ -324,6 +324,13 @@ func (s *storageImageDestination) TryReusingBlobWithOptions(ctx context.Context,
// tryReusingBlobAsPending implements TryReusingBlobWithOptions for (digest, size or -1), filling s.blobDiffIDs and other metadata.
// The caller must arrange the blob to be eventually committed using s.commitLayer().
func (s *storageImageDestination) tryReusingBlobAsPending(digest digest.Digest, size int64, options *private.TryReusingBlobOptions) (bool, private.ReusedBlob, error) {
+ if digest == "" {
+ return false, private.ReusedBlob{}, errors.New(`Can not check for a blob with unknown digest`)
+ }
+ if err := digest.Validate(); err != nil {
+ return false, private.ReusedBlob{}, fmt.Errorf("Can not check for a blob with invalid digest: %w", err)
+ }
+
// lock the entire method as it executes fairly quickly
s.lock.Lock()
defer s.lock.Unlock()
@@ -344,13 +351,6 @@ func (s *storageImageDestination) tryReusingBlobAsPending(digest digest.Digest,
}
}
- if digest == "" {
- return false, private.ReusedBlob{}, errors.New(`Can not check for a blob with unknown digest`)
- }
- if err := digest.Validate(); err != nil {
- return false, private.ReusedBlob{}, fmt.Errorf("Can not check for a blob with invalid digest: %w", err)
- }
-
// Check if we've already cached it in a file.
if size, ok := s.fileSizes[digest]; ok {
return true, private.ReusedBlob{
@@ -803,8 +803,12 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t
if err != nil {
return fmt.Errorf("digesting top-level manifest: %w", err)
}
+ key, err := manifestBigDataKey(manifestDigest)
+ if err != nil {
+ return err
+ }
options.BigData = append(options.BigData, storage.ImageBigDataOption{
- Key: manifestBigDataKey(manifestDigest),
+ Key: key,
Data: toplevelManifest,
Digest: manifestDigest,
})
@@ -812,8 +816,12 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t
// Set up to save the image's manifest. Allow looking it up by digest by using the key convention defined by the Store.
// Record the manifest twice: using a digest-specific key to allow references to that specific digest instance,
// and using storage.ImageDigestBigDataKey for future users that don’t specify any digest and for compatibility with older readers.
+ key, err := manifestBigDataKey(s.manifestDigest)
+ if err != nil {
+ return err
+ }
options.BigData = append(options.BigData, storage.ImageBigDataOption{
- Key: manifestBigDataKey(s.manifestDigest),
+ Key: key,
Data: s.manifest,
Digest: s.manifestDigest,
})
@@ -831,8 +839,12 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t
})
}
for instanceDigest, signatures := range s.signatureses {
+ key, err := signatureBigDataKey(instanceDigest)
+ if err != nil {
+ return err
+ }
options.BigData = append(options.BigData, storage.ImageBigDataOption{
- Key: signatureBigDataKey(instanceDigest),
+ Key: key,
Data: signatures,
Digest: digest.Canonical.FromBytes(signatures),
})
@@ -26,14 +26,20 @@ type storageImageCloser struct {
// manifestBigDataKey returns a key suitable for recording a manifest with the specified digest using storage.Store.ImageBigData and related functions.
// If a specific manifest digest is explicitly requested by the user, the key returned by this function should be used preferably;
// for compatibility, if a manifest is not available under this key, check also storage.ImageDigestBigDataKey
-func manifestBigDataKey(digest digest.Digest) string {
- return storage.ImageDigestManifestBigDataNamePrefix + "-" + digest.String()
+func manifestBigDataKey(digest digest.Digest) (string, error) {
+ if err := digest.Validate(); err != nil { // Make sure info.Digest.String() uses the expected format and does not collide with other BigData keys.
+ return "", err
+ }
+ return storage.ImageDigestManifestBigDataNamePrefix + "-" + digest.String(), nil
}
// signatureBigDataKey returns a key suitable for recording the signatures associated with the manifest with the specified digest using storage.Store.ImageBigData and related functions.
// If a specific manifest digest is explicitly requested by the user, the key returned by this function should be used preferably;
-func signatureBigDataKey(digest digest.Digest) string {
- return "signature-" + digest.Encoded()
+func signatureBigDataKey(digest digest.Digest) (string, error) {
+ if err := digest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, so validate explicitly.
+ return "", err
+ }
+ return "signature-" + digest.Encoded(), nil
}
// Size() returns the previously-computed size of the image, with no error.
@@ -73,7 +73,10 @@ func multiArchImageMatchesSystemContext(store storage.Store, img *storage.Image,
// We don't need to care about storage.ImageDigestBigDataKey because
// manifests lists are only stored into storage by c/image versions
// that know about manifestBigDataKey, and only using that key.
- key := manifestBigDataKey(manifestDigest)
+ key, err := manifestBigDataKey(manifestDigest)
+ if err != nil {
+ return false // This should never happen, manifestDigest comes from a reference.Digested, and that validates the format.
+ }
manifestBytes, err := store.ImageBigData(img.ID, key)
if err != nil {
return false
@@ -95,7 +98,10 @@ func multiArchImageMatchesSystemContext(store storage.Store, img *storage.Image,
if err != nil {
return false
}
- key = manifestBigDataKey(chosenInstance)
+ key, err = manifestBigDataKey(chosenInstance)
+ if err != nil {
+ return false
+ }
_, err = store.ImageBigData(img.ID, key)
return err == nil // true if img.ID is based on chosenInstance.
}
@@ -202,7 +202,10 @@ func (s *storageImageSource) getBlobAndLayerID(digest digest.Digest, layers []st
// GetManifest() reads the image's manifest.
func (s *storageImageSource) GetManifest(ctx context.Context, instanceDigest *digest.Digest) (manifestBlob []byte, mimeType string, err error) {
if instanceDigest != nil {
- key := manifestBigDataKey(*instanceDigest)
+ key, err := manifestBigDataKey(*instanceDigest)
+ if err != nil {
+ return nil, "", err
+ }
blob, err := s.imageRef.transport.store.ImageBigData(s.image.ID, key)
if err != nil {
return nil, "", fmt.Errorf("reading manifest for image instance %q: %w", *instanceDigest, err)
@@ -214,7 +217,10 @@ func (s *storageImageSource) GetManifest(ctx context.Context, instanceDigest *di
// Prefer the manifest corresponding to the user-specified digest, if available.
if s.imageRef.named != nil {
if digested, ok := s.imageRef.named.(reference.Digested); ok {
- key := manifestBigDataKey(digested.Digest())
+ key, err := manifestBigDataKey(digested.Digest())
+ if err != nil {
+ return nil, "", err
+ }
blob, err := s.imageRef.transport.store.ImageBigData(s.image.ID, key)
if err != nil && !os.IsNotExist(err) { // os.IsNotExist is true if the image exists but there is no data corresponding to key
return nil, "", err
@@ -329,7 +335,14 @@ func (s *storageImageSource) GetSignaturesWithFormat(ctx context.Context, instan
instance := "default instance"
if instanceDigest != nil {
signatureSizes = s.SignaturesSizes[*instanceDigest]
- key = signatureBigDataKey(*instanceDigest)
+ k, err := signatureBigDataKey(*instanceDigest)
+ if err != nil {
+ return nil, err
+ }
+ key = k
+ if err := instanceDigest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, so validate explicitly.
+ return nil, err
+ }
instance = instanceDigest.Encoded()
}
if len(signatureSizes) > 0 {
@@ -8,7 +8,7 @@ const (
// VersionMinor is for functionality in a backwards-compatible manner
VersionMinor = 29
// VersionPatch is for backwards-compatible bug fixes
- VersionPatch = 4
+ VersionPatch = 5
// VersionDev indicates development branch. Releases will be empty string.
VersionDev = ""
@@ -123,9 +123,24 @@ func addPubKeys(joseRecipients *[]jose.Recipient, pubKeys [][]byte) error {
}
alg := jose.RSA_OAEP
- switch key.(type) {
+ switch key := key.(type) {
case *ecdsa.PublicKey:
alg = jose.ECDH_ES_A256KW
+ case *jose.JSONWebKey:
+ if key.Algorithm != "" {
+ alg = jose.KeyAlgorithm(key.Algorithm)
+ switch alg {
+ /* accepted algorithms */
+ case jose.RSA_OAEP:
+ case jose.RSA_OAEP_256:
+ case jose.ECDH_ES_A128KW:
+ case jose.ECDH_ES_A192KW:
+ case jose.ECDH_ES_A256KW:
+ /* all others are rejected */
+ default:
+ return fmt.Errorf("%s is an unsupported JWE key algorithm", alg)
+ }
+ }
}
*joseRecipients = append(*joseRecipients, jose.Recipient{
@@ -38,6 +38,15 @@ func CreateRSAKey(bits int) (*rsa.PrivateKey, error) {
return key, nil
}
+// CreateECDSAKey creates an elliptic curve key for the given curve
+func CreateECDSAKey(curve elliptic.Curve) (*ecdsa.PrivateKey, error) {
+ key, err := ecdsa.GenerateKey(curve, rand.Reader)
+ if err != nil {
+ return nil, fmt.Errorf("ecdsa.GenerateKey failed: %w", err)
+ }
+ return key, nil
+}
+
// CreateRSATestKey creates an RSA key of the given size and returns
// the public and private key in PEM or DER format
func CreateRSATestKey(bits int, password []byte, pemencode bool) ([]byte, []byte, error) {
@@ -85,9 +94,9 @@ func CreateRSATestKey(bits int, password []byte, pemencode bool) ([]byte, []byte
// CreateECDSATestKey creates and elliptic curve key for the given curve and returns
// the public and private key in DER format
func CreateECDSATestKey(curve elliptic.Curve) ([]byte, []byte, error) {
- key, err := ecdsa.GenerateKey(curve, rand.Reader)
+ key, err := CreateECDSAKey(curve)
if err != nil {
- return nil, nil, fmt.Errorf("ecdsa.GenerateKey failed: %w", err)
+ return nil, nil, err
}
pubData, err := x509.MarshalPKIXPublicKey(&key.PublicKey)
@@ -285,6 +285,9 @@ func (ctx rsaDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm
switch alg {
case RS256, RS384, RS512:
+ // TODO(https://github.com/go-jose/go-jose/issues/40): As of go1.20, the
+ // random parameter is legacy and ignored, and it can be nil.
+ // https://cs.opensource.google/go/go/+/refs/tags/go1.20:src/crypto/rsa/pkcs1v15.go;l=263;bpv=0;bpt=1
out, err = rsa.SignPKCS1v15(RandReader, ctx.privateKey, hash, hashed)
case PS256, PS384, PS512:
out, err = rsa.SignPSS(RandReader, ctx.privateKey, hash, hashed, &rsa.PSSOptions{
@@ -21,7 +21,6 @@ import (
"crypto/rsa"
"errors"
"fmt"
- "reflect"
"github.com/go-jose/go-jose/v3/json"
)
@@ -76,14 +75,24 @@ type recipientKeyInfo struct {
type EncrypterOptions struct {
Compression CompressionAlgorithm
- // Optional map of additional keys to be inserted into the protected header
- // of a JWS object. Some specifications which make use of JWS like to insert
- // additional values here. All values must be JSON-serializable.
+ // Optional map of name/value pairs to be inserted into the protected
+ // header of a JWS object. Some specifications which make use of
+ // JWS require additional values here.
+ //
+ // Values will be serialized by [json.Marshal] and must be valid inputs to
+ // that function.
+ //
+ // [json.Marshal]: https://pkg.go.dev/encoding/json#Marshal
ExtraHeaders map[HeaderKey]interface{}
}
// WithHeader adds an arbitrary value to the ExtraHeaders map, initializing it
-// if necessary. It returns itself and so can be used in a fluent style.
+// if necessary, and returns the updated EncrypterOptions.
+//
+// The v parameter will be serialized by [json.Marshal] and must be a valid
+// input to that function.
+//
+// [json.Marshal]: https://pkg.go.dev/encoding/json#Marshal
func (eo *EncrypterOptions) WithHeader(k HeaderKey, v interface{}) *EncrypterOptions {
if eo.ExtraHeaders == nil {
eo.ExtraHeaders = map[HeaderKey]interface{}{}
@@ -111,7 +120,17 @@ func (eo *EncrypterOptions) WithType(typ ContentType) *EncrypterOptions {
// default of 100000 will be used for the count and a 128-bit random salt will
// be generated.
type Recipient struct {
- Algorithm KeyAlgorithm
+ Algorithm KeyAlgorithm
+ // Key must have one of these types:
+ // - ed25519.PublicKey
+ // - *ecdsa.PublicKey
+ // - *rsa.PublicKey
+ // - *JSONWebKey
+ // - JSONWebKey
+ // - []byte (a symmetric key)
+ // - Any type that satisfies the OpaqueKeyEncrypter interface
+ //
+ // The type of Key must match the value of Algorithm.
Key interface{}
KeyID string
PBES2Count int
@@ -150,16 +169,17 @@ func NewEncrypter(enc ContentEncryption, rcpt Recipient, opts *EncrypterOptions)
switch rcpt.Algorithm {
case DIRECT:
// Direct encryption mode must be treated differently
- if reflect.TypeOf(rawKey) != reflect.TypeOf([]byte{}) {
+ keyBytes, ok := rawKey.([]byte)
+ if !ok {
return nil, ErrUnsupportedKeyType
}
- if encrypter.cipher.keySize() != len(rawKey.([]byte)) {
+ if encrypter.cipher.keySize() != len(keyBytes) {
return nil, ErrInvalidKeySize
}
encrypter.keyGenerator = staticKeyGenerator{
- key: rawKey.([]byte),
+ key: keyBytes,
}
- recipientInfo, _ := newSymmetricRecipient(rcpt.Algorithm, rawKey.([]byte))
+ recipientInfo, _ := newSymmetricRecipient(rcpt.Algorithm, keyBytes)
recipientInfo.keyID = keyID
if rcpt.KeyID != "" {
recipientInfo.keyID = rcpt.KeyID
@@ -168,16 +188,16 @@ func NewEncrypter(enc ContentEncryption, rcpt Recipient, opts *EncrypterOptions)
return encrypter, nil
case ECDH_ES:
// ECDH-ES (w/o key wrapping) is similar to DIRECT mode
- typeOf := reflect.TypeOf(rawKey)
- if typeOf != reflect.TypeOf(&ecdsa.PublicKey{}) {
+ keyDSA, ok := rawKey.(*ecdsa.PublicKey)
+ if !ok {
return nil, ErrUnsupportedKeyType
}
encrypter.keyGenerator = ecKeyGenerator{
size: encrypter.cipher.keySize(),
algID: string(enc),
- publicKey: rawKey.(*ecdsa.PublicKey),
+ publicKey: keyDSA,
}
- recipientInfo, _ := newECDHRecipient(rcpt.Algorithm, rawKey.(*ecdsa.PublicKey))
+ recipientInfo, _ := newECDHRecipient(rcpt.Algorithm, keyDSA)
recipientInfo.keyID = keyID
if rcpt.KeyID != "" {
recipientInfo.keyID = rcpt.KeyID
@@ -270,9 +290,8 @@ func makeJWERecipient(alg KeyAlgorithm, encryptionKey interface{}) (recipientKey
recipient, err := makeJWERecipient(alg, encryptionKey.Key)
recipient.keyID = encryptionKey.KeyID
return recipient, err
- }
- if encrypter, ok := encryptionKey.(OpaqueKeyEncrypter); ok {
- return newOpaqueKeyEncrypter(alg, encrypter)
+ case OpaqueKeyEncrypter:
+ return newOpaqueKeyEncrypter(alg, encryptionKey)
}
return recipientKeyInfo{}, ErrUnsupportedKeyType
}
@@ -300,11 +319,11 @@ func newDecrypter(decryptionKey interface{}) (keyDecrypter, error) {
return newDecrypter(decryptionKey.Key)
case *JSONWebKey:
return newDecrypter(decryptionKey.Key)
+ case OpaqueKeyDecrypter:
+ return &opaqueKeyDecrypter{decrypter: decryptionKey}, nil
+ default:
+ return nil, ErrUnsupportedKeyType
}
- if okd, ok := decryptionKey.(OpaqueKeyDecrypter); ok {
- return &opaqueKeyDecrypter{decrypter: okd}, nil
- }
- return nil, ErrUnsupportedKeyType
}
// Implementation of encrypt method producing a JWE object.
@@ -403,9 +422,27 @@ func (ctx *genericEncrypter) Options() EncrypterOptions {
}
}
-// Decrypt and validate the object and return the plaintext. Note that this
-// function does not support multi-recipient, if you desire multi-recipient
+// Decrypt and validate the object and return the plaintext. This
+// function does not support multi-recipient. If you desire multi-recipient
// decryption use DecryptMulti instead.
+//
+// The decryptionKey argument must contain a private or symmetric key
+// and must have one of these types:
+// - *ecdsa.PrivateKey
+// - *rsa.PrivateKey
+// - *JSONWebKey
+// - JSONWebKey
+// - *JSONWebKeySet
+// - JSONWebKeySet
+// - []byte (a symmetric key)
+// - string (a symmetric key)
+// - Any type that satisfies the OpaqueKeyDecrypter interface.
+//
+// Note that ed25519 is only available for signatures, not encryption, so is
+// not an option here.
+//
+// Automatically decompresses plaintext, but returns an error if the decompressed
+// data would be >250kB or >10x the size of the compressed data, whichever is larger.
func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error) {
headers := obj.mergedHeaders(nil)
@@ -462,15 +499,24 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error)
// The "zip" header parameter may only be present in the protected header.
if comp := obj.protected.getCompression(); comp != "" {
plaintext, err = decompress(comp, plaintext)
+ if err != nil {
+ return nil, fmt.Errorf("go-jose/go-jose: failed to decompress plaintext: %v", err)
+ }
}
- return plaintext, err
+ return plaintext, nil
}
// DecryptMulti decrypts and validates the object and returns the plaintexts,
// with support for multiple recipients. It returns the index of the recipient
// for which the decryption was successful, the merged headers for that recipient,
// and the plaintext.
+//
+// The decryptionKey argument must have one of the types allowed for the
+// decryptionKey argument of Decrypt().
+//
+// Automatically decompresses plaintext, but returns an error if the decompressed
+// data would be >250kB or >3x the size of the compressed data, whichever is larger.
func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Header, []byte, error) {
globalHeaders := obj.mergedHeaders(nil)
@@ -532,7 +578,10 @@ func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Heade
// The "zip" header parameter may only be present in the protected header.
if comp := obj.protected.getCompression(); comp != "" {
- plaintext, _ = decompress(comp, plaintext)
+ plaintext, err = decompress(comp, plaintext)
+ if err != nil {
+ return -1, Header{}, nil, fmt.Errorf("go-jose/go-jose: failed to decompress plaintext: %v", err)
+ }
}
sanitized, err := headers.sanitized()
@@ -21,11 +21,11 @@ import (
"compress/flate"
"encoding/base64"
"encoding/binary"
+ "fmt"
"io"
"math/big"
"strings"
"unicode"
- "fmt"
"github.com/go-jose/go-jose/v3/json"
)
@@ -202,3 +202,36 @@ func base64URLDecode(value string) ([]byte, error) {
value = strings.TrimRight(value, "=")
return base64.RawURLEncoding.DecodeString(value)
}
+
+func base64EncodeLen(sl []byte) int {
+ return base64.RawURLEncoding.EncodedLen(len(sl))
+}
+
+func base64JoinWithDots(inputs ...[]byte) string {
+ if len(inputs) == 0 {
+ return ""
+ }
+
+ // Count of dots.
+ totalCount := len(inputs) - 1
+
+ for _, input := range inputs {
+ totalCount += base64EncodeLen(input)
+ }
+
+ out := make([]byte, totalCount)
+ startEncode := 0
+ for i, input := range inputs {
+ base64.RawURLEncoding.Encode(out[startEncode:], input)
+
+ if i == len(inputs)-1 {
+ continue
+ }
+
+ startEncode += base64EncodeLen(input)
+ out[startEncode] = '.'
+ startEncode++
+ }
+
+ return string(out)
+}
@@ -252,13 +252,13 @@ func (obj JSONWebEncryption) CompactSerialize() (string, error) {
serializedProtected := mustSerializeJSON(obj.protected)
- return fmt.Sprintf(
- "%s.%s.%s.%s.%s",
- base64.RawURLEncoding.EncodeToString(serializedProtected),
- base64.RawURLEncoding.EncodeToString(obj.recipients[0].encryptedKey),
- base64.RawURLEncoding.EncodeToString(obj.iv),
- base64.RawURLEncoding.EncodeToString(obj.ciphertext),
- base64.RawURLEncoding.EncodeToString(obj.tag)), nil
+ return base64JoinWithDots(
+ serializedProtected,
+ obj.recipients[0].encryptedKey,
+ obj.iv,
+ obj.ciphertext,
+ obj.tag,
+ ), nil
}
// FullSerialize serializes an object using the full JSON serialization format.
@@ -67,9 +67,21 @@ type rawJSONWebKey struct {
X5tSHA256 string `json:"x5t#S256,omitempty"`
}
-// JSONWebKey represents a public or private key in JWK format.
+// JSONWebKey represents a public or private key in JWK format. It can be
+// marshaled into JSON and unmarshaled from JSON.
type JSONWebKey struct {
- // Cryptographic key, can be a symmetric or asymmetric key.
+ // Key is the Go in-memory representation of this key. It must have one
+ // of these types:
+ // - ed25519.PublicKey
+ // - ed25519.PrivateKey
+ // - *ecdsa.PublicKey
+ // - *ecdsa.PrivateKey
+ // - *rsa.PublicKey
+ // - *rsa.PrivateKey
+ // - []byte (a symmetric key)
+ //
+ // When marshaling this JSONWebKey into JSON, the "kty" header parameter
+ // will be automatically set based on the type of this field.
Key interface{}
// Key identifier, parsed from `kid` header.
KeyID string
@@ -389,6 +401,8 @@ func (k *JSONWebKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
input, err = rsaThumbprintInput(key.N, key.E)
case ed25519.PrivateKey:
input, err = edThumbprintInput(ed25519.PublicKey(key[32:]))
+ case OpaqueSigner:
+ return key.Public().Thumbprint(hash)
default:
return nil, fmt.Errorf("go-jose/go-jose: unknown key type '%s'", reflect.TypeOf(key))
}
@@ -314,15 +314,18 @@ func (obj JSONWebSignature) compactSerialize(detached bool) (string, error) {
return "", ErrNotSupported
}
- serializedProtected := base64.RawURLEncoding.EncodeToString(mustSerializeJSON(obj.Signatures[0].protected))
- payload := ""
- signature := base64.RawURLEncoding.EncodeToString(obj.Signatures[0].Signature)
+ serializedProtected := mustSerializeJSON(obj.Signatures[0].protected)
+ var payload []byte
if !detached {
- payload = base64.RawURLEncoding.EncodeToString(obj.payload)
+ payload = obj.payload
}
- return fmt.Sprintf("%s.%s.%s", serializedProtected, payload, signature), nil
+ return base64JoinWithDots(
+ serializedProtected,
+ payload,
+ obj.Signatures[0].Signature,
+ ), nil
}
// CompactSerialize serializes an object using the compact serialization format.
@@ -40,6 +40,15 @@ type Signer interface {
}
// SigningKey represents an algorithm/key used to sign a message.
+//
+// Key must have one of these types:
+// - ed25519.PrivateKey
+// - *ecdsa.PrivateKey
+// - *rsa.PrivateKey
+// - *JSONWebKey
+// - JSONWebKey
+// - []byte (an HMAC key)
+// - Any type that satisfies the OpaqueSigner interface
type SigningKey struct {
Algorithm SignatureAlgorithm
Key interface{}
@@ -52,12 +61,22 @@ type SignerOptions struct {
// Optional map of additional keys to be inserted into the protected header
// of a JWS object. Some specifications which make use of JWS like to insert
- // additional values here. All values must be JSON-serializable.
+ // additional values here.
+ //
+ // Values will be serialized by [json.Marshal] and must be valid inputs to
+ // that function.
+ //
+ // [json.Marshal]: https://pkg.go.dev/encoding/json#Marshal
ExtraHeaders map[HeaderKey]interface{}
}
// WithHeader adds an arbitrary value to the ExtraHeaders map, initializing it
-// if necessary. It returns itself and so can be used in a fluent style.
+// if necessary, and returns the updated SignerOptions.
+//
+// The v argument will be serialized by [json.Marshal] and must be a valid
+// input to that function.
+//
+// [json.Marshal]: https://pkg.go.dev/encoding/json#Marshal
func (so *SignerOptions) WithHeader(k HeaderKey, v interface{}) *SignerOptions {
if so.ExtraHeaders == nil {
so.ExtraHeaders = map[HeaderKey]interface{}{}
@@ -173,11 +192,11 @@ func newVerifier(verificationKey interface{}) (payloadVerifier, error) {
return newVerifier(verificationKey.Key)
case *JSONWebKey:
return newVerifier(verificationKey.Key)
+ case OpaqueVerifier:
+ return &opaqueVerifier{verifier: verificationKey}, nil
+ default:
+ return nil, ErrUnsupportedKeyType
}
- if ov, ok := verificationKey.(OpaqueVerifier); ok {
- return &opaqueVerifier{verifier: ov}, nil
- }
- return nil, ErrUnsupportedKeyType
}
func (ctx *genericSigner) addRecipient(alg SignatureAlgorithm, signingKey interface{}) error {
@@ -204,11 +223,11 @@ func makeJWSRecipient(alg SignatureAlgorithm, signingKey interface{}) (recipient
return newJWKSigner(alg, signingKey)
case *JSONWebKey:
return newJWKSigner(alg, *signingKey)
+ case OpaqueSigner:
+ return newOpaqueSigner(alg, signingKey)
+ default:
+ return recipientSigInfo{}, ErrUnsupportedKeyType
}
- if signer, ok := signingKey.(OpaqueSigner); ok {
- return newOpaqueSigner(alg, signer)
- }
- return recipientSigInfo{}, ErrUnsupportedKeyType
}
func newJWKSigner(alg SignatureAlgorithm, signingKey JSONWebKey) (recipientSigInfo, error) {
@@ -321,12 +340,21 @@ func (ctx *genericSigner) Options() SignerOptions {
}
// Verify validates the signature on the object and returns the payload.
-// This function does not support multi-signature, if you desire multi-sig
+// This function does not support multi-signature. If you desire multi-signature
// verification use VerifyMulti instead.
//
// Be careful when verifying signatures based on embedded JWKs inside the
// payload header. You cannot assume that the key received in a payload is
// trusted.
+//
+// The verificationKey argument must have one of these types:
+// - ed25519.PublicKey
+// - *ecdsa.PublicKey
+// - *rsa.PublicKey
+// - *JSONWebKey
+// - JSONWebKey
+// - []byte (an HMAC key)
+// - Any type that implements the OpaqueVerifier interface.
func (obj JSONWebSignature) Verify(verificationKey interface{}) ([]byte, error) {
err := obj.DetachedVerify(obj.payload, verificationKey)
if err != nil {
@@ -346,6 +374,9 @@ func (obj JSONWebSignature) UnsafePayloadWithoutVerification() []byte {
// most cases, you will probably want to use Verify instead. DetachedVerify
// is only useful if you have a payload and signature that are separated from
// each other.
+//
+// The verificationKey argument must have one of the types allowed for the
+// verificationKey argument of JSONWebSignature.Verify().
func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey interface{}) error {
key := tryJWKS(verificationKey, obj.headers()...)
verifier, err := newVerifier(key)
@@ -388,6 +419,9 @@ func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey inter
// returns the index of the signature that was verified, along with the signature
// object and the payload. We return the signature and index to guarantee that
// callers are getting the verified value.
+//
+// The verificationKey argument must have one of the types allowed for the
+// verificationKey argument of JSONWebSignature.Verify().
func (obj JSONWebSignature) VerifyMulti(verificationKey interface{}) (int, Signature, []byte, error) {
idx, sig, err := obj.DetachedVerifyMulti(obj.payload, verificationKey)
if err != nil {
@@ -405,6 +439,9 @@ func (obj JSONWebSignature) VerifyMulti(verificationKey interface{}) (int, Signa
// DetachedVerifyMulti is only useful if you have a payload and signature that are
// separated from each other, and the signature can have multiple signers at the
// same time.
+//
+// The verificationKey argument must have one of the types allowed for the
+// verificationKey argument of JSONWebSignature.Verify().
func (obj JSONWebSignature) DetachedVerifyMulti(payload []byte, verificationKey interface{}) (int, Signature, error) {
key := tryJWKS(verificationKey, obj.headers()...)
verifier, err := newVerifier(key)
@@ -40,12 +40,17 @@ var RandReader = rand.Reader
const (
// RFC7518 recommends a minimum of 1,000 iterations:
- // https://tools.ietf.org/html/rfc7518#section-4.8.1.2
+ // - https://tools.ietf.org/html/rfc7518#section-4.8.1.2
+ //
// NIST recommends a minimum of 10,000:
- // https://pages.nist.gov/800-63-3/sp800-63b.html
- // 1Password uses 100,000:
- // https://support.1password.com/pbkdf2/
- defaultP2C = 100000
+ // - https://pages.nist.gov/800-63-3/sp800-63b.html
+ //
+ // 1Password increased in 2023 from 100,000 to 650,000:
+ // - https://support.1password.com/pbkdf2/
+ //
+ // OWASP recommended 600,000 in Dec 2022:
+ // - https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2
+ defaultP2C = 600000
// Default salt size: 128 bits
defaultP2SSize = 16
)
@@ -584,7 +584,7 @@ ccflags="$@"
$2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ ||
$2 ~ /^KEYCTL_/ ||
$2 ~ /^PERF_/ ||
- $2 ~ /^SECCOMP_MODE_/ ||
+ $2 ~ /^SECCOMP_/ ||
$2 ~ /^SEEK_/ ||
$2 ~ /^SCHED_/ ||
$2 ~ /^SPLICE_/ ||
@@ -1785,6 +1785,8 @@ const (
LANDLOCK_ACCESS_FS_REMOVE_FILE = 0x20
LANDLOCK_ACCESS_FS_TRUNCATE = 0x4000
LANDLOCK_ACCESS_FS_WRITE_FILE = 0x2
+ LANDLOCK_ACCESS_NET_BIND_TCP = 0x1
+ LANDLOCK_ACCESS_NET_CONNECT_TCP = 0x2
LANDLOCK_CREATE_RULESET_VERSION = 0x1
LINUX_REBOOT_CMD_CAD_OFF = 0x0
LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef
@@ -2465,6 +2467,7 @@ const (
PR_MCE_KILL_GET = 0x22
PR_MCE_KILL_LATE = 0x0
PR_MCE_KILL_SET = 0x1
+ PR_MDWE_NO_INHERIT = 0x2
PR_MDWE_REFUSE_EXEC_GAIN = 0x1
PR_MPX_DISABLE_MANAGEMENT = 0x2c
PR_MPX_ENABLE_MANAGEMENT = 0x2b
@@ -2669,8 +2672,9 @@ const (
RTAX_FEATURES = 0xc
RTAX_FEATURE_ALLFRAG = 0x8
RTAX_FEATURE_ECN = 0x1
- RTAX_FEATURE_MASK = 0xf
+ RTAX_FEATURE_MASK = 0x1f
RTAX_FEATURE_SACK = 0x2
+ RTAX_FEATURE_TCP_USEC_TS = 0x10
RTAX_FEATURE_TIMESTAMP = 0x4
RTAX_HOPLIMIT = 0xa
RTAX_INITCWND = 0xb
@@ -2913,9 +2917,38 @@ const (
SCM_RIGHTS = 0x1
SCM_TIMESTAMP = 0x1d
SC_LOG_FLUSH = 0x100000
+ SECCOMP_ADDFD_FLAG_SEND = 0x2
+ SECCOMP_ADDFD_FLAG_SETFD = 0x1
+ SECCOMP_FILTER_FLAG_LOG = 0x2
+ SECCOMP_FILTER_FLAG_NEW_LISTENER = 0x8
+ SECCOMP_FILTER_FLAG_SPEC_ALLOW = 0x4
+ SECCOMP_FILTER_FLAG_TSYNC = 0x1
+ SECCOMP_FILTER_FLAG_TSYNC_ESRCH = 0x10
+ SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV = 0x20
+ SECCOMP_GET_ACTION_AVAIL = 0x2
+ SECCOMP_GET_NOTIF_SIZES = 0x3
+ SECCOMP_IOCTL_NOTIF_RECV = 0xc0502100
+ SECCOMP_IOCTL_NOTIF_SEND = 0xc0182101
+ SECCOMP_IOC_MAGIC = '!'
SECCOMP_MODE_DISABLED = 0x0
SECCOMP_MODE_FILTER = 0x2
SECCOMP_MODE_STRICT = 0x1
+ SECCOMP_RET_ACTION = 0x7fff0000
+ SECCOMP_RET_ACTION_FULL = 0xffff0000
+ SECCOMP_RET_ALLOW = 0x7fff0000
+ SECCOMP_RET_DATA = 0xffff
+ SECCOMP_RET_ERRNO = 0x50000
+ SECCOMP_RET_KILL = 0x0
+ SECCOMP_RET_KILL_PROCESS = 0x80000000
+ SECCOMP_RET_KILL_THREAD = 0x0
+ SECCOMP_RET_LOG = 0x7ffc0000
+ SECCOMP_RET_TRACE = 0x7ff00000
+ SECCOMP_RET_TRAP = 0x30000
+ SECCOMP_RET_USER_NOTIF = 0x7fc00000
+ SECCOMP_SET_MODE_FILTER = 0x1
+ SECCOMP_SET_MODE_STRICT = 0x0
+ SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP = 0x1
+ SECCOMP_USER_NOTIF_FLAG_CONTINUE = 0x1
SECRETMEM_MAGIC = 0x5345434d
SECURITYFS_MAGIC = 0x73636673
SEEK_CUR = 0x1
@@ -3075,6 +3108,7 @@ const (
SOL_TIPC = 0x10f
SOL_TLS = 0x11a
SOL_UDP = 0x11
+ SOL_VSOCK = 0x11f
SOL_X25 = 0x106
SOL_XDP = 0x11b
SOMAXCONN = 0x1000
@@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
@@ -282,6 +282,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
@@ -288,6 +288,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
@@ -278,6 +278,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
@@ -275,6 +275,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
@@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307
@@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307
@@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307
@@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307
@@ -336,6 +336,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
@@ -340,6 +340,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
@@ -340,6 +340,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
@@ -272,6 +272,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
@@ -344,6 +344,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
@@ -335,6 +335,9 @@ const (
SCM_TIMESTAMPNS = 0x21
SCM_TXTIME = 0x3f
SCM_WIFI_STATUS = 0x25
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x400000
SFD_NONBLOCK = 0x4000
SF_FP = 0x38
@@ -448,4 +448,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
@@ -371,4 +371,7 @@ const (
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
@@ -412,4 +412,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
@@ -315,4 +315,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
@@ -309,4 +309,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
@@ -432,4 +432,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 4450
SYS_CACHESTAT = 4451
SYS_FCHMODAT2 = 4452
+ SYS_MAP_SHADOW_STACK = 4453
+ SYS_FUTEX_WAKE = 4454
+ SYS_FUTEX_WAIT = 4455
+ SYS_FUTEX_REQUEUE = 4456
)
@@ -362,4 +362,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 5450
SYS_CACHESTAT = 5451
SYS_FCHMODAT2 = 5452
+ SYS_MAP_SHADOW_STACK = 5453
+ SYS_FUTEX_WAKE = 5454
+ SYS_FUTEX_WAIT = 5455
+ SYS_FUTEX_REQUEUE = 5456
)
@@ -362,4 +362,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 5450
SYS_CACHESTAT = 5451
SYS_FCHMODAT2 = 5452
+ SYS_MAP_SHADOW_STACK = 5453
+ SYS_FUTEX_WAKE = 5454
+ SYS_FUTEX_WAIT = 5455
+ SYS_FUTEX_REQUEUE = 5456
)
@@ -432,4 +432,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 4450
SYS_CACHESTAT = 4451
SYS_FCHMODAT2 = 4452
+ SYS_MAP_SHADOW_STACK = 4453
+ SYS_FUTEX_WAKE = 4454
+ SYS_FUTEX_WAIT = 4455
+ SYS_FUTEX_REQUEUE = 4456
)
@@ -439,4 +439,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
@@ -411,4 +411,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
@@ -411,4 +411,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
@@ -316,4 +316,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
@@ -377,4 +377,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
@@ -390,4 +390,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
@@ -174,7 +174,8 @@ type FscryptPolicyV2 struct {
Contents_encryption_mode uint8
Filenames_encryption_mode uint8
Flags uint8
- _ [4]uint8
+ Log2_data_unit_size uint8
+ _ [3]uint8
Master_key_identifier [16]uint8
}
@@ -455,60 +456,63 @@ type Ucred struct {
}
type TCPInfo struct {
- State uint8
- Ca_state uint8
- Retransmits uint8
- Probes uint8
- Backoff uint8
- Options uint8
- Rto uint32
- Ato uint32
- Snd_mss uint32
- Rcv_mss uint32
- Unacked uint32
- Sacked uint32
- Lost uint32
- Retrans uint32
- Fackets uint32
- Last_data_sent uint32
- Last_ack_sent uint32
- Last_data_recv uint32
- Last_ack_recv uint32
- Pmtu uint32
- Rcv_ssthresh uint32
- Rtt uint32
- Rttvar uint32
- Snd_ssthresh uint32
- Snd_cwnd uint32
- Advmss uint32
- Reordering uint32
- Rcv_rtt uint32
- Rcv_space uint32
- Total_retrans uint32
- Pacing_rate uint64
- Max_pacing_rate uint64
- Bytes_acked uint64
- Bytes_received uint64
- Segs_out uint32
- Segs_in uint32
- Notsent_bytes uint32
- Min_rtt uint32
- Data_segs_in uint32
- Data_segs_out uint32
- Delivery_rate uint64
- Busy_time uint64
- Rwnd_limited uint64
- Sndbuf_limited uint64
- Delivered uint32
- Delivered_ce uint32
- Bytes_sent uint64
- Bytes_retrans uint64
- Dsack_dups uint32
- Reord_seen uint32
- Rcv_ooopack uint32
- Snd_wnd uint32
- Rcv_wnd uint32
- Rehash uint32
+ State uint8
+ Ca_state uint8
+ Retransmits uint8
+ Probes uint8
+ Backoff uint8
+ Options uint8
+ Rto uint32
+ Ato uint32
+ Snd_mss uint32
+ Rcv_mss uint32
+ Unacked uint32
+ Sacked uint32
+ Lost uint32
+ Retrans uint32
+ Fackets uint32
+ Last_data_sent uint32
+ Last_ack_sent uint32
+ Last_data_recv uint32
+ Last_ack_recv uint32
+ Pmtu uint32
+ Rcv_ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+ Snd_ssthresh uint32
+ Snd_cwnd uint32
+ Advmss uint32
+ Reordering uint32
+ Rcv_rtt uint32
+ Rcv_space uint32
+ Total_retrans uint32
+ Pacing_rate uint64
+ Max_pacing_rate uint64
+ Bytes_acked uint64
+ Bytes_received uint64
+ Segs_out uint32
+ Segs_in uint32
+ Notsent_bytes uint32
+ Min_rtt uint32
+ Data_segs_in uint32
+ Data_segs_out uint32
+ Delivery_rate uint64
+ Busy_time uint64
+ Rwnd_limited uint64
+ Sndbuf_limited uint64
+ Delivered uint32
+ Delivered_ce uint32
+ Bytes_sent uint64
+ Bytes_retrans uint64
+ Dsack_dups uint32
+ Reord_seen uint32
+ Rcv_ooopack uint32
+ Snd_wnd uint32
+ Rcv_wnd uint32
+ Rehash uint32
+ Total_rto uint16
+ Total_rto_recoveries uint16
+ Total_rto_time uint32
}
type CanFilter struct {
@@ -551,7 +555,7 @@ const (
SizeofIPv6MTUInfo = 0x20
SizeofICMPv6Filter = 0x20
SizeofUcred = 0xc
- SizeofTCPInfo = 0xf0
+ SizeofTCPInfo = 0xf8
SizeofCanFilter = 0x8
SizeofTCPRepairOpt = 0x8
)
@@ -3399,7 +3403,7 @@ const (
DEVLINK_PORT_FN_ATTR_STATE = 0x2
DEVLINK_PORT_FN_ATTR_OPSTATE = 0x3
DEVLINK_PORT_FN_ATTR_CAPS = 0x4
- DEVLINK_PORT_FUNCTION_ATTR_MAX = 0x4
+ DEVLINK_PORT_FUNCTION_ATTR_MAX = 0x5
)
type FsverityDigest struct {
@@ -4183,7 +4187,8 @@ const (
)
type LandlockRulesetAttr struct {
- Access_fs uint64
+ Access_fs uint64
+ Access_net uint64
}
type LandlockPathBeneathAttr struct {
@@ -5134,7 +5139,7 @@ const (
NL80211_FREQUENCY_ATTR_GO_CONCURRENT = 0xf
NL80211_FREQUENCY_ATTR_INDOOR_ONLY = 0xe
NL80211_FREQUENCY_ATTR_IR_CONCURRENT = 0xf
- NL80211_FREQUENCY_ATTR_MAX = 0x1b
+ NL80211_FREQUENCY_ATTR_MAX = 0x1c
NL80211_FREQUENCY_ATTR_MAX_TX_POWER = 0x6
NL80211_FREQUENCY_ATTR_NO_10MHZ = 0x11
NL80211_FREQUENCY_ATTR_NO_160MHZ = 0xc
@@ -5547,7 +5552,7 @@ const (
NL80211_REGDOM_TYPE_CUSTOM_WORLD = 0x2
NL80211_REGDOM_TYPE_INTERSECTION = 0x3
NL80211_REGDOM_TYPE_WORLD = 0x1
- NL80211_REG_RULE_ATTR_MAX = 0x7
+ NL80211_REG_RULE_ATTR_MAX = 0x8
NL80211_REKEY_DATA_AKM = 0x4
NL80211_REKEY_DATA_KCK = 0x2
NL80211_REKEY_DATA_KEK = 0x1
@@ -37,14 +37,17 @@ func (token Token) Environ(inheritExisting bool) (env []string, err error) {
return nil, err
}
defer DestroyEnvironmentBlock(block)
- blockp := unsafe.Pointer(block)
- for {
- entry := UTF16PtrToString((*uint16)(blockp))
- if len(entry) == 0 {
- break
+ size := unsafe.Sizeof(*block)
+ for *block != 0 {
+ // find NUL terminator
+ end := unsafe.Pointer(block)
+ for *(*uint16)(end) != 0 {
+ end = unsafe.Add(end, size)
}
- env = append(env, entry)
- blockp = unsafe.Add(blockp, 2*(len(entry)+1))
+
+ entry := unsafe.Slice(block, (uintptr(end)-uintptr(unsafe.Pointer(block)))/size)
+ env = append(env, UTF16ToString(entry))
+ block = (*uint16)(unsafe.Add(end, size))
}
return env, nil
}
@@ -125,8 +125,7 @@ func UTF16PtrToString(p *uint16) string {
for ptr := unsafe.Pointer(p); *(*uint16)(ptr) != 0; n++ {
ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*p))
}
-
- return string(utf16.Decode(unsafe.Slice(p, n)))
+ return UTF16ToString(unsafe.Slice(p, n))
}
func Getpagesize() int { return 4096 }
--
2.48.1