diff options
author | Bryn M. Reeves <bmr@redhat.com> | 2012-12-07 00:49:58 +0000 |
---|---|---|
committer | Bryn M. Reeves <bmr@redhat.com> | 2012-12-07 01:05:31 +0000 |
commit | 179d9bb9868b0a941201566a1774ad648ebde7b5 (patch) | |
tree | 6fba233b26e1de59b35f36cf78940893c56184dc | |
parent | f30f0cf83d3056caaaaacd35154ceceb4530a5e8 (diff) | |
download | sos-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.py | 71 |
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)) |