@@ -19,6 +19,7 @@ package v2
1919import (
2020 "bytes"
2121 "context"
22+ "errors"
2223 "fmt"
2324 "os"
2425 "os/exec"
@@ -42,6 +43,9 @@ import (
4243 "github.com/containerd/containerd/runtime"
4344 shimbinary "github.com/containerd/containerd/runtime/v2/shim"
4445 "github.com/containerd/containerd/sandbox"
46+ "github.com/containerd/typeurl/v2"
47+ "github.com/opencontainers/runtime-spec/specs-go"
48+ "github.com/opencontainers/runtime-spec/specs-go/features"
4549)
4650
4751// Config for the v2 runtime
@@ -420,6 +424,10 @@ func (m *TaskManager) Create(ctx context.Context, taskID string, opts runtime.Cr
420424 return nil , err
421425 }
422426
427+ if err := m .validateRuntimeFeatures (ctx , opts ); err != nil {
428+ return nil , fmt .Errorf ("failed to validate OCI runtime features: %w" , err )
429+ }
430+
423431 t , err := shimTask .Create (ctx , opts )
424432 if err != nil {
425433 // NOTE: ctx contains required namespace information.
@@ -532,3 +540,53 @@ func (m *TaskManager) RuntimeInfo(ctx context.Context, runtimeName string, runti
532540 }
533541 return & info , nil
534542}
543+
544+ func (m * TaskManager ) validateRuntimeFeatures (ctx context.Context , opts runtime.CreateOpts ) error {
545+ // Get a typed version of the spec.
546+ var spec specs.Spec
547+ if err := typeurl .UnmarshalTo (opts .Spec , & spec ); err != nil {
548+ return fmt .Errorf ("unmarshal spec: %w" , err )
549+ }
550+
551+ // Get features from runtime.
552+ rInfo , err := m .RuntimeInfo (ctx , opts .Runtime , nil )
553+ if err != nil {
554+ return fmt .Errorf ("runtime info: %w" , err )
555+ }
556+
557+ feat , err := typeurl .UnmarshalAny (rInfo .Features )
558+ if err != nil {
559+ return fmt .Errorf ("unmarshal runtime features: %w" , err )
560+ }
561+ features , ok := feat .(* features.Features )
562+ if ! ok {
563+ return fmt .Errorf ("invalid features type: %T" , rInfo .Features )
564+ }
565+
566+ if err := validateIDMapMounts (spec , features ); err != nil {
567+ return fmt .Errorf ("idmap mounts: %w" , err )
568+ }
569+ return nil
570+ }
571+
572+ func validateIDMapMounts (spec specs.Spec , features * features.Features ) error {
573+ var idmapUsed bool
574+ for _ , m := range spec .Mounts {
575+ if m .UIDMappings != nil || m .GIDMappings != nil {
576+ idmapUsed = true
577+ break
578+ }
579+ }
580+ if ! idmapUsed {
581+ return nil
582+ }
583+
584+ if features .Linux .MountExtensions == nil || features .Linux .MountExtensions .IDMap == nil {
585+ return errors .New ("missing `mountExtensions.idmap` entry in `features` command" )
586+
587+ }
588+ if enabled := features .Linux .MountExtensions .IDMap .Enabled ; enabled == nil || ! * enabled {
589+ return errors .New ("not supported or disabled" )
590+ }
591+ return nil
592+ }
0 commit comments