From 82f22650fba061d752ae0ef2ba9463e721ee55d1 Mon Sep 17 00:00:00 2001 From: Mahati Chamarthy Date: Fri, 17 Apr 2026 15:26:37 +0100 Subject: [PATCH] C-WCOW: Add mounted_cim check in enforcement Signed-off-by: Mahati Chamarthy --- internal/gcs-sidecar/handlers.go | 18 ++++++++++++++---- pkg/securitypolicy/framework.rego | 1 + pkg/securitypolicy/rego_utils_test.go | 7 ++++++- pkg/securitypolicy/regopolicy_windows_test.go | 8 +++++++- pkg/securitypolicy/securitypolicyenforcer.go | 6 +++--- .../securitypolicyenforcer_rego.go | 3 ++- 6 files changed, 33 insertions(+), 10 deletions(-) diff --git a/internal/gcs-sidecar/handlers.go b/internal/gcs-sidecar/handlers.go index a76680fe83..a51c3fd8f5 100644 --- a/internal/gcs-sidecar/handlers.go +++ b/internal/gcs-sidecar/handlers.go @@ -752,9 +752,14 @@ func (b *Bridge) modifySettings(req *request) (err error) { log.G(ctx).Debugf("block CIM layer digest %s, path: %s\n", layerHashes[i], physicalDevPath) } + // Top layer is the merged layer that will also be verified hashesToVerify := layerHashes + mountedCim := []string{layerHashes[0]} + if len(layerHashes) > 1 { + hashesToVerify = layerHashes[1:] + } - err := b.hostState.securityOptions.PolicyEnforcer.EnforceVerifiedCIMsPolicy(req.ctx, containerID, hashesToVerify) + err := b.hostState.securityOptions.PolicyEnforcer.EnforceVerifiedCIMsPolicy(req.ctx, containerID, hashesToVerify, mountedCim) if err != nil { return errors.Wrap(err, "CIM mount is denied by policy") } @@ -763,7 +768,7 @@ func (b *Bridge) modifySettings(req *request) (err error) { volGUID := wcowBlockCimMounts.VolumeGUID // Cache hashes along with volGUID - b.hostState.blockCIMVolumeHashes[volGUID] = hashesToVerify + b.hostState.blockCIMVolumeHashes[volGUID] = layerHashes // Store the containerID (associated with volGUID) to mark that hashes are verified for this container if _, ok := b.hostState.blockCIMVolumeContainers[volGUID]; !ok { @@ -886,10 +891,15 @@ func (b *Bridge) modifySettings(req *request) (err error) { if _, seen := containers[containerID]; !seen { // This is a container with similar layers as an existing container, hence already mounted. // Call EnforceVerifiedCIMsPolicy on this new container. - log.G(ctx).Tracef("Verified CIM hashes for reused mount volume %s (container %s)", volGUID.String(), containerID) - if err := b.hostState.securityOptions.PolicyEnforcer.EnforceVerifiedCIMsPolicy(ctx, containerID, hashes); err != nil { + hashesToVerify := hashes + mountedCim := []string{hashes[0]} + if len(hashes) > 1 { + hashesToVerify = hashes[1:] + } + if err := b.hostState.securityOptions.PolicyEnforcer.EnforceVerifiedCIMsPolicy(ctx, containerID, hashesToVerify, mountedCim); err != nil { return fmt.Errorf("CIM mount is denied by policy for this container: %w", err) } + log.G(ctx).Tracef("Verified CIM hashes for reused mount volume %s (container %s)", volGUID.String(), containerID) containers[containerID] = struct{}{} } } diff --git a/pkg/securitypolicy/framework.rego b/pkg/securitypolicy/framework.rego index de534eb863..daa0fe864e 100644 --- a/pkg/securitypolicy/framework.rego +++ b/pkg/securitypolicy/framework.rego @@ -174,6 +174,7 @@ mount_cims := {"metadata": [addMatches], "allowed": true} { containers := [container | container := candidate_containers[_] layerHashes_ok(container.layers) + input.mountedCim == container.mounted_cim ] count(containers) > 0 diff --git a/pkg/securitypolicy/rego_utils_test.go b/pkg/securitypolicy/rego_utils_test.go index 5ac12a5a0a..f6825e1f5a 100644 --- a/pkg/securitypolicy/rego_utils_test.go +++ b/pkg/securitypolicy/rego_utils_test.go @@ -2163,7 +2163,12 @@ func mountImageForWindowsContainer(policy *regoEnforcer, container *securityPoli } // Mount the CIMFS for the Windows container - err := policy.EnforceVerifiedCIMsPolicy(ctx, containerID, layerHashes) + hashesToVerify := layerHashes + mountedCim := []string{layerHashes[0]} + if len(layerHashes) > 1 { + hashesToVerify = layerHashes[1:] + } + err := policy.EnforceVerifiedCIMsPolicy(ctx, containerID, hashesToVerify, mountedCim) if err != nil { return "", fmt.Errorf("error mounting CIMFS: %w", err) } diff --git a/pkg/securitypolicy/regopolicy_windows_test.go b/pkg/securitypolicy/regopolicy_windows_test.go index 512e4e7ff9..78d69382e1 100644 --- a/pkg/securitypolicy/regopolicy_windows_test.go +++ b/pkg/securitypolicy/regopolicy_windows_test.go @@ -347,8 +347,14 @@ func Test_Rego_EnforceVerifiedCIMSPolicy_Multiple_Instances_Same_Container(t *te layerHashes[len(container.Layers)-1-i] = layer } + hashesToVerify := layerHashes + mountedCim := []string{layerHashes[0]} + if len(layerHashes) > 1 { + hashesToVerify = layerHashes[1:] + } + id := testDataGenerator.uniqueContainerID() - err = policy.EnforceVerifiedCIMsPolicy(constraints.ctx, id, layerHashes) + err = policy.EnforceVerifiedCIMsPolicy(constraints.ctx, id, hashesToVerify, mountedCim) if err != nil { t.Fatalf("failed with %d containers", containersToCreate) } diff --git a/pkg/securitypolicy/securitypolicyenforcer.go b/pkg/securitypolicy/securitypolicyenforcer.go index 6cae97118d..2a4edefce1 100644 --- a/pkg/securitypolicy/securitypolicyenforcer.go +++ b/pkg/securitypolicy/securitypolicyenforcer.go @@ -126,7 +126,7 @@ type SecurityPolicyEnforcer interface { EnforceScratchMountPolicy(ctx context.Context, scratchPath string, encrypted bool) (err error) EnforceScratchUnmountPolicy(ctx context.Context, scratchPath string) (err error) GetUserInfo(spec *oci.Process, rootPath string) (IDName, []IDName, string, error) - EnforceVerifiedCIMsPolicy(ctx context.Context, containerID string, layerHashes []string) (err error) + EnforceVerifiedCIMsPolicy(ctx context.Context, containerID string, layerHashes []string, mountedCim []string) (err error) EnforceRegistryChangesPolicy(ctx context.Context, containerID string, registryValues interface{}) error } @@ -316,7 +316,7 @@ func (OpenDoorSecurityPolicyEnforcer) GetUserInfo(spec *oci.Process, rootPath st return IDName{}, nil, "", nil } -func (OpenDoorSecurityPolicyEnforcer) EnforceVerifiedCIMsPolicy(ctx context.Context, containerID string, layerHashes []string) error { +func (OpenDoorSecurityPolicyEnforcer) EnforceVerifiedCIMsPolicy(ctx context.Context, containerID string, layerHashes []string, mountedCim []string) error { return nil } @@ -445,7 +445,7 @@ func (ClosedDoorSecurityPolicyEnforcer) GetUserInfo(spec *oci.Process, rootPath return IDName{}, nil, "", nil } -func (ClosedDoorSecurityPolicyEnforcer) EnforceVerifiedCIMsPolicy(ctx context.Context, containerID string, layerHashes []string) error { +func (ClosedDoorSecurityPolicyEnforcer) EnforceVerifiedCIMsPolicy(ctx context.Context, containerID string, layerHashes []string, mountedCim []string) error { return nil } diff --git a/pkg/securitypolicy/securitypolicyenforcer_rego.go b/pkg/securitypolicy/securitypolicyenforcer_rego.go index 1da5d78a0e..96c5613dd6 100644 --- a/pkg/securitypolicy/securitypolicyenforcer_rego.go +++ b/pkg/securitypolicy/securitypolicyenforcer_rego.go @@ -1157,11 +1157,12 @@ func (policy *regoEnforcer) EnforceScratchUnmountPolicy(ctx context.Context, scr return nil } -func (policy *regoEnforcer) EnforceVerifiedCIMsPolicy(ctx context.Context, containerID string, layerHashes []string) error { +func (policy *regoEnforcer) EnforceVerifiedCIMsPolicy(ctx context.Context, containerID string, layerHashes []string, mountedCim []string) error { log.G(ctx).Tracef("Enforcing verified cims in securitypolicy pkg %+v", layerHashes) input := inputData{ "containerID": containerID, "layerHashes": layerHashes, + "mountedCim": mountedCim, } _, err := policy.enforce(ctx, "mount_cims", input)