core/runtime: Check shim PluginInfo to enforce idmap support
This commit gets rid of the TODO by moving the check to use the pluginInfo() infrastructure. The check is only enforced for shims that return info that can be read as type runtime.Features. For shims that don't provide that, we just ignore it, as those shims might not be affected by this. Signed-off-by: Rodrigo Campos <rodrigoca@microsoft.com>
This commit is contained in:
@@ -19,13 +19,18 @@ package v2
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"slices"
|
||||
|
||||
"github.com/containerd/errdefs"
|
||||
"github.com/containerd/plugin"
|
||||
"github.com/containerd/plugin/registry"
|
||||
"github.com/containerd/typeurl/v2"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/opencontainers/runtime-spec/specs-go/features"
|
||||
|
||||
apitypes "github.com/containerd/containerd/v2/api/types"
|
||||
"github.com/containerd/containerd/v2/core/runtime"
|
||||
@@ -111,6 +116,12 @@ func (m *TaskManager) Create(ctx context.Context, taskID string, opts runtime.Cr
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// runc ignores silently features it doesn't know about, so for things that this is
|
||||
// problematic let's check if this runc version supports them.
|
||||
if err := m.validateRuntimeFeatures(ctx, opts); err != nil {
|
||||
return nil, fmt.Errorf("failed to validate OCI runtime features: %w", err)
|
||||
}
|
||||
|
||||
t, err := shimTask.Create(ctx, opts)
|
||||
if err != nil {
|
||||
// NOTE: ctx contains required namespace information.
|
||||
@@ -224,3 +235,71 @@ func (m *TaskManager) PluginInfo(ctx context.Context, request interface{}) (inte
|
||||
}
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func (m *TaskManager) validateRuntimeFeatures(ctx context.Context, opts runtime.CreateOpts) error {
|
||||
var spec specs.Spec
|
||||
if err := typeurl.UnmarshalTo(opts.Spec, &spec); err != nil {
|
||||
return fmt.Errorf("unmarshal spec: %w", err)
|
||||
}
|
||||
|
||||
// Only ask for the PluginInfo if idmap mounts are used.
|
||||
if !usesIDMapMounts(spec) {
|
||||
return nil
|
||||
}
|
||||
|
||||
pInfo, err := m.PluginInfo(ctx, &apitypes.RuntimeRequest{RuntimePath: opts.Runtime})
|
||||
if err != nil {
|
||||
return fmt.Errorf("runtime info: %w", err)
|
||||
}
|
||||
|
||||
pluginInfo, ok := pInfo.(*apitypes.RuntimeInfo)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid runtime info type: %T", pInfo)
|
||||
}
|
||||
|
||||
feat, err := typeurl.UnmarshalAny(pluginInfo.Features)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshal runtime features: %w", err)
|
||||
}
|
||||
|
||||
// runc-compatible runtimes silently ignores features it doesn't know about. But ignoring
|
||||
// our request to use idmap mounts can break permissions in the volume, so let's make sure
|
||||
// it supports it. For more info, see:
|
||||
// https://github.com/opencontainers/runtime-spec/pull/1219
|
||||
//
|
||||
features, ok := feat.(*features.Features)
|
||||
if !ok {
|
||||
// Leave alone non runc-compatible runtimes that don't provide the features info,
|
||||
// they might not be affected by this.
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := supportsIDMapMounts(features); err != nil {
|
||||
return fmt.Errorf("idmap mounts not supported: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func usesIDMapMounts(spec specs.Spec) bool {
|
||||
for _, m := range spec.Mounts {
|
||||
if m.UIDMappings != nil || m.GIDMappings != nil {
|
||||
return true
|
||||
}
|
||||
if slices.Contains(m.Options, "idmap") || slices.Contains(m.Options, "ridmap") {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func supportsIDMapMounts(features *features.Features) error {
|
||||
if features.Linux.MountExtensions == nil || features.Linux.MountExtensions.IDMap == nil {
|
||||
return errors.New("missing `mountExtensions.idmap` entry in `features` command")
|
||||
}
|
||||
if enabled := features.Linux.MountExtensions.IDMap.Enabled; enabled == nil || !*enabled {
|
||||
return errors.New("entry `mountExtensions.idmap.Enabled` in `features` command not present or disabled")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user