Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions internal/guest/runtime/hcsv2/uvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -1205,7 +1205,11 @@ func modifyMappedVirtualDisk(
mountCtx, cancel := context.WithTimeout(ctx, time.Second*5)
defer cancel()
if mvd.MountPath != "" {
if mvd.ReadOnly {
if mvd.BlockDev {
if err = securityPolicy.EnforceMountBlockDevicePolicy(ctx, mvd.MountPath); err != nil {
return errors.Wrapf(err, "creating blockdev symlink at %s (-> scsi controller %d lun %d) denied by policy", mvd.MountPath, mvd.Controller, mvd.Lun)
}
} else if mvd.ReadOnly {
Comment on lines 1205 to +1212
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leaving as-is to match the ctx used for the enforcement point calls below this.

var deviceHash string
if verityInfo != nil {
deviceHash = verityInfo.RootDigest
Expand Down Expand Up @@ -1233,7 +1237,11 @@ func modifyMappedVirtualDisk(
return nil
case guestrequest.RequestTypeRemove:
if mvd.MountPath != "" {
if mvd.ReadOnly {
if mvd.BlockDev {
if err = securityPolicy.EnforceUnmountBlockDevicePolicy(ctx, mvd.MountPath); err != nil {
return fmt.Errorf("removing blockdev symlink at %s (-> scsi controller %d lun %d) denied by policy: %w", mvd.MountPath, mvd.Controller, mvd.Lun, err)
}
} else if mvd.ReadOnly {
if err := securityPolicy.EnforceDeviceUnmountPolicy(ctx, mvd.MountPath); err != nil {
return fmt.Errorf("unmounting scsi device at %s denied by policy: %w", mvd.MountPath, err)
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/securitypolicy/api.rego
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ version := "@@API_VERSION@@"
enforcement_points := {
"mount_device": {"introducedVersion": "0.1.0", "default_results": {"allowed": false}, "use_framework": false},
"rw_mount_device": {"introducedVersion": "0.11.0", "default_results": {}, "use_framework": true},
"mount_blockdev": {"introducedVersion": "0.11.1", "default_results": {"allowed": false}, "use_framework": false},
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the denial reason is separate from this and we should still get the framework-provided reason (untested)

"mount_overlay": {"introducedVersion": "0.1.0", "default_results": {"allowed": false}, "use_framework": false},
"mount_cims": {"introducedVersion": "0.11.0", "default_results": {"allowed": false}, "use_framework": false},
"registry_changes": {"introducedVersion": "0.10.0", "default_results": {"allowed": false}, "use_framework": false},
"create_container": {"introducedVersion": "0.1.0", "default_results": {"allowed": false, "env_list": null, "allow_stdio_access": false}, "use_framework": false},
"unmount_device": {"introducedVersion": "0.2.0", "default_results": {"allowed": true}, "use_framework": false},
"rw_unmount_device": {"introducedVersion": "0.11.0", "default_results": {}, "use_framework": true},
"unmount_blockdev": {"introducedVersion": "0.11.1", "default_results": {"allowed": false}, "use_framework": false},
"unmount_overlay": {"introducedVersion": "0.6.0", "default_results": {"allowed": true}, "use_framework": false},
"exec_in_container": {"introducedVersion": "0.2.0", "default_results": {"allowed": true, "env_list": null}, "use_framework": false},
"exec_external": {"introducedVersion": "0.3.0", "default_results": {"allowed": true, "env_list": null, "allow_stdio_access": false}, "use_framework": false},
Expand Down
12 changes: 12 additions & 0 deletions pkg/securitypolicy/framework.rego
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ rw_unmount_device := {"metadata": [removeRWDevice], "allowed": true} {
}
}

# blockdev mounts (which are symlinks created at the mount point pointing to
# /dev/sdX instead of an actual mounted filesystem) are not supported on C-ACI
# and thus the framework currently denies them unconditionally.

default mount_blockdev := {"allowed": false}

default unmount_blockdev := {"allowed": false}

layerPaths_ok(layers) {
length := count(layers)
count(input.layerPaths) == length
Expand Down Expand Up @@ -1418,6 +1426,10 @@ reason := {
# Error messages
################################################################

errors["blockdev mounts are not supported"] {
input.rule in ["mount_blockdev", "unmount_blockdev"]
}

errors["deviceHash not found"] {
input.rule == "mount_device"
not deviceHash_ok
Expand Down
2 changes: 2 additions & 0 deletions pkg/securitypolicy/open_door.rego
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ api_version := "@@API_VERSION@@"

mount_device := {"allowed": true}
rw_mount_device := {"allowed": true}
mount_blockdev := {"allowed": true}
mount_overlay := {"allowed": true}
create_container := {"allowed": true, "env_list": null, "allow_stdio_access": true}
mount_cims := {"allowed": true}
registry_changes := {"allowed": true}
unmount_device := {"allowed": true}
rw_unmount_device := {"allowed": true}
unmount_blockdev := {"allowed": true}
unmount_overlay := {"allowed": true}
exec_in_container := {"allowed": true, "env_list": null}
exec_external := {"allowed": true, "env_list": null, "allow_stdio_access": true}
Expand Down
2 changes: 2 additions & 0 deletions pkg/securitypolicy/policy.rego
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ framework_version := "@@FRAMEWORK_VERSION@@"

mount_device := data.framework.mount_device
rw_mount_device := data.framework.rw_mount_device
mount_blockdev := data.framework.mount_blockdev
unmount_device := data.framework.unmount_device
rw_unmount_device := data.framework.rw_unmount_device
unmount_blockdev := data.framework.unmount_blockdev
mount_overlay := data.framework.mount_overlay
unmount_overlay := data.framework.unmount_overlay
mount_cims:= data.framework.mount_cims
Expand Down
31 changes: 31 additions & 0 deletions pkg/securitypolicy/regopolicy_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7367,3 +7367,34 @@ func substituteUVMPath(sandboxID string, m mountInternal) mountInternal {
}
return m
}

func Test_Rego_EnforceMountBlockDevicePolicy_DefaultDenied(t *testing.T) {
p := generateConstraints(testRand, 1)
securityPolicy := p.toPolicy()
policy, err := newRegoPolicy(securityPolicy.marshalRego(), []oci.Mount{}, []oci.Mount{}, testOSType)
if err != nil {
t.Fatalf("cannot make rego policy from constraints: %v", err)
}

target := testDataGenerator.uniqueLayerMountTarget()
err = policy.EnforceMountBlockDevicePolicy(p.ctx, target)
assertDecisionJSONContains(t, err, "blockdev mounts are not supported")

err = policy.EnforceUnmountBlockDevicePolicy(p.ctx, target)
assertDecisionJSONContains(t, err, "blockdev mounts are not supported")
}

func Test_Rego_EnforceMountBlockDevicePolicy_OpenDoor(t *testing.T) {
policy, err := newRegoPolicy(openDoorRego, []oci.Mount{}, []oci.Mount{}, testOSType)
if err != nil {
t.Fatalf("cannot compile open door rego policy: %v", err)
}

target := testDataGenerator.uniqueLayerMountTarget()
if err = policy.EnforceMountBlockDevicePolicy(context.Background(), target); err != nil {
t.Errorf("open door should allow mount_blockdev, got: %v", err)
}
if err = policy.EnforceUnmountBlockDevicePolicy(context.Background(), target); err != nil {
t.Errorf("open door should allow unmount_blockdev, got: %v", err)
}
}
18 changes: 18 additions & 0 deletions pkg/securitypolicy/securitypolicyenforcer.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,10 @@ func init() {
type SecurityPolicyEnforcer interface {
EnforceDeviceMountPolicy(ctx context.Context, target string, deviceHash string) (err error)
EnforceRWDeviceMountPolicy(ctx context.Context, target string, encrypted, ensureFilesystem bool, filesystem string) (err error)
EnforceMountBlockDevicePolicy(ctx context.Context, target string) (err error)
EnforceDeviceUnmountPolicy(ctx context.Context, unmountTarget string) (err error)
EnforceRWDeviceUnmountPolicy(ctx context.Context, unmountTarget string) (err error)
EnforceUnmountBlockDevicePolicy(ctx context.Context, unmountTarget string) (err error)
Comment thread
micromaomao marked this conversation as resolved.
EnforceOverlayMountPolicy(ctx context.Context, containerID string, layerPaths []string, target string) (err error)
EnforceOverlayUnmountPolicy(ctx context.Context, target string) (err error)
EnforceCreateContainerPolicy(
Expand Down Expand Up @@ -207,6 +209,10 @@ func (OpenDoorSecurityPolicyEnforcer) EnforceRWDeviceMountPolicy(context.Context
return nil
}

func (OpenDoorSecurityPolicyEnforcer) EnforceMountBlockDevicePolicy(context.Context, string) error {
return nil
}

func (OpenDoorSecurityPolicyEnforcer) EnforceDeviceUnmountPolicy(context.Context, string) error {
return nil
}
Expand All @@ -215,6 +221,10 @@ func (OpenDoorSecurityPolicyEnforcer) EnforceRWDeviceUnmountPolicy(context.Conte
return nil
}

func (OpenDoorSecurityPolicyEnforcer) EnforceUnmountBlockDevicePolicy(context.Context, string) error {
return nil
}

func (OpenDoorSecurityPolicyEnforcer) EnforceOverlayMountPolicy(context.Context, string, []string, string) error {
return nil
}
Expand Down Expand Up @@ -336,6 +346,10 @@ func (ClosedDoorSecurityPolicyEnforcer) EnforceRWDeviceMountPolicy(context.Conte
return errors.New("Read-write device mounting is denied by policy")
}

func (ClosedDoorSecurityPolicyEnforcer) EnforceMountBlockDevicePolicy(context.Context, string) error {
return errors.New("block-device mounting is denied by policy")
}

func (ClosedDoorSecurityPolicyEnforcer) EnforceDeviceUnmountPolicy(context.Context, string) error {
return errors.New("unmounting is denied by policy")
}
Expand All @@ -344,6 +358,10 @@ func (ClosedDoorSecurityPolicyEnforcer) EnforceRWDeviceUnmountPolicy(context.Con
return errors.New("Read-write device unmounting is denied by policy")
}

func (ClosedDoorSecurityPolicyEnforcer) EnforceUnmountBlockDevicePolicy(context.Context, string) error {
return errors.New("block-device unmounting is denied by policy")
}

func (ClosedDoorSecurityPolicyEnforcer) EnforceOverlayMountPolicy(context.Context, string, []string, string) error {
return errors.New("creating an overlay fs is denied by policy")
}
Expand Down
18 changes: 18 additions & 0 deletions pkg/securitypolicy/securitypolicyenforcer_rego.go
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,15 @@ func (policy *regoEnforcer) EnforceRWDeviceMountPolicy(ctx context.Context, targ
return err
}

func (policy *regoEnforcer) EnforceMountBlockDevicePolicy(ctx context.Context, target string) error {
input := inputData{
"target": target,
}

_, err := policy.enforce(ctx, "mount_blockdev", input)
return err
}

func (policy *regoEnforcer) EnforceOverlayMountPolicy(ctx context.Context, containerID string, layerPaths []string, target string) error {
input := inputData{
"containerID": containerID,
Expand Down Expand Up @@ -822,6 +831,15 @@ func (policy *regoEnforcer) EnforceRWDeviceUnmountPolicy(ctx context.Context, un
return err
}

func (policy *regoEnforcer) EnforceUnmountBlockDevicePolicy(ctx context.Context, unmountTarget string) error {
input := inputData{
"unmountTarget": unmountTarget,
}

_, err := policy.enforce(ctx, "unmount_blockdev", input)
return err
}

func appendMountData(mountData []interface{}, mounts []oci.Mount) []interface{} {
for _, mount := range mounts {
mountData = append(mountData, inputData{
Expand Down
2 changes: 1 addition & 1 deletion pkg/securitypolicy/version_api
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.11.0
0.11.1
2 changes: 1 addition & 1 deletion pkg/securitypolicy/version_framework
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.4.1
0.4.2
Loading