From 9e820575ac528d562fc9bd207c8674bfed03589d Mon Sep 17 00:00:00 2001 From: Michael E Brown Date: Thu, 18 Oct 2007 21:39:52 -0500 Subject: completely drop privs (real and effective) when running RPM commands. add a bit of infrastructure to mock.util.do() to handle this. Change mock.util.do to not return output by default. No users use the output, and it can be switched on via karg. --- src/py-libs/backend.py | 48 ++++++++++++++++++++++-------------------------- src/py-libs/util.py | 33 ++++++++++++++++++++++----------- 2 files changed, 44 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/py-libs/backend.py b/src/py-libs/backend.py index 6a190fa..809383d 100644 --- a/src/py-libs/backend.py +++ b/src/py-libs/backend.py @@ -210,6 +210,7 @@ class Root(object): # files in /dev mock.util.rmtree(os.path.join(self.rootdir, "dev")) mock.util.mkdirIfAbsent(os.path.join(self.rootdir, "dev", "pts")) + prevMask = os.umask(0000) os.mknod(os.path.join(self.rootdir, "dev/zero"), stat.S_IFCHR | 0666, os.makedev(1, 5)) os.mknod(os.path.join(self.rootdir, "dev/tty"), stat.S_IFCHR | 0666, os.makedev(5, 0)) os.mknod(os.path.join(self.rootdir, "dev/null"), stat.S_IFCHR | 0666, os.makedev(1, 3)) @@ -219,6 +220,7 @@ class Root(object): os.symlink("/proc/self/fd/0", os.path.join(self.rootdir, "dev/stdin")) os.symlink("/proc/self/fd/1", os.path.join(self.rootdir, "dev/stdout")) os.symlink("/proc/self/fd/2", os.path.join(self.rootdir, "dev/stderr")) + os.umask(prevMask) # set up cache dirs: self._initCache() @@ -292,8 +294,13 @@ class Root(object): srpmBasename = os.path.basename(srpmChrootFilename) # install srpm - env = "HOME=%s" % self.homedir - self.doChroot("rpm -Uvh --nodeps %s" % srpmChrootFilename, env=env) + os.environ["HOME"] = self.homedir + # Completely/Permanently drop privs while running the following: + mock.util.do( + "rpm -Uvh --nodeps %s" % srpmChrootFilename, + chrootPath=self.rootdir, + uidManager=self.uidManager, + ) # rebuild srpm/rpm from SPEC file specs = glob.glob("%s/%s/SPECS/*.spec" % (self.rootdir, self.builddir)) @@ -302,9 +309,13 @@ class Root(object): spec = specs[0] # if there's more than one then someone is an idiot chrootspec = spec.replace(self.rootdir, '') # get rid of rootdir prefix - self.doChroot( + self.root_log.info("about to drop to unpriv mode.") + # Completely/Permanently drop privs while running the following: + mock.util.do( "rpmbuild -bs --target %s --nodeps %s" % (self.target_arch, chrootspec), - env=env, logger=self.build_log, timeout=timeout, output=0 + chrootPath=self.rootdir, + uidManager=self.uidManager, + logger=self.build_log, timeout=timeout, ) rebuiltSrpmFile = glob.glob("%s/%s/SRPMS/*.src.rpm" % (self.rootdir, self.builddir)) @@ -315,28 +326,13 @@ class Root(object): self.installSrpmDeps(rebuiltSrpmFile) #have to permanently drop privs or rpmbuild regains them - # can only do this by forking... self.state("build") - pid = os.fork() - if pid: - # parent - try: - os.waitpid(pid,0) - except: - os.kill(-pid, signal.SIGTERM) - time.sleep(1) - os.kill(-pid, signal.SIGKILL) - - else: - # child - try: - uidManager.dropPrivsForever() - self.doChroot( - "rpmbuild -bb --target %s --nodeps %s" % (self.target_arch, chrootspec), - env=env, logger=self.build_log, timeout=timeout, output=0 - ) - finally: - os._exit(0) + mock.util.do( + "rpmbuild -bb --target %s --nodeps %s" % (self.target_arch, chrootspec), + chrootPath=self.rootdir, + uidManager=self.uidManager, + logger=self.build_log, timeout=timeout, + ) bd_out = self.rootdir + self.builddir rpms = glob.glob(bd_out + '/RPMS/*.rpm') @@ -495,7 +491,7 @@ class Root(object): self.root_log.info(cmd) try: self._callHooks("preyum") - mock.util.do(cmd, output=0) + mock.util.do(cmd) self._callHooks("postyum") except mock.exception.Error, e: self.root_log.exception("Error performing yum command: %s" % cmd) diff --git a/src/py-libs/util.py b/src/py-libs/util.py index 0bca233..868fb41 100644 --- a/src/py-libs/util.py +++ b/src/py-libs/util.py @@ -142,24 +142,19 @@ def uniqReqs(*args): master.extend(l) return rpmUtils.miscutils.unique(master) -@traceLog(log) -def do_interactive(command, *args, **kargs): - # we always assume that we dont care about return code for interactive stuff - os.system(command) - # logger = # output = [1|0] +# chrootPath +# +# Warning: this is the function from hell. :( +# @traceLog(log) -def do(command, timeout=0, raiseExc=True, interactive=0, *args, **kargs): +def do(command, chrootPath=None, timeout=0, raiseExc=True, returnOutput=0, *args, **kargs): """execute given command outside of chroot""" logger = kargs.get("logger", log) logger.debug("Run cmd: %s" % command) - # need to not fork, etc or interactive command wont properly display, so catch it here. - if interactive: - return do_interactive(command, timeout=timeout, raiseExc=raiseExc, *args, **kargs) - class alarmExc(Exception): pass def alarmhandler(signum,stackframe): raise alarmExc("timeout expired") @@ -187,7 +182,7 @@ def do(command, timeout=0, raiseExc=True, interactive=0, *args, **kargs): else: logger.debug(line) - if kargs.get("output",1): + if returnOutput: output += line # close read handle, get child return status, etc @@ -225,6 +220,22 @@ def do(command, timeout=0, raiseExc=True, interactive=0, *args, **kargs): # can kill our children os.setpgrp() + uidManager = kargs.get("uidManager") + + if chrootPath is not None: + if uidManager: + logger.debug("elevate privs to run chroot") + uidManager.becomeUser(0) + os.chdir(chrootPath) + os.chroot(chrootPath) + if uidManager: + logger.debug("back to other privs") + uidManager.restorePrivs() + + if uidManager: + logger.debug("about to drop privs") + uidManager.dropPrivsForever() + child = popen2.Popen4(command) child.tochild.close() -- cgit