diff --git a/internal/gcs-sidecar/handlers.go b/internal/gcs-sidecar/handlers.go index f5a7c48d5e..6406ef7029 100644 --- a/internal/gcs-sidecar/handlers.go +++ b/internal/gcs-sidecar/handlers.go @@ -4,6 +4,7 @@ package bridge import ( + "context" "encoding/hex" "encoding/json" "fmt" @@ -130,6 +131,15 @@ func (b *Bridge) createContainer(req *request) (err error) { return fmt.Errorf("CreateContainer operation is denied by policy: %w", err) } + // Create the source directory for each mapped directory if it does not + // already exist. In non-confidential WCOW the host does this for + // sandbox:// mounts by exec'ing `cmd /c mkdir ... & dir ...` inside the + // UVM (see resources_wcow.go:setupMounts), but for confidential, we + // handle this here in the sidecar GCS. + if err := createMappedDirectorySourceDirs(ctx, container.MappedDirectories); err != nil { + return fmt.Errorf("failed to create mapped directory source directories: %w", err) + } + commandLine := len(spec.Process.Args) > 0 c := &Container{ id: containerID, @@ -201,6 +211,28 @@ func (b *Bridge) createContainer(req *request) (err error) { return nil } +// createMappedDirectorySourceDirs creates the host-side source directory for +// every mapped directory (i.e. "mounts") in the container document, if it does +// not already exist. +func createMappedDirectorySourceDirs(ctx context.Context, mappedDirectories []hcsschema.MappedDirectory) error { + for _, md := range mappedDirectories { + source := md.HostPath + + if _, err := os.Stat(source); err == nil { + // exists + continue + } else if !os.IsNotExist(err) { + return fmt.Errorf("failed to stat mapped directory source %q: %w", source, err) + } + + if err := os.MkdirAll(source, 0755); err != nil { + return fmt.Errorf("failed to create mapped directory source %q: %w", source, err) + } + log.G(ctx).WithField("source", source).Debug("created mapped directory source directory") + } + return nil +} + // processParamEnvToOCIEnv converts an Environment field from ProcessParameters // (a map from environment variable to value) into an array of environment // variable assignments (where each is in the form "=") which diff --git a/internal/hcsoci/resources_wcow.go b/internal/hcsoci/resources_wcow.go index baa5d7fb7d..31b35f4246 100644 --- a/internal/hcsoci/resources_wcow.go +++ b/internal/hcsoci/resources_wcow.go @@ -206,20 +206,27 @@ func setupMounts(ctx context.Context, coi *createOptionsInternal, r *resources.R // Now we need to exec a process in the vm that will make these directories as theres // no functionality in the Windows gcs to create an arbitrary directory. // - // Create the directory, but also run dir afterwards regardless of if mkdir succeeded to handle the case where the directory already exists - // e.g. from a previous container specifying the same mount (and thus creating the same directory). - b := &bytes.Buffer{} - stderr, err := cmd.CreatePipeAndListen(b, false) - if err != nil { - return err - } - req := &cmd.CmdProcessRequest{ - Args: []string{"cmd", "/c", "mkdir", sandboxPath, "&", "dir", sandboxPath}, - Stderr: stderr, - } - exitCode, err := coi.HostingSystem.ExecInUVM(ctx, req) - if err != nil { - return errors.Wrapf(err, "failed to create sandbox mount directory in utility VM with exit code %d %q", exitCode, b.String()) + // We do not need to do this for Confidential WCOW, because in that case the gcs-sidecar + // handles the create container request and will do this for us. This way the policy + // does not have to have exceptions for allowing such mkdir commands. + // + // Create the directory, but also run dir afterwards regardless of if mkdir succeeded to + // handle the case where the directory already exists e.g. from a previous container + // specifying the same mount (and thus creating the same directory). + if !coi.HostingSystem.HasConfidentialPolicy() { + b := &bytes.Buffer{} + stderr, err := cmd.CreatePipeAndListen(b, false) + if err != nil { + return err + } + req := &cmd.CmdProcessRequest{ + Args: []string{"cmd", "/c", "mkdir", sandboxPath, "&", "dir", sandboxPath}, + Stderr: stderr, + } + exitCode, err := coi.HostingSystem.ExecInUVM(ctx, req) + if err != nil { + return errors.Wrapf(err, "failed to create sandbox mount directory in utility VM with exit code %d %q", exitCode, b.String()) + } } } else if np, ok := uvm.ParseNamedPipe(coi.HostingSystem, mount); ok { if !np.UVMPipe {