From 7d3d1473510b07962ec04b6449fe18b8ace77c40 Mon Sep 17 00:00:00 2001 From: "Bryn M. Reeves" Date: Wed, 12 Dec 2012 19:06:40 +0000 Subject: Work around non-writable directories in host file systems Distributions that have moved to reduced capabilities and replaced suid and sgid binaries with fscaps have tightened the permissions on several standard system paths. For e.g.: dr-xr-xr-x. 18 root root 4096 Nov 23 19:04 / -rw-r--r--. 1 root root 1174 Dec 11 18:05 /etc/passwd ----------. 1 root root 742 Dec 11 18:05 /etc/shadow dr-xr-x---. 8 root root 4096 Dec 12 19:06 /root Processes that need to write to these paths on the host system must possess cap_dac_override in order to work but in the archive this creates problems when unpacking the archive without this capability. For files this is not a problem since the user only requires write permissions to the containing directory to remove the file. For directories it causes real problems for unprivileged users working with sosreport archives. This includes problems unpacking the archive (since directories are created without write permissions causing subsequent file creation beneath that path to fail) as well as problems cleaning up archives as a typical 'rm -rf' fails to remove these paths. These problems make it impossible to create archives that are both failthful to the host system and easy to work with for typical analysis users. Ultimately this may necessitate dropping permission preservation in the archive and instead storing these (and other information like ACLs and SELinux context) in files within the archive instead). Works around Issue #85 --- sos/utilities.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/sos/utilities.py b/sos/utilities.py index 94298c9e..32e08012 100644 --- a/sos/utilities.py +++ b/sos/utilities.py @@ -228,11 +228,14 @@ class TarFileArchive(Archive): except: return None - def set_tar_info_from_stat(self, tar_info, fstat): + def set_tar_info_from_stat(self, tar_info, fstat, mode=None): tar_info.mtime = fstat.st_mtime tar_info.pax_headers['atime'] = "%.9f" % fstat.st_atime tar_info.pax_headers['ctime'] = "%.9f" % fstat.st_ctime - tar_info.mode = fstat.st_mode + if mode: + tar_info.mode = mode + else: + tar_info.mode = fstat.st_mode tar_info.uid = fstat.st_uid tar_info.gid = fstat.st_gid @@ -240,8 +243,6 @@ class TarFileArchive(Archive): return "%s.%s" % (self._name, self._suffix) def add_parent(self, path): - if (path == '/'): - return path = os.path.split(path)[0] self.add_file(path) @@ -251,6 +252,9 @@ class TarFileArchive(Archive): else: dest = self.prepend(src) + if src != '/': + self.add_parent(src) + tar_info = tarfile.TarInfo(name=dest) if os.path.isdir(src): @@ -262,7 +266,7 @@ class TarFileArchive(Archive): fp.close() tar_info.size = len(content) fileobj = StringIO(content) - fstat = os.stat(src) + # FIXME: handle this at a higher level? if src.startswith("/sys/") or src.startswith ("/proc/"): context = None @@ -270,8 +274,15 @@ class TarFileArchive(Archive): context = self.get_selinux_context(src) if context: tar_info.pax_headers['RHT.security.selinux'] = context - self.set_tar_info_from_stat(tar_info,fstat) - self.add_parent(src) + + fstat = os.stat(src) + if os.path.isdir(src) and not (fstat.st_mode & 000200): + # directories not writable by their owner are a world of pain + # in tar archives. Do not allow them (see Issue #85). + mode = fstat.st_mode | 000200 + else: + mode = None + self.set_tar_info_from_stat(tar_info,fstat, mode) self.tarfile.addfile(tar_info, fileobj) def add_string(self, content, dest): -- cgit