From a00c59a300072c020a70ea50f7bfcfdacba8befb Mon Sep 17 00:00:00 2001 From: Elijah Rodriguez-Beltran Date: Thu, 25 Sep 2025 02:12:47 +0000 Subject: [PATCH 1/2] Add NodeStageVolume disk size validation before mounting --- pkg/common/constants.go | 1 + pkg/gce-pd-csi-driver/controller.go | 4 ++- pkg/gce-pd-csi-driver/node.go | 11 ++++++ pkg/gce-pd-csi-driver/node_test.go | 54 +++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 1 deletion(-) diff --git a/pkg/common/constants.go b/pkg/common/constants.go index 62d8a6bc9..250105836 100644 --- a/pkg/common/constants.go +++ b/pkg/common/constants.go @@ -48,6 +48,7 @@ const ( ContextDataCacheSize = "data-cache-size" ContextDataCacheMode = "data-cache-mode" + ContextDiskSizeGB = "disk-size" // Keys in the publish context ContexLocalSsdCacheSize = "local-ssd-cache-size" diff --git a/pkg/gce-pd-csi-driver/controller.go b/pkg/gce-pd-csi-driver/controller.go index f77d0982b..e17fa0e84 100644 --- a/pkg/gce-pd-csi-driver/controller.go +++ b/pkg/gce-pd-csi-driver/controller.go @@ -21,6 +21,7 @@ import ( "math/rand" neturl "net/url" "sort" + "strconv" "strings" "time" @@ -1113,7 +1114,7 @@ func (gceCS *GCEControllerServer) executeControllerPublishVolume(ctx context.Con volumeCapability := req.GetVolumeCapability() pubVolResp := &csi.ControllerPublishVolumeResponse{ - PublishContext: nil, + PublishContext: map[string]string{}, } // Set data cache publish context @@ -1162,6 +1163,7 @@ func (gceCS *GCEControllerServer) executeControllerPublishVolume(ctx context.Con } return nil, common.LoggedError("Failed to getDisk: ", err), disk } + pubVolResp.PublishContext[common.ContextDiskSizeGB] = strconv.FormatInt(disk.GetSizeGb(), 10) instance, err := gceCS.CloudProvider.GetInstanceOrError(ctx, project, instanceZone, instanceName) if err != nil { if gce.IsGCENotFoundError(err) { diff --git a/pkg/gce-pd-csi-driver/node.go b/pkg/gce-pd-csi-driver/node.go index f96bdac14..ce8e6afbb 100644 --- a/pkg/gce-pd-csi-driver/node.go +++ b/pkg/gce-pd-csi-driver/node.go @@ -435,6 +435,17 @@ func (ns *GCENodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStage klog.V(4).Infof("CSI volume is read-only, mounting with extra option ro") } + // If a disk size is provided in the publish context, ensure it matches the actual device size. + if expectedSize := req.GetPublishContext()[common.ContextDiskSizeGB]; expectedSize != "" { + actualSize, err := getBlockSizeBytes(devicePath, ns.Mounter) + if err != nil { + return nil, status.Error(codes.Internal, fmt.Sprintf("failed to get block size for '%s': %v", devicePath, err.Error())) + } + if expectedSize != strconv.FormatInt(actualSize, 10) { + return nil, status.Error(codes.Internal, fmt.Sprintf("expected block size %q, got %q", expectedSize, strconv.FormatInt(actualSize, 10))) + } + } + err = ns.formatAndMount(devicePath, stagingTargetPath, fstype, options, ns.Mounter) if err != nil { // If a volume is created from a content source like snapshot or cloning, the filesystem might get marked diff --git a/pkg/gce-pd-csi-driver/node_test.go b/pkg/gce-pd-csi-driver/node_test.go index 77ef9c39c..e7f4d927e 100644 --- a/pkg/gce-pd-csi-driver/node_test.go +++ b/pkg/gce-pd-csi-driver/node_test.go @@ -32,6 +32,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "k8s.io/mount-utils" + "sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/common" "sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/deviceutils" metadataservice "sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/gce-cloud-provider/metadata" "sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/linkcache" @@ -1104,6 +1105,41 @@ func TestNodeStageVolume(t *testing.T) { }, }, }, + { + name: "Valid request with disk size check", + req: &csi.NodeStageVolumeRequest{ + VolumeId: volumeID, + StagingTargetPath: stagingPath, + VolumeCapability: stdVolCap, + PublishContext: map[string]string{common.ContextDiskSizeGB: "1"}, + }, + deviceSize: 1, + blockExtSize: 1, + readonlyBit: "1", + expResize: false, + expCommandList: []fakeCmd{ + { + cmd: "blockdev", + args: "--getsize64 /dev/disk/fake-path", + stdout: "%v", + }, + { + cmd: "blkid", + args: "-p -s TYPE -s PTTYPE -o export /dev/disk/fake-path", + stdout: "DEVNAME=/dev/sdb\nTYPE=%v", + }, + { + cmd: "fsck", + args: "-a /dev/disk/fake-path", + stdout: "", + }, + { + cmd: "blockdev", + args: "--getro /dev/disk/fake-path", + stdout: "%v", + }, + }, + }, { name: "Invalid request (Bad Access Mode)", req: &csi.NodeStageVolumeRequest{ @@ -1183,6 +1219,24 @@ func TestNodeStageVolume(t *testing.T) { }, expErrCode: codes.InvalidArgument, }, + { + name: "Invalid request, block size mismatch", + req: &csi.NodeStageVolumeRequest{ + VolumeId: volumeID, + StagingTargetPath: stagingPath, + VolumeCapability: stdVolCap, + PublishContext: map[string]string{common.ContextDiskSizeGB: "10"}, + }, + deviceSize: 5, + expErrCode: codes.Internal, + expCommandList: []fakeCmd{ + { + cmd: "blockdev", + args: "--getsize64 /dev/disk/fake-path", + stdout: "%v", + }, + }, + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { From c2fe2e7d2dabf359620d84135e0aadb0230cd3d7 Mon Sep 17 00:00:00 2001 From: Elijah Rodriguez-Beltran Date: Fri, 26 Sep 2025 18:26:03 +0000 Subject: [PATCH 2/2] Flag protect disk validation --- cmd/gce-pd-csi-driver/main.go | 5 ++++- pkg/gce-pd-csi-driver/controller.go | 10 +++++++--- pkg/gce-pd-csi-driver/gce-pd-driver.go | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/cmd/gce-pd-csi-driver/main.go b/cmd/gce-pd-csi-driver/main.go index b0883a444..9f3f1554d 100644 --- a/cmd/gce-pd-csi-driver/main.go +++ b/cmd/gce-pd-csi-driver/main.go @@ -100,6 +100,8 @@ var ( diskCacheSyncPeriod = flag.Duration("disk-cache-sync-period", 10*time.Minute, "Period for the disk cache to check the /dev/disk/by-id/ directory and evaluate the symlinks") + enableDiskSizeValidation = flag.Bool("enable-disk-size-validation", false, "If set to true, the driver will validate that the requested disk size is matches the physical disk size. This flag is disabled by default.") + version string ) @@ -251,7 +253,8 @@ func handle() { maxBackoffDuration := time.Duration(*errorBackoffMaxDurationMs) * time.Millisecond // TODO(2042): Move more of the constructor args into this struct args := &driver.GCEControllerServerArgs{ - EnableDiskTopology: *diskTopology, + EnableDiskTopology: *diskTopology, + EnableDiskSizeValidation: *enableDiskSizeValidation, } controllerServer = driver.NewControllerServer(gceDriver, cloudProvider, initialBackoffDuration, maxBackoffDuration, fallbackRequisiteZones, *enableStoragePoolsFlag, *enableDataCacheFlag, multiZoneVolumeHandleConfig, listVolumesConfig, provisionableDisksConfig, *enableHdHAFlag, args) diff --git a/pkg/gce-pd-csi-driver/controller.go b/pkg/gce-pd-csi-driver/controller.go index e17fa0e84..8526b2bf7 100644 --- a/pkg/gce-pd-csi-driver/controller.go +++ b/pkg/gce-pd-csi-driver/controller.go @@ -122,11 +122,13 @@ type GCEControllerServer struct { // new RPC methods that might be introduced in future versions of the spec. csi.UnimplementedControllerServer - EnableDiskTopology bool + EnableDiskTopology bool + EnableDiskSizeValidation bool } type GCEControllerServerArgs struct { - EnableDiskTopology bool + EnableDiskTopology bool + EnableDiskSizeValidation bool } type MultiZoneVolumeHandleConfig struct { @@ -1163,7 +1165,9 @@ func (gceCS *GCEControllerServer) executeControllerPublishVolume(ctx context.Con } return nil, common.LoggedError("Failed to getDisk: ", err), disk } - pubVolResp.PublishContext[common.ContextDiskSizeGB] = strconv.FormatInt(disk.GetSizeGb(), 10) + if gceCS.EnableDiskSizeValidation && pubVolResp.GetPublishContext() != nil { + pubVolResp.PublishContext[common.ContextDiskSizeGB] = strconv.FormatInt(disk.GetSizeGb(), 10) + } instance, err := gceCS.CloudProvider.GetInstanceOrError(ctx, project, instanceZone, instanceName) if err != nil { if gce.IsGCENotFoundError(err) { diff --git a/pkg/gce-pd-csi-driver/gce-pd-driver.go b/pkg/gce-pd-csi-driver/gce-pd-driver.go index 83ff9767a..c1740df80 100644 --- a/pkg/gce-pd-csi-driver/gce-pd-driver.go +++ b/pkg/gce-pd-csi-driver/gce-pd-driver.go @@ -178,6 +178,7 @@ func NewControllerServer(gceDriver *GCEDriver, cloudProvider gce.GCECompute, err provisionableDisksConfig: provisionableDisksConfig, enableHdHA: enableHdHA, EnableDiskTopology: args.EnableDiskTopology, + EnableDiskSizeValidation: args.EnableDiskSizeValidation, } }