@@ -308,7 +308,11 @@ func mountCgroupV1(m *configs.Mount, c *mountConfig) error {
308308
309309	for  _ , b  :=  range  binds  {
310310		if  c .cgroupns  {
311+ 			// We just created the tmpfs, and so we can just use filepath.Join 
312+ 			// here (not to mention we want to make sure we create the path 
313+ 			// inside the tmpfs, so we don't want to resolve symlinks). 
311314			subsystemPath  :=  filepath .Join (c .root , b .Destination )
315+ 			subsystemName  :=  filepath .Base (b .Destination )
312316			if  err  :=  os .MkdirAll (subsystemPath , 0o755 ); err  !=  nil  {
313317				return  err 
314318			}
@@ -319,7 +323,7 @@ func mountCgroupV1(m *configs.Mount, c *mountConfig) error {
319323				}
320324				var  (
321325					source  =  "cgroup" 
322- 					data    =  filepath . Base ( subsystemPath ) 
326+ 					data    =  subsystemName 
323327				)
324328				if  data  ==  "systemd"  {
325329					data  =  cgroups .CgroupNamePrefix  +  data 
@@ -349,14 +353,7 @@ func mountCgroupV1(m *configs.Mount, c *mountConfig) error {
349353}
350354
351355func  mountCgroupV2 (m  * configs.Mount , c  * mountConfig ) error  {
352- 	dest , err  :=  securejoin .SecureJoin (c .root , m .Destination )
353- 	if  err  !=  nil  {
354- 		return  err 
355- 	}
356- 	if  err  :=  os .MkdirAll (dest , 0o755 ); err  !=  nil  {
357- 		return  err 
358- 	}
359- 	err  =  utils .WithProcfd (c .root , m .Destination , func (dstFd  string ) error  {
356+ 	err  :=  utils .WithProcfd (c .root , m .Destination , func (dstFd  string ) error  {
360357		return  mountViaFds (m .Source , nil , m .Destination , dstFd , "cgroup2" , uintptr (m .Flags ), m .Data )
361358	})
362359	if  err  ==  nil  ||  ! (errors .Is (err , unix .EPERM ) ||  errors .Is (err , unix .EBUSY )) {
@@ -482,6 +479,65 @@ func statfsToMountFlags(st unix.Statfs_t) int {
482479	return  flags 
483480}
484481
482+ var  errRootfsToFile  =  errors .New ("config tries to change rootfs to file" )
483+ 
484+ func  createMountpoint (rootfs  string , m  mountEntry ) (string , error ) {
485+ 	dest , err  :=  securejoin .SecureJoin (rootfs , m .Destination )
486+ 	if  err  !=  nil  {
487+ 		return  "" , err 
488+ 	}
489+ 	if  err  :=  checkProcMount (rootfs , dest , m ); err  !=  nil  {
490+ 		return  "" , fmt .Errorf ("check proc-safety of %s mount: %w" , m .Destination , err )
491+ 	}
492+ 
493+ 	switch  m .Device  {
494+ 	case  "bind" :
495+ 		fi , _ , err  :=  m .srcStat ()
496+ 		if  err  !=  nil  {
497+ 			// Error out if the source of a bind mount does not exist as we 
498+ 			// will be unable to bind anything to it. 
499+ 			return  "" , err 
500+ 		}
501+ 		// If the original source is not a directory, make the target a file. 
502+ 		if  ! fi .IsDir () {
503+ 			// Make sure we aren't tricked into trying to make the root a file. 
504+ 			if  rootfs  ==  dest  {
505+ 				return  "" , fmt .Errorf ("%w: file bind mount over rootfs" , errRootfsToFile )
506+ 			}
507+ 			// Make the parent directory. 
508+ 			if  err  :=  os .MkdirAll (filepath .Dir (dest ), 0o755 ); err  !=  nil  {
509+ 				return  "" , fmt .Errorf ("make parent dir of file bind-mount: %w" , err )
510+ 			}
511+ 			// Make the target file. 
512+ 			f , err  :=  os .OpenFile (dest , os .O_CREATE , 0o755 )
513+ 			if  err  !=  nil  {
514+ 				return  "" , fmt .Errorf ("create target of file bind-mount: %w" , err )
515+ 			}
516+ 			_  =  f .Close ()
517+ 			// Nothing left to do. 
518+ 			return  dest , nil 
519+ 		}
520+ 
521+ 	case  "tmpfs" :
522+ 		// If the original target exists, copy the mode for the tmpfs mount. 
523+ 		if  stat , err  :=  os .Stat (dest ); err  ==  nil  {
524+ 			dt  :=  fmt .Sprintf ("mode=%04o" , syscallMode (stat .Mode ()))
525+ 			if  m .Data  !=  ""  {
526+ 				dt  =  dt  +  ","  +  m .Data 
527+ 			}
528+ 			m .Data  =  dt 
529+ 
530+ 			// Nothing left to do. 
531+ 			return  dest , nil 
532+ 		}
533+ 	}
534+ 
535+ 	if  err  :=  os .MkdirAll (dest , 0o755 ); err  !=  nil  {
536+ 		return  "" , err 
537+ 	}
538+ 	return  dest , nil 
539+ }
540+ 
485541func  mountToRootfs (c  * mountConfig , m  mountEntry ) error  {
486542	rootfs  :=  c .root 
487543
@@ -495,7 +551,7 @@ func mountToRootfs(c *mountConfig, m mountEntry) error {
495551		// TODO: This won't be necessary once we switch to libpathrs and we can 
496552		//       stop all of these symlink-exchange attacks. 
497553		dest  :=  filepath .Clean (m .Destination )
498- 		if  ! strings . HasPrefix ( dest ,  rootfs ) {
554+ 		if  ! utils . IsLexicallyInRoot ( rootfs ,  dest ) {
499555			// Do not use securejoin as it resolves symlinks. 
500556			dest  =  filepath .Join (rootfs , dest )
501557		}
@@ -516,37 +572,19 @@ func mountToRootfs(c *mountConfig, m mountEntry) error {
516572		return  mountPropagate (m , rootfs , "" )
517573	}
518574
519- 	mountLabel  :=  c .label 
520- 	dest , err  :=  securejoin .SecureJoin (rootfs , m .Destination )
575+ 	dest , err  :=  createMountpoint (rootfs , m )
521576	if  err  !=  nil  {
522- 		return  err 
523- 	}
524- 	if  err  :=  checkProcMount (rootfs , dest , m ); err  !=  nil  {
525- 		return  err 
577+ 		return  fmt .Errorf ("create mountpoint for %s mount: %w" , m .Destination , err )
526578	}
579+ 	mountLabel  :=  c .label 
527580
528581	switch  m .Device  {
529582	case  "mqueue" :
530- 		if  err  :=  os .MkdirAll (dest , 0o755 ); err  !=  nil  {
531- 			return  err 
532- 		}
533583		if  err  :=  mountPropagate (m , rootfs , "" ); err  !=  nil  {
534584			return  err 
535585		}
536586		return  label .SetFileLabel (dest , mountLabel )
537587	case  "tmpfs" :
538- 		if  stat , err  :=  os .Stat (dest ); err  !=  nil  {
539- 			if  err  :=  os .MkdirAll (dest , 0o755 ); err  !=  nil  {
540- 				return  err 
541- 			}
542- 		} else  {
543- 			dt  :=  fmt .Sprintf ("mode=%04o" , syscallMode (stat .Mode ()))
544- 			if  m .Data  !=  ""  {
545- 				dt  =  dt  +  ","  +  m .Data 
546- 			}
547- 			m .Data  =  dt 
548- 		}
549- 
550588		if  m .Extensions & configs .EXT_COPYUP  ==  configs .EXT_COPYUP  {
551589			err  =  doTmpfsCopyUp (m , rootfs , mountLabel )
552590		} else  {
@@ -555,15 +593,6 @@ func mountToRootfs(c *mountConfig, m mountEntry) error {
555593
556594		return  err 
557595	case  "bind" :
558- 		fi , _ , err  :=  m .srcStat ()
559- 		if  err  !=  nil  {
560- 			// error out if the source of a bind mount does not exist as we will be 
561- 			// unable to bind anything to it. 
562- 			return  err 
563- 		}
564- 		if  err  :=  createIfNotExists (dest , fi .IsDir ()); err  !=  nil  {
565- 			return  err 
566- 		}
567596		// open_tree()-related shenanigans are all handled in mountViaFds. 
568597		if  err  :=  mountPropagate (m , rootfs , mountLabel ); err  !=  nil  {
569598			return  err 
@@ -679,9 +708,6 @@ func mountToRootfs(c *mountConfig, m mountEntry) error {
679708		}
680709		return  mountCgroupV1 (m .Mount , c )
681710	default :
682- 		if  err  :=  os .MkdirAll (dest , 0o755 ); err  !=  nil  {
683- 			return  err 
684- 		}
685711		return  mountPropagate (m , rootfs , mountLabel )
686712	}
687713}
@@ -899,6 +925,9 @@ func createDeviceNode(rootfs string, node *devices.Device, bind bool) error {
899925	if  err  !=  nil  {
900926		return  err 
901927	}
928+ 	if  dest  ==  rootfs  {
929+ 		return  fmt .Errorf ("%w: mknod over rootfs" , errRootfsToFile )
930+ 	}
902931	if  err  :=  os .MkdirAll (filepath .Dir (dest ), 0o755 ); err  !=  nil  {
903932		return  err 
904933	}
@@ -1169,26 +1198,6 @@ func chroot() error {
11691198	return  nil 
11701199}
11711200
1172- // createIfNotExists creates a file or a directory only if it does not already exist. 
1173- func  createIfNotExists (path  string , isDir  bool ) error  {
1174- 	if  _ , err  :=  os .Stat (path ); err  !=  nil  {
1175- 		if  os .IsNotExist (err ) {
1176- 			if  isDir  {
1177- 				return  os .MkdirAll (path , 0o755 )
1178- 			}
1179- 			if  err  :=  os .MkdirAll (filepath .Dir (path ), 0o755 ); err  !=  nil  {
1180- 				return  err 
1181- 			}
1182- 			f , err  :=  os .OpenFile (path , os .O_CREATE , 0o755 )
1183- 			if  err  !=  nil  {
1184- 				return  err 
1185- 			}
1186- 			_  =  f .Close ()
1187- 		}
1188- 	}
1189- 	return  nil 
1190- }
1191- 
11921201// readonlyPath will make a path read only. 
11931202func  readonlyPath (path  string ) error  {
11941203	if  err  :=  mount (path , path , "" , unix .MS_BIND | unix .MS_REC , "" ); err  !=  nil  {
0 commit comments