Mount /proc inside a chroot before provisioning it, to work around #787227

This commit is contained in:
Joey Hess 2015-05-30 10:26:43 -04:00
parent c67691f1aa
commit 95b6d711e7
4 changed files with 24 additions and 5 deletions

1
debian/changelog vendored
View File

@ -11,6 +11,7 @@ propellor (2.5.0) UNRELEASED; urgency=medium
environment variables. environment variables.
* Fix Postfix.satellite bug; the default relayhost was set to the * Fix Postfix.satellite bug; the default relayhost was set to the
domain, not to smtp.domain as documented. domain, not to smtp.domain as documented.
* Mount /proc inside a chroot before provisioning it, to work around #787227
-- Joey Hess <id@joeyh.name> Thu, 07 May 2015 12:08:34 -0400 -- Joey Hess <id@joeyh.name> Thu, 07 May 2015 12:08:34 -0400

View File

@ -16,6 +16,7 @@ import Propellor
import Propellor.Types.CmdLine import Propellor.Types.CmdLine
import Propellor.Types.Chroot import Propellor.Types.Chroot
import Propellor.Property.Chroot.Util import Propellor.Property.Chroot.Util
import Propellor.Property.Mount
import qualified Propellor.Property.Debootstrap as Debootstrap import qualified Propellor.Property.Debootstrap as Debootstrap
import qualified Propellor.Property.Systemd.Core as Systemd import qualified Propellor.Property.Systemd.Core as Systemd
import qualified Propellor.Shim as Shim import qualified Propellor.Shim as Shim
@ -55,8 +56,9 @@ debootstrapped system conf location = case system of
-- | Ensures that the chroot exists and is provisioned according to its -- | Ensures that the chroot exists and is provisioned according to its
-- properties. -- properties.
-- --
-- Reverting this property removes the chroot. Note that it does not ensure -- Reverting this property removes the chroot. Anything mounted inside it
-- that any processes that might be running inside the chroot are stopped. -- is first unmounted. Note that it does not ensure that any processes
-- that might be running inside the chroot are stopped.
provisioned :: Chroot -> RevertableProperty provisioned :: Chroot -> RevertableProperty
provisioned c = provisioned' (propigateChrootInfo c) c False provisioned c = provisioned' (propigateChrootInfo c) c False
@ -101,6 +103,7 @@ propellChroot c@(Chroot loc _ _ _) mkproc systemdonly = property (chrootDesc c "
( pure (Shim.file me d) ( pure (Shim.file me d)
, Shim.setup me Nothing d , Shim.setup me Nothing d
) )
liftIO mountproc
ifM (liftIO $ bindmount shim) ifM (liftIO $ bindmount shim)
( chainprovision shim ( chainprovision shim
, return FailedChange , return FailedChange
@ -117,6 +120,12 @@ propellChroot c@(Chroot loc _ _ _) mkproc systemdonly = property (chrootDesc c "
] ]
) )
-- /proc needs to be mounted in the chroot for the linker to use
-- /proc/self/exe which is necessary for some commands to work
mountproc = unlessM (elem procloc <$> mountPointsBelow loc) $
void $ mount "proc" "proc" procloc
procloc = loc </> "proc"
chainprovision shim = do chainprovision shim = do
parenthost <- asks hostName parenthost <- asks hostName
cmd <- liftIO $ toChain parenthost c systemdonly cmd <- liftIO $ toChain parenthost c systemdonly

View File

@ -106,9 +106,7 @@ unpopulated d = null <$> catchDefaultIO [] (dirContents d)
removetarget :: FilePath -> IO () removetarget :: FilePath -> IO ()
removetarget target = do removetarget target = do
submnts <- filter (\p -> simplifyPath p /= simplifyPath target) submnts <- mountPointsBelow target
. filter (dirContains target)
<$> mountPoints
forM_ submnts umountLazy forM_ submnts umountLazy
removeDirectoryRecursive target removeDirectoryRecursive target

View File

@ -1,22 +1,33 @@
module Propellor.Property.Mount where module Propellor.Property.Mount where
import Propellor import Propellor
import Utility.Path
type FsType = String type FsType = String
type Source = String type Source = String
-- | Lists all mount points of the system.
mountPoints :: IO [FilePath] mountPoints :: IO [FilePath]
mountPoints = lines <$> readProcess "findmnt" ["-rn", "--output", "target"] mountPoints = lines <$> readProcess "findmnt" ["-rn", "--output", "target"]
-- | Finds all filesystems mounted inside the specified directory.
mountPointsBelow :: FilePath -> IO [FilePath]
mountPointsBelow target = filter (\p -> simplifyPath p /= simplifyPath target)
. filter (dirContains target)
<$> mountPoints
-- | Filesystem type mounted at a given location.
getFsType :: FilePath -> IO (Maybe FsType) getFsType :: FilePath -> IO (Maybe FsType)
getFsType mnt = catchDefaultIO Nothing $ getFsType mnt = catchDefaultIO Nothing $
headMaybe . lines headMaybe . lines
<$> readProcess "findmnt" ["-n", mnt, "--output", "fstype"] <$> readProcess "findmnt" ["-n", mnt, "--output", "fstype"]
-- | Unmounts a device, lazily so any running processes don't block it.
umountLazy :: FilePath -> IO () umountLazy :: FilePath -> IO ()
umountLazy mnt = umountLazy mnt =
unlessM (boolSystem "umount" [ Param "-l", Param mnt ]) $ unlessM (boolSystem "umount" [ Param "-l", Param mnt ]) $
errorMessage $ "failed unmounting " ++ mnt errorMessage $ "failed unmounting " ++ mnt
-- | Mounts a device.
mount :: FsType -> Source -> FilePath -> IO Bool mount :: FsType -> Source -> FilePath -> IO Bool
mount fs src mnt = boolSystem "mount" [Param "-t", Param fs, Param src, Param mnt] mount fs src mnt = boolSystem "mount" [Param "-t", Param fs, Param src, Param mnt]