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
32 changes: 16 additions & 16 deletions internal/guest/runtime/hcsv2/sandbox_root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,15 @@ func TestVirtualPodRootFromOCIBundlePath(t *testing.T) {

func TestVirtualPodRootMatchesLegacy(t *testing.T) {
// When OCIBundlePath uses the legacy prefix, the derived virtual pod root
// must match what VirtualPodRootDir() would have produced.
// must match the expected path under the legacy prefix.
ociBundlePath := "/run/gcs/c/container-id"
virtualPodID := "vpod-abc"

derived := filepath.Join(filepath.Dir(ociBundlePath), "virtual-pods", virtualPodID)
legacy := specGuest.VirtualPodRootDir(virtualPodID)
expected := "/run/gcs/c/virtual-pods/vpod-abc"

if derived != legacy {
t.Fatalf("derived %q != legacy %q — backwards compatibility broken", derived, legacy)
if derived != expected {
t.Fatalf("derived %q != expected %q — backwards compatibility broken", derived, expected)
}
}

Expand All @@ -127,8 +127,8 @@ func TestSubdirectoryPaths(t *testing.T) {
if specGuest.SandboxHugePagesMountsDirFromRoot(sandboxRoot) != specGuest.HugePagesMountsDir("sandbox-xyz") {
t.Fatal("SandboxHugePagesMountsDirFromRoot doesn't match legacy HugePagesMountsDir")
}
if specGuest.SandboxLogsDirFromRoot(sandboxRoot) != specGuest.SandboxLogsDir("sandbox-xyz", "") {
t.Fatal("SandboxLogsDirFromRoot doesn't match legacy SandboxLogsDir")
if specGuest.SandboxLogsDirFromRoot(sandboxRoot) != filepath.Join(specGuest.SandboxRootDir("sandbox-xyz"), "logs") {
t.Fatal("SandboxLogsDirFromRoot doesn't match expected logs directory")
}
}

Expand Down Expand Up @@ -171,12 +171,12 @@ func TestOldVsNewPathParity(t *testing.T) {
},
{
name: "logs dir",
oldPath: specGuest.SandboxLogsDir(sandboxID, ""),
oldPath: filepath.Join(specGuest.SandboxRootDir(sandboxID), "logs"),
newPath: filepath.Join(sandboxRoot, "logs"),
},
{
name: "log file path",
oldPath: specGuest.SandboxLogPath(sandboxID, "", "container.log"),
oldPath: filepath.Join(specGuest.SandboxRootDir(sandboxID), "logs", "container.log"),
newPath: filepath.Join(sandboxRoot, "logs", "container.log"),
},
{
Expand Down Expand Up @@ -213,42 +213,42 @@ func TestOldVsNewPathParity(t *testing.T) {
vpodCases := []pathCase{
{
name: "virtual pod root",
oldPath: specGuest.VirtualPodRootDir(vpodID),
oldPath: filepath.Join("/run/gcs/c", "virtual-pods", vpodID),
newPath: vpodSandboxRoot,
},
{
name: "virtual pod sandboxMounts",
oldPath: specGuest.VirtualPodMountsDir(vpodID),
oldPath: filepath.Join("/run/gcs/c", "virtual-pods", vpodID, "sandboxMounts"),
newPath: filepath.Join(vpodSandboxRoot, "sandboxMounts"),
},
{
name: "virtual pod tmpfs mounts",
oldPath: specGuest.VirtualPodTmpfsMountsDir(vpodID),
oldPath: filepath.Join("/run/gcs/c", "virtual-pods", vpodID, "sandboxTmpfsMounts"),
newPath: filepath.Join(vpodSandboxRoot, "sandboxTmpfsMounts"),
},
{
name: "virtual pod hugepages",
oldPath: specGuest.VirtualPodHugePagesMountsDir(vpodID),
oldPath: filepath.Join("/run/gcs/c", "virtual-pods", vpodID, "hugepages"),
newPath: filepath.Join(vpodSandboxRoot, "hugepages"),
},
{
name: "virtual pod logs",
oldPath: specGuest.SandboxLogsDir(sandboxID, vpodID),
oldPath: filepath.Join("/run/gcs/c", "virtual-pods", vpodID, "logs"),
newPath: filepath.Join(vpodSandboxRoot, "logs"),
},
{
name: "virtual pod hostname",
oldPath: filepath.Join(specGuest.VirtualPodRootDir(vpodID), "hostname"),
oldPath: filepath.Join("/run/gcs/c", "virtual-pods", vpodID, "hostname"),
newPath: filepath.Join(vpodSandboxRoot, "hostname"),
},
{
name: "virtual pod hosts",
oldPath: filepath.Join(specGuest.VirtualPodRootDir(vpodID), "hosts"),
oldPath: filepath.Join("/run/gcs/c", "virtual-pods", vpodID, "hosts"),
newPath: filepath.Join(vpodSandboxRoot, "hosts"),
},
{
name: "virtual pod resolv.conf",
oldPath: filepath.Join(specGuest.VirtualPodRootDir(vpodID), "resolv.conf"),
oldPath: filepath.Join("/run/gcs/c", "virtual-pods", vpodID, "resolv.conf"),
newPath: filepath.Join(vpodSandboxRoot, "resolv.conf"),
},
}
Expand Down
6 changes: 3 additions & 3 deletions internal/guest/runtime/hcsv2/uvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ func (h *Host) CreateContainer(ctx context.Context, id string, settings *prot.VM
return nil, err
}

if err := securitypolicy.ExtendPolicyWithNetworkingMounts(id, h.securityOptions.PolicyEnforcer, settings.OCISpecification); err != nil {
if err := securitypolicy.ExtendPolicyWithNetworkingMounts(sandboxRoot, h.securityOptions.PolicyEnforcer, settings.OCISpecification); err != nil {
return nil, err
}

Expand Down Expand Up @@ -528,7 +528,7 @@ func (h *Host) CreateContainer(ctx context.Context, id string, settings *prot.VM
_ = os.RemoveAll(settings.OCIBundlePath)
}
}()
if err := securitypolicy.ExtendPolicyWithNetworkingMounts(sandboxID, h.securityOptions.PolicyEnforcer, settings.OCISpecification); err != nil {
if err := securitypolicy.ExtendPolicyWithNetworkingMounts(sandboxRoot, h.securityOptions.PolicyEnforcer, settings.OCISpecification); err != nil {
return nil, err
}
default:
Expand All @@ -547,7 +547,7 @@ func (h *Host) CreateContainer(ctx context.Context, id string, settings *prot.VM
_ = os.RemoveAll(settings.OCIBundlePath)
}
}()
if err := securitypolicy.ExtendPolicyWithNetworkingMounts(id, h.securityOptions.PolicyEnforcer,
if err := securitypolicy.ExtendPolicyWithNetworkingMounts(c.sandboxRoot, h.securityOptions.PolicyEnforcer,
settings.OCISpecification); err != nil {
return nil, err
}
Expand Down
142 changes: 0 additions & 142 deletions internal/guest/spec/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,45 +37,6 @@ func networkingMountPaths() []string {
}
}

// GenerateWorkloadContainerNetworkMounts generates an array of specs.Mount
// required for container networking. Original spec is left untouched and
// it's the responsibility of a caller to update it.
func GenerateWorkloadContainerNetworkMounts(sandboxID string, spec *oci.Spec) []oci.Mount {
var nMounts []oci.Mount

// In multipod mode, the sandbox writes networking files (resolv.conf, hostname, hosts)
// under the virtual pod root directory. Use VirtualPodAwareSandboxRootDir to ensure
// workload containers mount from the correct path.
virtualSandboxID := spec.Annotations[annotations.VirtualPodID]
rootDir := VirtualPodAwareSandboxRootDir(sandboxID, virtualSandboxID)

logrus.WithFields(logrus.Fields{
logfields.SandboxID: sandboxID,
logfields.VirtualSandboxID: virtualSandboxID,
"rootDir": rootDir,
}).Info("GenerateWorkloadContainerNetworkMounts: resolved mount source root directory")

for _, mountPath := range networkingMountPaths() {
// Don't override if the mount is present in the spec
if MountPresent(mountPath, spec.Mounts) {
continue
}
options := []string{"bind"}
if spec.Root != nil && spec.Root.Readonly {
options = append(options, "ro")
}
trimmedMountPath := strings.TrimPrefix(mountPath, "/etc/")
mt := oci.Mount{
Destination: mountPath,
Type: "bind",
Source: filepath.Join(rootDir, trimmedMountPath),
Options: options,
}
nMounts = append(nMounts, mt)
}
return nMounts
}

// MountPresent checks if mountPath is present in the specMounts array.
func MountPresent(mountPath string, specMounts []oci.Mount) bool {
for _, m := range specMounts {
Expand All @@ -91,145 +52,42 @@ func SandboxRootDir(sandboxID string) string {
return filepath.Join(guestpath.LCOWRootPrefixInUVM, sandboxID)
}

// VirtualPodRootDir returns the virtual pod root directory inside UVM/host.
// This is used when multiple pods share a UVM via virtualSandboxID.
func VirtualPodRootDir(virtualSandboxID string) string {
// Ensure virtualSandboxID is a relative path to prevent directory traversal
sanitizedID := filepath.Clean(virtualSandboxID)
if filepath.IsAbs(sanitizedID) || strings.Contains(sanitizedID, "..") {
return ""
}
return filepath.Join(guestpath.LCOWRootPrefixInUVM, "virtual-pods", sanitizedID)
}

// VirtualPodAwareSandboxRootDir returns the appropriate root directory based on whether
// the sandbox is part of a virtual pod or traditional single-pod setup.
func VirtualPodAwareSandboxRootDir(sandboxID, virtualSandboxID string) string {
if virtualSandboxID != "" {
return VirtualPodRootDir(virtualSandboxID)
}
return SandboxRootDir(sandboxID)
}

// SandboxMountsDir returns sandbox mounts directory inside UVM/host.
func SandboxMountsDir(sandboxID string) string {
return filepath.Join(SandboxRootDir(sandboxID), "sandboxMounts")
}

// VirtualPodMountsDir returns virtual pod mounts directory inside UVM/host.
func VirtualPodMountsDir(virtualSandboxID string) string {
return filepath.Join(VirtualPodRootDir(virtualSandboxID), "sandboxMounts")
}

// VirtualPodAwareSandboxMountsDir returns the appropriate mounts directory.
func VirtualPodAwareSandboxMountsDir(sandboxID, virtualSandboxID string) string {
if virtualSandboxID != "" {
return VirtualPodMountsDir(virtualSandboxID)
}
return SandboxMountsDir(sandboxID)
}

// SandboxTmpfsMountsDir returns sandbox tmpfs mounts directory inside UVM.
func SandboxTmpfsMountsDir(sandboxID string) string {
return filepath.Join(SandboxRootDir(sandboxID), "sandboxTmpfsMounts")
}

// VirtualPodTmpfsMountsDir returns virtual pod tmpfs mounts directory inside UVM/host.
func VirtualPodTmpfsMountsDir(virtualSandboxID string) string {
return filepath.Join(VirtualPodRootDir(virtualSandboxID), "sandboxTmpfsMounts")
}

// VirtualPodAwareSandboxTmpfsMountsDir returns the appropriate tmpfs mounts directory.
func VirtualPodAwareSandboxTmpfsMountsDir(sandboxID, virtualSandboxID string) string {
if virtualSandboxID != "" {
return VirtualPodTmpfsMountsDir(virtualSandboxID)
}
return SandboxTmpfsMountsDir(sandboxID)
}

// HugePagesMountsDir returns hugepages mounts directory inside UVM.
func HugePagesMountsDir(sandboxID string) string {
return filepath.Join(SandboxRootDir(sandboxID), "hugepages")
}

// VirtualPodHugePagesMountsDir returns virtual pod hugepages mounts directory.
func VirtualPodHugePagesMountsDir(virtualSandboxID string) string {
return filepath.Join(VirtualPodRootDir(virtualSandboxID), "hugepages")
}

// VirtualPodAwareHugePagesMountsDir returns the appropriate hugepages directory.
func VirtualPodAwareHugePagesMountsDir(sandboxID, virtualSandboxID string) string {
if virtualSandboxID != "" {
return VirtualPodHugePagesMountsDir(virtualSandboxID)
}
return HugePagesMountsDir(sandboxID)
}

// SandboxMountSource returns sandbox mount path inside UVM.
func SandboxMountSource(sandboxID, path string) string {
mountsDir := SandboxMountsDir(sandboxID)
subPath := strings.TrimPrefix(path, guestpath.SandboxMountPrefix)
return filepath.Join(mountsDir, subPath)
}

// VirtualPodAwareSandboxMountSource returns mount source path for virtual pod aware containers.
func VirtualPodAwareSandboxMountSource(sandboxID, virtualSandboxID, path string) string {
if virtualSandboxID != "" {
mountsDir := VirtualPodMountsDir(virtualSandboxID)
subPath := strings.TrimPrefix(path, guestpath.SandboxMountPrefix)
return filepath.Join(mountsDir, subPath)
}
return SandboxMountSource(sandboxID, path)
}

// SandboxTmpfsMountSource returns sandbox tmpfs mount path inside UVM.
func SandboxTmpfsMountSource(sandboxID, path string) string {
tmpfsMountDir := SandboxTmpfsMountsDir(sandboxID)
subPath := strings.TrimPrefix(path, guestpath.SandboxTmpfsMountPrefix)
return filepath.Join(tmpfsMountDir, subPath)
}

// VirtualPodAwareSandboxTmpfsMountSource returns tmpfs mount source path for virtual pod aware containers.
func VirtualPodAwareSandboxTmpfsMountSource(sandboxID, virtualSandboxID, path string) string {
if virtualSandboxID != "" {
mountsDir := VirtualPodTmpfsMountsDir(virtualSandboxID)
subPath := strings.TrimPrefix(path, guestpath.SandboxTmpfsMountPrefix)
return filepath.Join(mountsDir, subPath)
}
return SandboxTmpfsMountSource(sandboxID, path)
}

// HugePagesMountSource returns hugepages mount path inside UVM.
func HugePagesMountSource(sandboxID, path string) string {
mountsDir := HugePagesMountsDir(sandboxID)
subPath := strings.TrimPrefix(path, guestpath.HugePagesMountPrefix)
return filepath.Join(mountsDir, subPath)
}

// VirtualPodAwareHugePagesMountSource returns hugepages mount source for virtual pod aware containers.
func VirtualPodAwareHugePagesMountSource(sandboxID, virtualSandboxID, path string) string {
if virtualSandboxID != "" {
mountsDir := VirtualPodHugePagesMountsDir(virtualSandboxID)
subPath := strings.TrimPrefix(path, guestpath.HugePagesMountPrefix)
return filepath.Join(mountsDir, subPath)
}
return HugePagesMountSource(sandboxID, path)
}

// SandboxLogsDir returns the logs directory inside the UVM for forwarding container stdio to.
//
// Virtual pod aware.
func SandboxLogsDir(sandboxID, virtualSandboxID string) string {
return filepath.Join(VirtualPodAwareSandboxRootDir(sandboxID, virtualSandboxID), "logs")
}

// SandboxLogPath returns the log path inside the UVM.
//
// Virtual pod aware.
func SandboxLogPath(sandboxID, virtualSandboxID, path string) string {
return filepath.Join(SandboxLogsDir(sandboxID, virtualSandboxID), path)
}

// Root-based path helpers. These accept a pre-resolved sandbox root directory
// and are used by the guest-side sandbox root mapping for Shim v2 / multi-pod support.

Expand Down
8 changes: 2 additions & 6 deletions pkg/securitypolicy/securitypolicy_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,8 @@ import (
//nolint:unused
const osType = "linux"

func ExtendPolicyWithNetworkingMounts(sandboxID string, enforcer SecurityPolicyEnforcer, spec *oci.Spec) error {
roSpec := &oci.Spec{
Root: spec.Root,
Annotations: spec.Annotations,
}
networkingMounts := specInternal.GenerateWorkloadContainerNetworkMounts(sandboxID, roSpec)
func ExtendPolicyWithNetworkingMounts(sandboxRoot string, enforcer SecurityPolicyEnforcer, spec *oci.Spec) error {
networkingMounts := specInternal.GenerateWorkloadContainerNetworkMountsFromRoot(sandboxRoot, spec)
if err := enforcer.ExtendDefaultMounts(networkingMounts); err != nil {
return err
}
Expand Down