Skip to content

Commit bf553e3

Browse files
committed
fix(ldconfig): add support for rootless mode in ldconfig to suppress /proc mount error for non-root users
Non-root users are not permitted to mount /proc, which causes `mountProc` to fail and abort `prepareRoot`. To prevent this, the error is now suppressed with `rootless=true` argument at 3rd in `soname-symlinks` and `update-ldcache` instead of causing a failure, allowing continued execution.
1 parent 178348b commit bf553e3

File tree

3 files changed

+54
-43
lines changed

3 files changed

+54
-43
lines changed

cmd/nvidia-cdi-hook/create-soname-symlinks/soname-symlinks.go

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -142,25 +142,11 @@ func createSonameSymlinksHandler() {
142142
// It is invoked from a reexec'd handler and provides namespace isolation for
143143
// the operations performed by this hook. At the point where this is invoked,
144144
// we are in a new mount namespace that is cloned from the parent.
145-
//
146-
// args[0] is the reexec initializer function name
147-
// args[1] is the path of the ldconfig binary on the host
148-
// args[2] is the container root directory
149-
// The remaining args are directories where soname symlinks need to be created.
150145
func createSonameSymlinks(args []string) error {
151-
if len(args) < 3 {
152-
return fmt.Errorf("incorrect arguments: %v", args)
153-
}
154-
hostLdconfigPath := args[1]
155-
containerRootDirPath := args[2]
156-
157-
ldconfig, err := ldconfig.New(
158-
hostLdconfigPath,
159-
containerRootDirPath,
160-
)
146+
ldconfig, args, err := ldconfig.NewFromArgs(args...)
161147
if err != nil {
162148
return fmt.Errorf("failed to construct ldconfig runner: %w", err)
163149
}
164150

165-
return ldconfig.CreateSonameSymlinks(args[3:]...)
151+
return ldconfig.CreateSonameSymlinks(args...)
166152
}

cmd/nvidia-cdi-hook/update-ldcache/update-ldcache.go

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -140,25 +140,11 @@ func updateLdCacheHandler() {
140140
// It is invoked from a reexec'd handler and provides namespace isolation for
141141
// the operations performed by this hook. At the point where this is invoked,
142142
// we are in a new mount namespace that is cloned from the parent.
143-
//
144-
// args[0] is the reexec initializer function name
145-
// args[1] is the path of the ldconfig binary on the host
146-
// args[2] is the container root directory
147-
// The remaining args are folders where soname symlinks need to be created.
148143
func updateLdCache(args []string) error {
149-
if len(args) < 3 {
150-
return fmt.Errorf("incorrect arguments: %v", args)
151-
}
152-
hostLdconfigPath := args[1]
153-
containerRootDirPath := args[2]
154-
155-
ldconfig, err := ldconfig.New(
156-
hostLdconfigPath,
157-
containerRootDirPath,
158-
)
144+
ldconfig, args, err := ldconfig.NewFromArgs(args...)
159145
if err != nil {
160146
return fmt.Errorf("failed to construct ldconfig runner: %w", err)
161147
}
162148

163-
return ldconfig.UpdateLDCache(args[3:]...)
149+
return ldconfig.UpdateLDCache(args...)
164150
}

internal/ldconfig/ldconfig.go

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ package ldconfig
1919

2020
import (
2121
"fmt"
22+
"log"
2223
"os"
2324
"os/exec"
2425
"path/filepath"
26+
"strconv"
2527
"strings"
2628

2729
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
@@ -39,6 +41,7 @@ const (
3941
type Ldconfig struct {
4042
ldconfigPath string
4143
inRoot string
44+
isRootless bool
4245
}
4346

4447
// NewRunner creates an exec.Cmd that can be used to run ldconfig.
@@ -47,26 +50,59 @@ func NewRunner(id string, ldconfigPath string, containerRoot string, additionala
4750
id,
4851
strings.TrimPrefix(config.NormalizeLDConfigPath("@"+ldconfigPath), "@"),
4952
containerRoot,
53+
fmt.Sprintf("rootless=%v", os.Geteuid() != 0),
5054
}
5155
args = append(args, additionalargs...)
5256

5357
return createReexecCommand(args)
5458
}
5559

56-
// New creates an Ldconfig struct that is used to perform operations on the
57-
// ldcache and libraries in a particular root (e.g. a container).
58-
func New(ldconfigPath string, inRoot string) (*Ldconfig, error) {
59-
l := &Ldconfig{
60-
ldconfigPath: ldconfigPath,
61-
inRoot: inRoot,
62-
}
60+
// NewFromRunnerArgs creates an Ldconfig struct from the args passed to the Cmd
61+
// above.
62+
// This struct is used to perform operations on the ldcache and libraries in a
63+
// particular root (e.g. a container).
64+
//
65+
// args[0] is the reexec initializer function name
66+
// args[1] is the path of the ldconfig binary on the host
67+
// args[2] is the container root directory
68+
// args[3] is the optional flag indicating whether the container is being run rootless.
69+
// The remaining args are folders where soname symlinks need to be created.
70+
func NewFromArgs(args ...string) (*Ldconfig, []string, error) {
71+
// Validate the number of arguments: [program, ldconfigPath, inRoot]
72+
if len(args) < 4 {
73+
return nil, args, fmt.Errorf("incorrect arguments: %v", args)
74+
}
75+
76+
ldconfigPath := args[1]
6377
if ldconfigPath == "" {
64-
return nil, fmt.Errorf("an ldconfig path must be specified")
78+
return nil, args, fmt.Errorf("an ldconfig path must be specified")
6579
}
80+
81+
inRoot := args[2]
6682
if inRoot == "" || inRoot == "/" {
67-
return nil, fmt.Errorf("ldconfig must be run in the non-system root")
83+
return nil, args, fmt.Errorf("ldconfig must be run in the non-system root")
84+
}
85+
86+
isRootless := false
87+
if len(args) >= 4 && strings.HasPrefix(args[3], "rootless=") {
88+
value, err := strconv.ParseBool(strings.TrimPrefix(args[3], "rootless="))
89+
if err != nil {
90+
return nil, args, err
91+
}
92+
isRootless = value
6893
}
69-
return l, nil
94+
95+
remainingArgs := args[3:]
96+
if isRootless {
97+
remainingArgs = args[4:]
98+
}
99+
100+
l := &Ldconfig{
101+
ldconfigPath: ldconfigPath,
102+
inRoot: inRoot,
103+
isRootless: isRootless,
104+
}
105+
return l, remainingArgs, nil
70106
}
71107

72108
// CreateSonameSymlinks uses ldconfig to create the soname symlinks in the
@@ -130,7 +166,10 @@ func (l *Ldconfig) prepareRoot() (string, error) {
130166
// To prevent leaking the parent proc filesystem, we create a new proc mount
131167
// in the specified root.
132168
if err := mountProc(l.inRoot); err != nil {
133-
return "", fmt.Errorf("error mounting /proc: %w", err)
169+
if !l.isRootless {
170+
return "", fmt.Errorf("error mounting /proc: %w", err)
171+
}
172+
log.Printf("Ignoring error for rootless container: %v", err)
134173
}
135174

136175
// We mount the host ldconfig before we pivot root since host paths are not

0 commit comments

Comments
 (0)