Skip to content

Commit b28c301

Browse files
authored
Merge pull request #1410 from elezar/use-os-root
Switch to go 1.25 os.Root
2 parents a7a8df2 + 4a4e7f8 commit b28c301

File tree

7 files changed

+45
-90
lines changed

7 files changed

+45
-90
lines changed

cmd/nvidia-cdi-hook/disable-device-node-modification/disable-device-node-modification.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,13 @@ func run(_ context.Context, _ *cli.Command, cfg *options) error {
9090
return fmt.Errorf("failed to determined container root: %w", err)
9191
}
9292

93-
return createParamsFileInContainer(containerRootDirPath, modifiedParamsFileContents)
93+
containerRoot, err := os.OpenRoot(containerRootDirPath)
94+
if err != nil {
95+
return fmt.Errorf("failed to open root: %w", err)
96+
}
97+
defer containerRoot.Close()
98+
99+
return createParamsFileInContainer(containerRoot, modifiedParamsFileContents)
94100
}
95101

96102
func getModifiedNVIDIAParamsContents() ([]byte, error) {

cmd/nvidia-cdi-hook/disable-device-node-modification/params_linux.go

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,32 +20,32 @@
2020
package disabledevicenodemodification
2121

2222
import (
23-
"errors"
2423
"fmt"
2524
"os"
2625
"path/filepath"
2726

28-
securejoin "github.com/cyphar/filepath-securejoin"
27+
"github.com/google/uuid"
2928
"github.com/opencontainers/runc/libcontainer/utils"
3029
"golang.org/x/sys/unix"
3130
)
3231

33-
func createParamsFileInContainer(containerRootDirPath string, contents []byte) error {
34-
hookScratchDirPath := "/var/run/nvidia-ctk-hook"
35-
if err := utils.MkdirAllInRoot(containerRootDirPath, hookScratchDirPath, 0755); err != nil {
32+
func createParamsFileInContainer(containerRoot *os.Root, contents []byte) error {
33+
containerRootDirPath := containerRoot.Name()
34+
35+
hookScratchDirPath := "/run/nvidia-ctk-hook" + uuid.NewString()
36+
if err := containerRoot.MkdirAll(hookScratchDirPath[1:], 0755); err != nil {
3637
return fmt.Errorf("error creating hook scratch folder: %w", err)
3738
}
3839

3940
err := utils.WithProcfd(containerRootDirPath, hookScratchDirPath, func(hookScratchDirFdPath string) error {
4041
return createTmpFs(hookScratchDirFdPath, len(contents))
41-
4242
})
4343
if err != nil {
4444
return fmt.Errorf("failed to create tmpfs mount for params file: %w", err)
4545
}
4646

4747
modifiedParamsFilePath := filepath.Join(hookScratchDirPath, "nvct-params")
48-
if _, err := createFileInRoot(containerRootDirPath, modifiedParamsFilePath, 0444); err != nil {
48+
if _, err := containerRoot.OpenFile(modifiedParamsFilePath[1:], os.O_CREATE|os.O_RDONLY|os.O_TRUNC, 0444); err != nil {
4949
return fmt.Errorf("error creating modified params file: %w", err)
5050
}
5151

@@ -79,32 +79,3 @@ func createParamsFileInContainer(containerRootDirPath string, contents []byte) e
7979
func createTmpFs(target string, size int) error {
8080
return unix.Mount("tmpfs", target, "tmpfs", 0, fmt.Sprintf("size=%d", size))
8181
}
82-
83-
// TODO(ArangoGutierrez): This function also exists in internal/ldconfig we should move this to a separate package.
84-
func createFileInRoot(containerRootDirPath string, destinationPath string, mode os.FileMode) (string, error) {
85-
dest, err := securejoin.SecureJoin(containerRootDirPath, destinationPath)
86-
if err != nil {
87-
return "", err
88-
}
89-
// Make the parent directory.
90-
destDir, destBase := filepath.Split(dest)
91-
destDirFd, err := utils.MkdirAllInRootOpen(containerRootDirPath, destDir, 0755)
92-
if err != nil {
93-
return "", fmt.Errorf("error creating parent dir: %w", err)
94-
}
95-
defer destDirFd.Close()
96-
// Make the target file. We want to avoid opening any file that is
97-
// already there because it could be a "bad" file like an invalid
98-
// device or hung tty that might cause a DoS, so we use mknodat.
99-
// destBase does not contain any "/" components, and mknodat does
100-
// not follow trailing symlinks, so we can safely just call mknodat
101-
// here.
102-
if err := unix.Mknodat(int(destDirFd.Fd()), destBase, unix.S_IFREG|uint32(mode), 0); err != nil {
103-
// If we get EEXIST, there was already an inode there and
104-
// we can consider that a success.
105-
if !errors.Is(err, unix.EEXIST) {
106-
return "", fmt.Errorf("error creating empty file: %w", err)
107-
}
108-
}
109-
return dest, nil
110-
}

cmd/nvidia-cdi-hook/disable-device-node-modification/params_other.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919

2020
package disabledevicenodemodification
2121

22-
import "fmt"
22+
import (
23+
"fmt"
24+
"os"
25+
)
2326

24-
func createParamsFileInContainer(containerRootDirPath string, contents []byte) error {
27+
func createParamsFileInContainer(containerRootDirPath *os.Root, contents []byte) error {
2528
return fmt.Errorf("not supported")
2629
}

go.mod

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
module github.com/NVIDIA/nvidia-container-toolkit
22

3-
go 1.24.0
4-
5-
toolchain go1.24.4
3+
go 1.25.0
64

75
require (
86
github.com/NVIDIA/go-nvlib v0.8.1
97
github.com/NVIDIA/go-nvml v0.13.0-1
10-
github.com/cyphar/filepath-securejoin v0.5.0
8+
github.com/google/uuid v1.6.0
119
github.com/moby/sys/reexec v0.1.0
1210
github.com/moby/sys/symlink v0.3.0
1311
github.com/opencontainers/runc v1.3.2
@@ -24,10 +22,10 @@ require (
2422
)
2523

2624
require (
25+
github.com/cyphar/filepath-securejoin v0.5.0 // indirect
2726
github.com/davecgh/go-spew v1.1.1 // indirect
2827
github.com/fsnotify/fsnotify v1.7.0 // indirect
2928
github.com/google/go-cmp v0.6.0 // indirect
30-
github.com/google/uuid v1.6.0 // indirect
3129
github.com/hashicorp/errwrap v1.1.0 // indirect
3230
github.com/kr/pretty v0.3.1 // indirect
3331
github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 // indirect

internal/ldconfig/ldconfig.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,22 +135,28 @@ func (l *Ldconfig) UpdateLDCache() error {
135135
}
136136

137137
func (l *Ldconfig) prepareRoot() (string, error) {
138+
root, err := os.OpenRoot(l.inRoot)
139+
if err != nil {
140+
return "", fmt.Errorf("failed to open root: %w", err)
141+
}
142+
defer root.Close()
143+
138144
// To prevent leaking the parent proc filesystem, we create a new proc mount
139145
// in the specified root.
140-
if err := mountProc(l.inRoot); err != nil {
146+
if err := mountProc(root); err != nil {
141147
return "", fmt.Errorf("error mounting /proc: %w", err)
142148
}
143149

144150
// We mount the host ldconfig before we pivot root since host paths are not
145151
// visible after the pivot root operation.
146-
ldconfigPath, err := mountLdConfig(l.ldconfigPath, l.inRoot)
152+
ldconfigPath, err := mountLdConfig(l.ldconfigPath, root)
147153
if err != nil {
148154
return "", fmt.Errorf("error mounting host ldconfig: %w", err)
149155
}
150156

151157
// We pivot to the container root for the new process, this further limits
152158
// access to the host.
153-
if err := pivotRoot(l.inRoot); err != nil {
159+
if err := pivotRoot(root.Name()); err != nil {
154160
return "", fmt.Errorf("error running pivot_root: %w", err)
155161
}
156162

internal/ldconfig/ldconfig_linux.go

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,14 @@
2020
package ldconfig
2121

2222
import (
23-
"errors"
2423
"fmt"
2524
"os"
2625
"os/exec"
2726
"path/filepath"
2827
"strconv"
2928
"syscall"
3029

31-
securejoin "github.com/cyphar/filepath-securejoin"
30+
"github.com/google/uuid"
3231
"github.com/moby/sys/reexec"
3332

3433
"github.com/opencontainers/runc/libcontainer/utils"
@@ -102,27 +101,28 @@ func pivotRoot(rootfs string) error {
102101
// mountLdConfig mounts the host ldconfig to the mount namespace of the hook.
103102
// We use WithProcfd to perform the mount operations to ensure that the changes
104103
// are persisted across the pivot root.
105-
func mountLdConfig(hostLdconfigPath string, containerRootDirPath string) (string, error) {
104+
func mountLdConfig(hostLdconfigPath string, containerRoot *os.Root) (string, error) {
105+
containerRootDirPath := containerRoot.Name()
106+
106107
hostLdconfigInfo, err := os.Stat(hostLdconfigPath)
107108
if err != nil {
108109
return "", fmt.Errorf("error reading host ldconfig: %w", err)
109110
}
110111

111-
hookScratchDirPath := "/var/run/nvidia-ctk-hook"
112+
hookScratchDirPath := "/run/nvidia-ctk-hook/" + uuid.NewString()
112113
ldconfigPath := filepath.Join(hookScratchDirPath, "ldconfig")
113-
if err := utils.MkdirAllInRoot(containerRootDirPath, hookScratchDirPath, 0755); err != nil {
114+
if err := containerRoot.MkdirAll(hookScratchDirPath[1:], 0755); err != nil {
114115
return "", fmt.Errorf("error creating hook scratch folder: %w", err)
115116
}
116117

117118
err = utils.WithProcfd(containerRootDirPath, hookScratchDirPath, func(hookScratchDirFdPath string) error {
118119
return createTmpFs(hookScratchDirFdPath, int(hostLdconfigInfo.Size()))
119-
120120
})
121121
if err != nil {
122122
return "", fmt.Errorf("error creating tmpfs: %w", err)
123123
}
124124

125-
if _, err := createFileInRoot(containerRootDirPath, ldconfigPath, hostLdconfigInfo.Mode()); err != nil {
125+
if _, err := containerRoot.OpenFile(ldconfigPath[1:], os.O_CREATE|os.O_RDWR|os.O_TRUNC, hostLdconfigInfo.Mode()); err != nil {
126126
return "", fmt.Errorf("error creating ldconfig: %w", err)
127127
}
128128

@@ -136,43 +136,13 @@ func mountLdConfig(hostLdconfigPath string, containerRootDirPath string) (string
136136
return ldconfigPath, nil
137137
}
138138

139-
func createFileInRoot(containerRootDirPath string, destinationPath string, mode os.FileMode) (string, error) {
140-
dest, err := securejoin.SecureJoin(containerRootDirPath, destinationPath)
141-
if err != nil {
142-
return "", err
143-
}
144-
// Make the parent directory.
145-
destDir, destBase := filepath.Split(dest)
146-
destDirFd, err := utils.MkdirAllInRootOpen(containerRootDirPath, destDir, 0755)
147-
if err != nil {
148-
return "", fmt.Errorf("error creating parent dir: %w", err)
149-
}
150-
defer destDirFd.Close()
151-
// Make the target file. We want to avoid opening any file that is
152-
// already there because it could be a "bad" file like an invalid
153-
// device or hung tty that might cause a DoS, so we use mknodat.
154-
// destBase does not contain any "/" components, and mknodat does
155-
// not follow trailing symlinks, so we can safely just call mknodat
156-
// here.
157-
if err := unix.Mknodat(int(destDirFd.Fd()), destBase, unix.S_IFREG|uint32(mode), 0); err != nil {
158-
// If we get EEXIST, there was already an inode there and
159-
// we can consider that a success.
160-
if !errors.Is(err, unix.EEXIST) {
161-
return "", fmt.Errorf("error creating empty file: %w", err)
162-
}
163-
}
164-
return dest, nil
165-
}
166-
167139
// mountProc mounts a clean proc filesystem in the new root.
168-
func mountProc(newroot string) error {
169-
target, err := securejoin.SecureJoin(newroot, "proc")
170-
if err != nil {
171-
return err
172-
}
173-
if err := utils.MkdirAllInRoot(newroot, target, 0755); err != nil {
140+
func mountProc(newroot *os.Root) error {
141+
if err := newroot.MkdirAll("proc", 0755); err != nil {
174142
return err
175143
}
144+
145+
target := filepath.Join(newroot.Name(), "proc")
176146
return unix.Mount("proc", target, "proc", 0, "")
177147
}
178148

internal/ldconfig/ldconfig_other.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,19 @@ package ldconfig
2121

2222
import (
2323
"fmt"
24+
"os"
2425
"os/exec"
2526
)
2627

2728
func pivotRoot(newroot string) error {
2829
return fmt.Errorf("not supported")
2930
}
3031

31-
func mountLdConfig(hostLdconfigPath string, containerRootDirPath string) (string, error) {
32+
func mountLdConfig(hostLdconfigPath string, containerRoot *os.Root) (string, error) {
3233
return "", fmt.Errorf("not supported")
3334
}
3435

35-
func mountProc(newroot string) error {
36+
func mountProc(newroot *os.Root) error {
3637
return fmt.Errorf("not supported")
3738
}
3839

0 commit comments

Comments
 (0)