@@ -982,54 +982,33 @@ func mknodDevice(dest string, node *devices.Device) error {
982982 return os .Chown (dest , int (node .Uid ), int (node .Gid ))
983983}
984984
985- // Get the parent mount point of directory passed in as argument. Also return
986- // optional fields.
987- func getParentMount (rootfs string ) (string , string , error ) {
988- mi , err := mountinfo .GetMounts (mountinfo .ParentsFilter (rootfs ))
989- if err != nil {
990- return "" , "" , err
991- }
992- if len (mi ) < 1 {
993- return "" , "" , fmt .Errorf ("could not find parent mount of %s" , rootfs )
994- }
995-
996- // find the longest mount point
997- var idx , maxlen int
998- for i := range mi {
999- if len (mi [i ].Mountpoint ) > maxlen {
1000- maxlen = len (mi [i ].Mountpoint )
1001- idx = i
985+ // rootfsParentMountPrivate ensures rootfs parent mount is private.
986+ // This is needed for two reasons:
987+ // - pivot_root() will fail if parent mount is shared;
988+ // - when we bind mount rootfs, if its parent is not private, the new mount
989+ // will propagate (leak!) to parent namespace and we don't want that.
990+ func rootfsParentMountPrivate (path string ) error {
991+ var err error
992+ // Assuming path is absolute and clean (this is checked in
993+ // libcontainer/validate). Any error other than EINVAL means we failed,
994+ // and EINVAL means this is not a mount point, so traverse up until we
995+ // find one.
996+ for {
997+ err = unix .Mount ("" , path , "" , unix .MS_PRIVATE , "" )
998+ if err == nil {
999+ return nil
10021000 }
1003- }
1004- return mi [idx ].Mountpoint , mi [idx ].Optional , nil
1005- }
1006-
1007- // Make parent mount private if it was shared
1008- func rootfsParentMountPrivate (rootfs string ) error {
1009- sharedMount := false
1010-
1011- parentMount , optionalOpts , err := getParentMount (rootfs )
1012- if err != nil {
1013- return err
1014- }
1015-
1016- optsSplit := strings .Split (optionalOpts , " " )
1017- for _ , opt := range optsSplit {
1018- if strings .HasPrefix (opt , "shared:" ) {
1019- sharedMount = true
1001+ if err != unix .EINVAL || path == "/" { //nolint:errorlint // unix errors are bare
10201002 break
10211003 }
1004+ path = filepath .Dir (path )
10221005 }
1023-
1024- // Make parent mount PRIVATE if it was shared. It is needed for two
1025- // reasons. First of all pivot_root() will fail if parent mount is
1026- // shared. Secondly when we bind mount rootfs it will propagate to
1027- // parent namespace and we don't want that to happen.
1028- if sharedMount {
1029- return mount ("" , parentMount , "" , unix .MS_PRIVATE , "" )
1006+ return & mountError {
1007+ op : "remount-private" ,
1008+ target : path ,
1009+ flags : unix .MS_PRIVATE ,
1010+ err : err ,
10301011 }
1031-
1032- return nil
10331012}
10341013
10351014func prepareRoot (config * configs.Config ) error {
@@ -1041,9 +1020,6 @@ func prepareRoot(config *configs.Config) error {
10411020 return err
10421021 }
10431022
1044- // Make parent mount private to make sure following bind mount does
1045- // not propagate in other namespaces. Also it will help with kernel
1046- // check pass in pivot_root. (IS_SHARED(new_mnt->mnt_parent))
10471023 if err := rootfsParentMountPrivate (config .Rootfs ); err != nil {
10481024 return err
10491025 }
0 commit comments