From c1a8e94c584a140a2834923e6c0e1108b996d53b Mon Sep 17 00:00:00 2001 From: Avi Deitcher Date: Tue, 16 Jan 2024 18:52:22 +0200 Subject: [PATCH] pillar: Encode media type in verifier filenames. Implemented a feature to save the media type hashed in the verifier filename. This enhancement is used in both config and status, ensuring that the media type is persistently available and survives reboots. Modified several functions in verifier.go to include media type in the filename generation. Also updated related structures in verifiertypes.go to include the media type. Issue: #3704 Signed-off-by: Avi Deitcher --- pkg/pillar/cmd/verifier/verifier.go | 36 +++++++++++++++++----- pkg/pillar/cmd/volumemgr/handleverifier.go | 1 + pkg/pillar/types/verifiertypes.go | 2 ++ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/pkg/pillar/cmd/verifier/verifier.go b/pkg/pillar/cmd/verifier/verifier.go index 5a7dcdd137..814a44d300 100644 --- a/pkg/pillar/cmd/verifier/verifier.go +++ b/pkg/pillar/cmd/verifier/verifier.go @@ -14,6 +14,7 @@ package verifier import ( "flag" "fmt" + "net/url" "os" "path" "strings" @@ -308,6 +309,7 @@ func handleCreate(ctx *verifierContext, status := types.VerifyImageStatus{ Name: config.Name, ImageSha256: config.ImageSha256, + MediaType: config.MediaType, PendingAdd: true, State: types.VERIFYING, RefCount: config.RefCount, @@ -500,12 +502,20 @@ func handleGlobalConfigDelete(ctxArg interface{}, key string, } // ImageVerifierFilenames - Returns pendingFilename, verifierFilename, verifiedFilename -// for the image -func ImageVerifierFilenames(infile, sha256, tmpID string) (string, string, string) { +// for the image. The verifierFilename and verifiedFilename always will have an extension +// of the media-type, e.g. abcdeff112.application-vnd.oci.image.manifest.v1+json +// This is because we need the media-type to process the blob. Normally, we carry +// it around in the status (DownloadStatus -> BlobStatus), but those are ephemeral and +// lost during a reboot. We need that information to be persistent and survive reboot, +// so we can reconstruct it. Hence, we preserve it in the filename. It is PathEscape'd +// so it is filename-safe. +func ImageVerifierFilenames(infile, sha256, tmpID, mediaType string) (string, string, string) { verifierDirname, verifiedDirname := getVerifierDir(), getVerifiedDir() // Handle names which are paths - verified := tmpID + "." + sha256 - return infile, path.Join(verifierDirname, verified), path.Join(verifiedDirname, sha256) + mediaTypeSafe := url.PathEscape(mediaType) + verifierFilename := strings.Join([]string{tmpID, sha256, mediaTypeSafe}, ".") + verifiedFilename := strings.Join([]string{sha256, mediaTypeSafe}, ".") + return infile, path.Join(verifierDirname, verifierFilename), path.Join(verifiedDirname, verifiedFilename) } // Returns ok, size of object @@ -514,7 +524,7 @@ func markObjectAsVerifying(ctx *verifierContext, status *types.VerifyImageStatus, tmpID uuid.UUID) (bool, int64) { verifierDirname := getVerifierDir() - pendingFilename, verifierFilename, _ := ImageVerifierFilenames(config.FileLocation, config.ImageSha256, tmpID.String()) + pendingFilename, verifierFilename, _ := ImageVerifierFilenames(config.FileLocation, config.ImageSha256, tmpID.String(), config.MediaType) // Move to verifier directory which is RO // XXX should have dom0 do this and/or have RO mounts @@ -561,7 +571,7 @@ func markObjectAsVerifying(ctx *verifierContext, func markObjectAsVerified(config *types.VerifyImageConfig, status *types.VerifyImageStatus, tmpID uuid.UUID) { verifiedDirname := getVerifiedDir() - _, verifierFilename, verifiedFilename := ImageVerifierFilenames(config.FileLocation, config.ImageSha256, tmpID.String()) + _, verifierFilename, verifiedFilename := ImageVerifierFilenames(config.FileLocation, config.ImageSha256, tmpID.String(), config.MediaType) // Move directory from DownloadDirname/verifier to // DownloadDirname/verified // XXX should have dom0 do this and/or have RO mounts @@ -609,10 +619,22 @@ func handleInitVerifiedObjects(ctx *verifierContext) { func verifyImageStatusFromImageFile(imageFileName string, size int64, pathname string) *types.VerifyImageStatus { + // filename might have two parts, separated by '.': digest and PathEscape(mediaType) + var ( + mediaType string + digest string + ) + parts := strings.SplitN(imageFileName, ".", 2) + digest = parts[0] + if len(parts) == 2 { + // just ignore the error and treat mediaType as empty + mediaType, _ = url.PathUnescape(parts[1]) + } status := types.VerifyImageStatus{ Name: imageFileName, FileLocation: pathname, - ImageSha256: imageFileName, + ImageSha256: digest, + MediaType: mediaType, Size: size, State: types.VERIFIED, RefCount: 0, diff --git a/pkg/pillar/cmd/volumemgr/handleverifier.go b/pkg/pillar/cmd/volumemgr/handleverifier.go index 13eacffe9f..f76cade519 100644 --- a/pkg/pillar/cmd/volumemgr/handleverifier.go +++ b/pkg/pillar/cmd/volumemgr/handleverifier.go @@ -71,6 +71,7 @@ func MaybeAddVerifyImageConfigBlob(ctx *volumemgrContext, blob types.BlobStatus) ImageSha256: blob.Sha256, // the sha to verify Name: blob.Sha256, // we are just going to use the sha for the verifier display RefCount: refcount, + MediaType: blob.MediaType, } log.Tracef("MaybeAddVerifyImageConfigBlob - config: %+v", vic) } diff --git a/pkg/pillar/types/verifiertypes.go b/pkg/pillar/types/verifiertypes.go index 4b7dfef503..be20c29e87 100644 --- a/pkg/pillar/types/verifiertypes.go +++ b/pkg/pillar/types/verifiertypes.go @@ -21,6 +21,7 @@ import ( type VerifyImageConfig struct { ImageSha256 string // sha256 of immutable image Name string + MediaType string // MIME type FileLocation string // Current location; should be info about file Size int64 //FileLocation size RefCount uint @@ -91,6 +92,7 @@ type VerifyImageStatus struct { Name string FileLocation string // Current location Size int64 + MediaType string // MIME type PendingAdd bool PendingModify bool PendingDelete bool