mock patch proposal: unmount everything mounted under chroot
Mike McLean
mikem at redhat.com
Mon Mar 15 20:13:23 UTC 2010
On 03/15/2010 09:29 AM, Alan Franzoni wrote:
> Hello,
> after getting some errors about unmount in mock, most probably caused
> by binfmt_misc issues - somewhere some package I was building did
> indeed trigger some "automagic" binfmt_misc mount under /proc/sys, I
> decided to patch mock to just unmount *all* directories that have been
> mounted under such chroot, no matter who mounted them or how they got
> mounted.
While I am a fan of extra-paranoid unmounting (as is anyone who has even
run mock clean with an extra mount accidentally left in place), I think
the implementation needs to be more robust.
To go a step further than your suggestion, I would like to see mock's
util.rmtree altered to not cross filesystem boundaries.
Comments on the patch itself inline.
> --- /tmp/backend.py.orig 2010-03-15 12:10:30.000000000 +0100
> +++ /usr/lib/python2.6/site-packages/mock/backend.py 2010-03-15 14:16:38.000000000 +0100
When submitting a patch, it is best to make sure the patch is can be
easily applied by the developers. Your patch references absolute
pathnames which makes applying a hassle. Depending on invocation, patch
might try to apply the change to the system's backend.py instead of the
development copy, or simply fail to find a file to patch.
> @@ -85,14 +85,14 @@
> self.pluginConf[key]['cache_topdir'] = self.cache_topdir
> self.pluginConf[key]['cachedir'] = self.cachedir
> self.pluginConf[key]['root'] = self.sharedRootName
> -
> - # mount/umount
> - self.umountCmds = ['umount -n %s' % self.makeChrootPath('proc'),
> - 'umount -n %s' % self.makeChrootPath('sys')
> - ]
> +
^^^^ trailing whitespace
> + # mount
> self.mountCmds = ['mount -n -t proc mock_chroot_proc %s' % self.makeChrootPath('proc'),
> 'mount -n -t sysfs mock_chroot_sysfs %s' % self.makeChrootPath('sys'),
> ]
> + # retain umountCmds for interfacing sake, but they're not required
> + # anymore
> + self.umountCmds = []
>
> self.build_log_fmt_str = config['build_log_fmt_str']
> self.root_log_fmt_str = config['root_log_fmt_str']
> @@ -340,13 +340,6 @@
>
> os.umask(prevMask)
>
> - # mount/umount
> - for devUnmtCmd in (
> - 'umount -n %s' % self.makeChrootPath('/dev/pts'),
> - 'umount -n %s' % self.makeChrootPath('/dev/shm') ):
> - if devUnmtCmd not in self.umountCmds:
> - self.umountCmds.append(devUnmtCmd)
> -
> mountopt = 'gid=%d,mode=0620,ptmxmode=0666' % grp.getgrnam('tty').gr_gid
> if kver >= '2.6.29':
> mountopt += ',newinstance'
> @@ -587,9 +580,19 @@
> decorate(traceLog())
> def _umountall(self):
> """umount all mounted chroot fs."""
> - for cmd in self.umountCmds:
> - self.root_log.debug(cmd)
> - mock.util.do(cmd, raiseExc=0, shell=True)
> + mountpoints = mock.util.do("cat /proc/mounts", raiseExc=0, shell=True, returnOutput=1)
You're reading /proc/mounts by running cat in a shell, which is a bit
silly when python can just read the file itself.
> + # umount in reverse mount order to prevent nested mount issues that
> + # may prevent clean unmount.
> + for mountline in reversed(mountpoints.split("\n")):
> + try:
> + mountpoint = mountline.split(" ")[1]
> + if self.makeChrootPath("/") in mountpoint:
^^
The test "self.makeChrootPath("/") in mountpoint" is not quite correct.
It could generate false positives (granted this is unlikely), but more
importantly, it could fail to detect a chroot mount when there are
multiple ways to specify it (e.g. with symlinks in use). A more careful
approach would:
- use os.path.realpath() to canonicalize paths before comparing
- retain mount data as a fallback
> + cmd = "umount -n %s" % mountpoint
> + self.root_log.debug(cmd)
> + mock.util.do(cmd, raiseExc=0, shell=True)
> + except:
> + # dont mind about wrong parsing, etc. just go on with the next
> + continue
What are you trying to catch here? You passed raiseExc=0, so the command
is not going to generate an error. What's left? Parsing the line from
/proc/mounts? It looks like the only way that can fail is if
/proc/mounts contains a malformed line. I'm not sure if that can even
happen (and if it does I think it is worth noting instead of ignoring).
Also, unqualified except clauses should be used sparingly, if at all.
>
> decorate(traceLog())
> def _yum(self, cmd, returnOutput=0):
More information about the buildsys
mailing list