aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBryn M. Reeves <bmr@redhat.com>2012-12-07 00:49:58 +0000
committerBryn M. Reeves <bmr@redhat.com>2012-12-07 01:05:31 +0000
commit179d9bb9868b0a941201566a1774ad648ebde7b5 (patch)
tree6fba233b26e1de59b35f36cf78940893c56184dc
parentf30f0cf83d3056caaaaacd35154ceceb4530a5e8 (diff)
downloadsos-179d9bb9868b0a941201566a1774ad648ebde7b5.tar.gz
Make TarArchive preserve permissions and SELinux context
Make the TarArchive class preserve permissions and SELinux context on all files and directories it collects. This requires us to recursively add the parent directories of any files copied in by full path (or the directory would only be implicitly created and so receive default ownership and permissions and no SELinux context). To make this work, don't call tarfile.add() to recursively add directories - the doCopyFileOrDir machinery in the Plugin class already handles directory recursion properly. Instead when a directory is passed to add_file(), just create a TarInfo record of type tarfile.DIRTYPE and propagate the permissions from the host file system. The SELinux contexts have the unfortunate side-effect of spewing errors if unpacked without --no-selinux as some contexts cannot be placed on some file systems. It may be more useful to eventually store the contexts in the in a file rather than directly in the tarball. Before: drwxr-xr-x. 9 root root 640 Dec 7 00:57 proc lrwxrwxrwx. 1 root root 30 Dec 7 00:57 ps -> sos_commands/process/ps_auxwww drwxr-xr-x. 2 root root 60 Dec 7 00:57 root drwxr-xr-x. 2 root root 80 Dec 7 00:57 sbin After: dr-xr-xr-x. 9 root root 640 Dec 5 19:07 proc lrwxrwxrwx. 1 root root 30 Dec 7 00:58 ps -> sos_commands/process/ps_auxwww dr-xr-x---. 2 root root 60 Dec 7 00:48 root dr-xr-xr-x. 2 root root 80 Dec 7 00:57 sbin More fixes issue #76
-rw-r--r--sos/utilities.py71
1 files changed, 53 insertions, 18 deletions
diff --git a/sos/utilities.py b/sos/utilities.py
index 2180aeb2..4d31b805 100644
--- a/sos/utilities.py
+++ b/sos/utilities.py
@@ -36,6 +36,7 @@ import tarfile
import hashlib
import logging
import fnmatch
+import selinux
from contextlib import closing
try:
@@ -201,39 +202,74 @@ class Archive(object):
self.close()
-
class TarFileArchive(Archive):
def __init__(self, name):
self._name = name
self._suffix = "tar"
- self.tarfile = tarfile.open(self.name(), mode="w")
-
+ self.tarfile = tarfile.open(self.name(),
+ mode="w", format=tarfile.PAX_FORMAT)
+
+ # this can be used to set permissions if using the
+ # tarfile.add() interface to add directory trees.
+ def copy_permissions_filter(self, tar_info):
+ orig_path = tar_info.name[len(os.path.split(self._name)[-1]):]
+ fstat = os.stat(orig_path)
+ context = self.get_selinux_context(orig_path)
+ if(context):
+ tar_info.pax_headers['RHT.security.selinux'] = context
+ self.set_tar_info_from_stat(tar_info,fstat)
+ print "filtering orig_path=%s context=%s" % (orig_path, context)
+ return tar_info
+
+ def get_selinux_context(self, path):
+ try:
+ (rc, c) = selinux.getfilecon(path)
+ return c
+ except:
+ return None
+
+ def set_tar_info_from_stat(self, tar_info, fstat):
+ tar_info.mtime = "%.9f" % 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
+ tar_info.uid = fstat.st_uid
+ tar_info.gid = fstat.st_gid
+
def name(self):
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)
+
def add_file(self, src, dest=None):
if dest:
dest = self.prepend(dest)
else:
dest = self.prepend(src)
+ tar_info = tarfile.TarInfo(name=dest)
+
if os.path.isdir(src):
- self.tarfile.add(src, dest)
+ tar_info.type = tarfile.DIRTYPE
+ fileobj = None
else:
fp = open(src, 'rb')
content = fp.read()
fp.close()
- fstat = os.stat(src)
- tar_info = tarfile.TarInfo(name=dest)
tar_info.size = len(content)
- tar_info.mtime = fstat.st_mtime
- tar_info.pax_headers['atime'] = fstat.st_atime
- tar_info.mode = fstat.st_mode
- tar_info.uid = fstat.st_uid
- tar_info.gid = fstat.st_gid
-
- self.tarfile.addfile(tar_info, StringIO(content))
+ fileobj = StringIO(content)
+ fstat = os.stat(src)
+ 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)
+ self.tarfile.addfile(tar_info, fileobj)
def add_string(self, content, dest):
fstat = None
@@ -243,11 +279,10 @@ class TarFileArchive(Archive):
tar_info = tarfile.TarInfo(name=dest)
tar_info.size = len(content)
if fstat:
- tar_info.mtime = fstat.st_mtime
- tar_info.pax_headers['atime'] = fstat.st_atime
- tar_info.mode = fstat.st_mode
- tar_info.uid = fstat.st_uid
- tar_info.gid = fstat.st_gid
+ context = self.get_selinux_context(dest)
+ if context:
+ tar_info.pax_headers['RHT.security.selinux'] = context
+ self.set_tar_info_from_stat(tar_info, fstat)
else:
tar_info.mtime = time.time()
self.tarfile.addfile(tar_info, StringIO(content))