From e1a198baa30de5873fca51845d16d584cff6f1de Mon Sep 17 00:00:00 2001 From: Dmitry Voropaev Date: Thu, 8 Oct 2026 15:07:57 +0300 Subject: [PATCH] Require a path separator below the device-mount root requestsFromMounts tests the container mount destination with strings.HasPrefix against /var/run/nvidia-container-devices and then trims that prefix, so a sibling path with the same leading characters is read as a device request: /var/run/nvidia-container-devices-backup/GPU0 -> device "-backup/GPU0" /var/run/nvidia-container-devicesimex/0 -> IMEX channel "0" /var/run/nvidia-container-devicescdi/n.com/gpu=0 -> CDI device "n.com/gpu=0" The first fails the container with an unresolvable device name. The other two are worse than that, because the request looks valid: a /dev/null mount at a path that is not below the device root ends up requesting an IMEX channel, or a fully qualified CDI device, which also sends the container down the OnlyFullyQualifiedCDIDevices path. Require the separator. A destination equal to the root is still ignored, as before, and the existing "Container path is only 'root'" case covers it. Signed-off-by: Dmitry Voropaev --- internal/config/image/cuda_image.go | 7 ++- internal/config/image/cuda_image_test.go | 55 ++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/internal/config/image/cuda_image.go b/internal/config/image/cuda_image.go index a06a7bb31..f46726f1d 100644 --- a/internal/config/image/cuda_image.go +++ b/internal/config/image/cuda_image.go @@ -370,8 +370,11 @@ func (i CUDA) requestsFromMounts() []string { } seen[destination] = true - // Only consider container mount points that begin with 'root' - if !strings.HasPrefix(destination, root) { + // Only consider container mount points below 'root'. The separator is + // required: without it a sibling path such as + // /var/run/nvidia-container-devices-backup/GPU0 has the same prefix, + // and the remainder is read as a device request. + if !strings.HasPrefix(destination, root+"/") { continue } diff --git a/internal/config/image/cuda_image_test.go b/internal/config/image/cuda_image_test.go index ec73f6574..e7b52afd8 100644 --- a/internal/config/image/cuda_image_test.go +++ b/internal/config/image/cuda_image_test.go @@ -513,6 +513,30 @@ func TestGetVisibleDevicesFromMounts(t *testing.T) { mounts: makeTestMounts("GPU0", "imex/0", "GPU1"), expectedDevices: []string{"GPU0", "GPU1"}, }, + { + description: "Container path is a sibling of 'root'", + mounts: []specs.Mount{ + { + Source: "/dev/null", + Destination: DeviceListAsVolumeMountsRoot + "-backup/GPU0", + }, + { + Source: "/dev/null", + Destination: DeviceListAsVolumeMountsRoot + ".old/GPU1", + }, + }, + expectedDevices: nil, + }, + { + description: "A sibling of 'root' does not request a CDI device", + mounts: []specs.Mount{ + { + Source: "/dev/null", + Destination: DeviceListAsVolumeMountsRoot + "cdi/nvidia.com/gpu=0", + }, + }, + expectedDevices: nil, + }, } for _, tc := range tests { t.Run(tc.description, func(t *testing.T) { @@ -523,6 +547,37 @@ func TestGetVisibleDevicesFromMounts(t *testing.T) { } } +func TestImexChannelsFromMounts(t *testing.T) { + var tests = []struct { + description string + mounts []specs.Mount + expectedChannels []string + }{ + { + description: "channels below 'root' are requested", + mounts: makeTestMounts("imex/0", "GPU0", "imex/1"), + expectedChannels: []string{"0", "1"}, + }, + { + description: "a sibling of 'root' does not request a channel", + mounts: []specs.Mount{ + { + Source: "/dev/null", + Destination: DeviceListAsVolumeMountsRoot + "imex/0", + }, + }, + expectedChannels: nil, + }, + } + for _, tc := range tests { + t.Run(tc.description, func(t *testing.T) { + image, err := New(WithMounts(tc.mounts)) + require.NoError(t, err) + require.Equal(t, tc.expectedChannels, image.imexChannelsFromMounts()) + }) + } +} + func TestVisibleDevices(t *testing.T) { var tests = []struct { description string