@@ -27,6 +27,8 @@ import (
2727 "runtime"
2828 "strings"
2929
30+ "github.com/prometheus/procfs"
31+
3032 "github.com/NVIDIA/nvidia-container-toolkit/internal/config"
3133)
3234
@@ -44,6 +46,7 @@ type Ldconfig struct {
4446 inRoot string
4547 isDebianLikeHost bool
4648 isDebianLikeContainer bool
49+ noPivotRoot bool
4750 directories []string
4851}
4952
@@ -57,6 +60,11 @@ func NewRunner(id string, ldconfigPath string, containerRoot string, additionala
5760 if isDebian () {
5861 args = append (args , "--is-debian-like-host" )
5962 }
63+
64+ if noPivotRoot () {
65+ args = append (args , "--no-pivot" )
66+ }
67+
6068 args = append (args , additionalargs ... )
6169
6270 return createReexecCommand (args )
@@ -76,6 +84,7 @@ func NewRunner(id string, ldconfigPath string, containerRoot string, additionala
7684// The following flags are optional:
7785//
7886// --is-debian-like-host Indicates that the host system is debian-based.
87+ // --no-pivot pivot_root should not be used to provide process isolation.
7988//
8089// The remaining args are folders where soname symlinks need to be created.
8190func NewFromArgs (args ... string ) (* Ldconfig , error ) {
@@ -86,6 +95,7 @@ func NewFromArgs(args ...string) (*Ldconfig, error) {
8695 ldconfigPath := fs .String ("ldconfig-path" , "" , "the path to ldconfig on the host" )
8796 containerRoot := fs .String ("container-root" , "" , "the path in which ldconfig must be run" )
8897 isDebianLikeHost := fs .Bool ("is-debian-like-host" , false , "the hook is running from a Debian-like host" )
98+ noPivot := fs .Bool ("no-pivot" , false , "don't use pivot_root to perform isolation" )
8999 if err := fs .Parse (args [1 :]); err != nil {
90100 return nil , err
91101 }
@@ -101,6 +111,7 @@ func NewFromArgs(args ...string) (*Ldconfig, error) {
101111 ldconfigPath : * ldconfigPath ,
102112 inRoot : * containerRoot ,
103113 isDebianLikeHost : * isDebianLikeHost ,
114+ noPivotRoot : * noPivot ,
104115 directories : fs .Args (),
105116 }
106117 return l , nil
@@ -158,7 +169,7 @@ func (l *Ldconfig) prepareRoot() (string, error) {
158169
159170 // We pivot to the container root for the new process, this further limits
160171 // access to the host.
161- if err := pivotRoot (root . Name () ); err != nil {
172+ if err := l . pivotRoot (root ); err != nil {
162173 return "" , fmt .Errorf ("error running pivot_root: %w" , err )
163174 }
164175
@@ -339,3 +350,50 @@ func debianSystemSearchPaths() []string {
339350
340351 return paths
341352}
353+
354+ func (l * Ldconfig ) pivotRoot (root * os.Root ) error {
355+ rootDir := root .Name ()
356+ // We select the function to pivot the root based on whether pivot_root is
357+ // supported.
358+ // See https://github.com/opencontainers/runc/blob/c3d127f6e8d9f6c06d78b8329cafa8dd39f6236e/libcontainer/rootfs_linux.go#L207-L216
359+ if l .noPivotRoot {
360+ return msMoveRoot (rootDir )
361+ }
362+ return pivotRoot (rootDir )
363+ }
364+
365+ // noPivotRoot checks whether the current root filesystem supports a pivot_root.
366+ // See https://github.com/opencontainers/runc/blob/main/libcontainer/SPEC.md#filesystem
367+ // for a discussion on when this is not the case.
368+ // If we fail to detect whether pivot-root is supported, we assume that it is supported.
369+ // The logic to check for support is adapted from kata-containers:
370+ //
371+ // https://github.com/kata-containers/kata-containers/blob/e7b9eddcede4bbe2edeb9c3af7b2358dc65da76f/src/agent/src/sandbox.rs#L150
372+ //
373+ // and checks whether "/" is mounted as a rootfs.
374+ func noPivotRoot () bool {
375+ rootFsType , err := getRootfsType ("/" )
376+ if err != nil {
377+ return false
378+ }
379+ return rootFsType == "rootfs"
380+ }
381+
382+ func getRootfsType (path string ) (string , error ) {
383+ procSelf , err := procfs .Self ()
384+ if err != nil {
385+ return "" , err
386+ }
387+
388+ mountStats , err := procSelf .MountStats ()
389+ if err != nil {
390+ return "" , err
391+ }
392+
393+ for _ , mountStat := range mountStats {
394+ if mountStat .Mount == path {
395+ return mountStat .Type , nil
396+ }
397+ }
398+ return "" , fmt .Errorf ("mount stats for %q not found" , path )
399+ }
0 commit comments