def matchPathContext(fn): con = None try: con = selinux.matchpathcon(os.path.normpath(fn), 0)[1] except OSError as e: log.info("failed to get default SELinux context for %s: %s" % (fn, e)) return con
def analyze(self, avc): if not avc.query_environment: return None if avc.tcontext.type in [ "cifs_t", "nfs_t" ]: return None if avc.tcontext.type not in file_types: return None if avc.all_accesses_are_in("relabelto"): return None restorecon_files = {} restorecon_files['dir'] = S_IFDIR restorecon_files['file'] = S_IFREG restorecon_files['lnk_file'] = S_IFLNK restorecon_files['chr_file'] = S_IFCHR restorecon_files['blk_file'] = S_IFBLK if avc.has_tclass_in(restorecon_files.keys()): if avc.tpath is None: return None if avc.tpath == "/": return None if avc.tpath[0] != '/': return None if customizable(avc.tcontext.type): return None try: mcon = selinux.matchpathcon(avc.tpath.strip('"'), restorecon_files[avc.tclass])[1] mcon_type=mcon.split(":")[2] if mcon_type != avc.tcontext.type: return self.report((0, mcon_type)) except OSError, e: pass
def mkpolydir(dir_name, poly_dir_name, level): dir_context = None (rc, context) = selinux.getcon() if rc < 0: raise Exception("Error getting context.") rc = selinux.matchpathcon_init(None) if rc < 0: raise Exception("Error calling matchpathcon_init.") (rc, dir_context) = selinux.matchpathcon(dir_name, 0) selinux.matchpathcon_fini() if rc < 0: raise Exception("Error in matchpathcon for %s." % (dir_name)) (rc, dir_context) = selinux.security_compute_create(context, dir_context, selinux.SECCLASS_FILE) if rc < 0: raise Exception("Error in security_compute_create context: %s directory context: %s" % (context, dir_context)) context_array = dir_context.split(":") context_array[3] = level dir_context = ':'.join(context_array) rc = selinux.setfscreatecon(dir_context) if rc < 0: raise Exception("Error in setfscreatecon for %s %s." % (poly_dir_name, dir_context)) try: if not os.path.isdir(poly_dir_name): os.mkdir(poly_dir_name) except (IOError, OSError), (errno, strerror): raise Exception("Error creating directory %s with context %s: %s %s" % (poly_dir_name, dir_context, errno, strerror))
def mkpolydir(dir_name, poly_dir_name, level): dir_context = None (rc, context) = selinux.getcon() if rc < 0: raise Exception("Error getting context.") rc = selinux.matchpathcon_init(None) if rc < 0: raise Exception("Error calling matchpathcon_init.") (rc, dir_context) = selinux.matchpathcon(dir_name, 0) selinux.matchpathcon_fini() if rc < 0: raise Exception("Error in matchpathcon for %s." % (dir_name)) (rc, dir_context) = selinux.security_compute_create(context, dir_context, selinux.SECCLASS_FILE) if rc < 0: raise Exception( "Error in security_compute_create context: %s directory context: %s" % (context, dir_context)) context_array = dir_context.split(":") context_array[3] = level dir_context = ':'.join(context_array) rc = selinux.setfscreatecon(dir_context) if rc < 0: raise Exception("Error in setfscreatecon for %s %s." % (poly_dir_name, dir_context)) try: if not os.path.isdir(poly_dir_name): os.mkdir(poly_dir_name) except (IOError, OSError), (errno, strerror): raise Exception("Error creating directory %s with context %s: %s %s" % (poly_dir_name, dir_context, errno, strerror))
def analyze(self, avc): if not avc.query_environment: return None if avc.tcontext.type in ["cifs_t", "nfs_t"]: return None if avc.tcontext.type not in file_types: return None if avc.all_accesses_are_in("relabelto"): return None restorecon_files = {} restorecon_files['dir'] = S_IFDIR restorecon_files['file'] = S_IFREG restorecon_files['lnk_file'] = S_IFLNK restorecon_files['chr_file'] = S_IFCHR restorecon_files['blk_file'] = S_IFBLK if avc.has_tclass_in(restorecon_files.keys()): if avc.tpath is None: return None if avc.tpath == "/": return None if avc.tpath[0] != '/': return None if customizable(avc.tcontext.type): return None try: mcon = selinux.matchpathcon(avc.tpath.strip('"'), restorecon_files[avc.tclass])[1] mcon_type = mcon.split(":")[2] if mcon_type != avc.tcontext.type: return self.report((0, mcon_type)) except OSError, e: pass
def restoreSecurityContext_api(path, recursive=False): """ restorecon() wrapper. path - can be a single string or a list returns True if successful or False if there was a problem """ try: logger = TCSLogger.TCSLogger.getInstance(6) except TCSLogger.SingletonException: logger = TCSLogger.TCSLogger.getInstance() if type(path).__name__ == 'str': if os.path.exists(path): contextCurrent = "" notes = "" rpath = os.path.realpath(path) if rpath != path: notes = "(%s)" % rpath myerror = None try: contextCurrent = selinux.getfilecon(rpath)[1] except: pass try: # unfortunately not all RH5 boxes have 'restorecon' as part of the python bindings. Since we never # do this recursively, we'll explicitly do the matchpathcon/lsetfilecon ourselves. mode = os.stat(rpath)[stat.ST_MODE] status, contextRestore = selinux.matchpathcon(rpath, mode) if status == 0: # On the advice of our inhouse SELinux experts, we are intentially disregarding a potential 'user' mismatch # We know that especially for daemon processes in targetted mode we could be either user_u or system_u # depending on how the daemon started. if contextRestore.split(':')[1:] != contextCurrent.split( ':')[1:]: selinux.lsetfilecon(rpath, contextRestore) if notes: msg = """OS Lockdown reset context of '%s' (actually '%s') to '%s'""" % ( path, notes, contextRestore) else: msg = """OS Lockdown reset context of '%s' to '%s'""" % ( path, contextRestore) logger.info(MODULE_NAME, msg) else: myerror = "Unable to get default context for '%s'" % path except OSError, err: myerror = err if myerror != None: logger.error(MODULE_NAME, str(myerror)) return False else: msg = """OS Lockdown trying to restore context of '%s' which does not exist.""" % ( path) logger.warn(MODULE_NAME, msg)
def match_path_context(path): """ Return the default SELinux context for the given path. """ context = None try: context = selinux.matchpathcon(os.path.normpath(path), 0)[1] except OSError as e: log.info("failed to get default SELinux context for %s: %s", path, e) return context
def matchpathcon(path, mode): try: status, context = selinux.matchpathcon(path, mode) except FileNotFoundError as e: if os.path.exists(path): raise LabelNotFoundError(e.errno, "No such label", path) from e else: e.filename = path raise return context
def __restore_label(self, av): import selinux try: context = selinux.matchpathcon(av.obj_path, 0) split = context[1].split(":")[2] if split != av.tgt_type: self.mislabled = split return except OSError: pass self.mislabled = None
def __copy_from_user(self, user_path, profile_path): global has_selinux os.chown(user_path, os.geteuid(), os.getegid()) shutil.move(user_path, profile_path) if has_selinux: if selinux.is_selinux_enabled() > 0: rc, con = selinux.matchpathcon(profile_path, 0) if rc == 0: selinux.setfilecon(profile_path, con) dprint("Moved %s back from %s", user_path, profile_path)
def analyze(self, avc): import commands if avc.has_any_access_in(['execmod']): # MATCH if (commands.getstatusoutput("eu-readelf -d %s | fgrep -q TEXTREL" % avc.tpath)[0] == 1): return self.report(("unsafe")) mcon = selinux.matchpathcon(avc.tpath.strip('"'), S_IFREG)[1] if mcon.split(":")[2] == "lib_t": return self.report() return None
def selinux_default_context(self, path, mode=0): context = self.selinux_initial_context() if not HAVE_SELINUX or not self.selinux_enabled(): return context try: ret = selinux.matchpathcon(self._to_filesystem_str(path), mode) except OSError: return context if ret[0] == -1: return context context = ret[1].split(':') return context
def analyze(self, avc): if not avc.query_environment: return None if avc.spath is None: return None if avc.spath[0] != '/': return None try: mcon = selinux.matchpathcon(avc.spath.strip('"'), S_IFREG) mcon_type=mcon.split(":")[2] if mcon_type != avc.scontext.type: return self.report((0, mcon_type)) except OSError: pass return None
def selinux_default_context(self, path, mode=0): context = self.selinux_initial_context() if not HAVE_SELINUX or not self.selinux_enabled(): return context try: ret = selinux.matchpathcon(self._to_filesystem_str(path), mode) except OSError: return context if ret[0] == -1: return context # Limit split to 4 because the selevel, the last in the list, # may contain ':' characters context = ret[1].split(':', 3) return context
def _verify(self, path): """Verify the selinux context on given path is as expected.""" fn = Pathname(path, prefix=self._prefix) try: mode = os.lstat(fn)[stat.ST_MODE] status, expected = selinux.matchpathcon(path, mode) except OSError: fn = Pathname(os.path.realpath(os.path.expanduser(fn)), prefix=None) try: mode = os.lstat(fn)[stat.ST_MODE] status, expected = selinux.matchpathcon(path, mode) except OSError as e: sys.stderr.write('Verifying "{}" failed with {}\n'.format( path, os.strerror(int(e.errno)))) return False if status != 0: sys.stderr.write('Verifying "{}" failed with {}\n'.format( path, os.strerror(int(status)))) return False try: _, actual = selinux.lgetfilecon(fn) except OSError as e: if e.errno != errno.ENODATA: sys.stderr.write('Verifying "{}" failed with {}\n'.format( path, os.strerror(int(e.errno)))) return False actual = None if expected != actual: sys.stderr.write( "{} incorrect context: actual({}) expected({})\n".format( path, actual, expected)) return False return True
def analyze(self, avc): if not avc.query_environment: return None if avc.spath is None: return None if avc.spath[0] != '/': return None try: mcon = selinux.matchpathcon(avc.spath.strip('"'), S_IFREG)[1] mcon_type = mcon.split(":")[2] gcon = selinux.getfilecon(avc.spath.strip('"'))[1] gcon_type = gcon.split(":")[2] if mcon_type != gcon_type: return self.report((0, mcon_type)) except OSError: pass return None
def __save_as(self, filename = None): global has_selinux """Save the current version to the given filename""" if filename == None: filename = self.file dprint("Saving UserDatabase to %s\n", filename) try: os.rename(filename, filename + ".bak") backup = 1 except: backup = 0 pass try: f = open(filename, 'w') except: if backup == 1: try: os.rename(filename + ".bak", filename) dprint("Restore from %s.bak\n", filename) except: dprint("Failed to restore from %s.bak\n", filename) raise SystemDatabaseException( _("Could not open %s for writing") % filename) try: f.write(self.doc.serialize("UTF-8", format=1)) f.close() except: if backup == 1: try: os.rename(filename + ".bak", filename) dprint("Restore from %s.bak\n", filename) except: dprint("Failed to restore from %s.bak\n", filename) raise SystemDatabaseException( _("Failed to save UserDatabase to %s") % filename) if has_selinux: if selinux.is_selinux_enabled() > 0: rc, con = selinux.matchpathcon(filename, 0) if rc == 0: selinux.setfilecon(filename, con) self.modified = 0
def analyze(self, avc): import subprocess if avc.has_any_access_in(['execmod']): # MATCH # from https://docs.python.org/2.7/library/subprocess.html#replacing-shell-pipeline p1 = subprocess.Popen(['eu-readelf', '-d', avc.tpath], stdout=subprocess.PIPE) p2 = subprocess.Popen(["fgrep", "-q", "TEXTREL"], stdin=p1.stdout, stdout=subprocess.PIPE) p1.stdout.close() # Allow p1 to receive a SIGPIPE if p2 exits. p1.wait() p2.wait() if p2.returncode == 1: return self.report(("unsafe")) mcon = selinux.matchpathcon(avc.tpath.strip('"'), S_IFREG)[1] if mcon.split(":")[2] == "lib_t": return self.report() return None
def matchpathcon(filename, mode): if __enabled < 0: return [None, None] return selinux.matchpathcon(filename, mode)
def _verify_metadata(self, entry, path=None): # pylint: disable=R0912 """ generic method to verify mode, owner, group, secontext, acls, and mtime """ # allow setting an alternate path for recursive permissions checking if path is None: path = entry.get('name') attrib = dict() ondisk, attrib['current_owner'], attrib['current_group'], \ attrib['current_mode'], attrib['current_secontext'] = \ self._gather_data(path)[0:5] if not ondisk: entry.set('current_exists', 'false') return False # we conditionally verify every bit of metadata only if it's # specified on the entry. consequently, canVerify() and # fully_specified() are preconditions of _verify_metadata(), # since they will ensure that everything that needs to be # specified actually is. this lets us gracefully handle # symlink and hardlink entries, which have SELinux contexts # but not other permissions, optional secontext and mtime # attrs, and so on. wanted_owner, wanted_group, wanted_mode, mtime = None, None, None, -1 if entry.get('mtime', '-1') != '-1': mtime = str(ondisk[stat.ST_MTIME]) if entry.get("owner"): wanted_owner = str(self._norm_entry_uid(entry)) if entry.get("group"): wanted_group = str(self._norm_entry_gid(entry)) if entry.get("mode"): while len(entry.get('mode', '')) < 4: entry.set('mode', '0' + entry.get('mode', '')) wanted_mode = int(entry.get('mode'), 8) errors = [] if wanted_owner and attrib['current_owner'] != wanted_owner: errors.append("Owner for path %s is incorrect. " "Current owner is %s but should be %s" % (path, attrib['current_owner'], entry.get('owner'))) if wanted_group and attrib['current_group'] != wanted_group: errors.append("Group for path %s is incorrect. " "Current group is %s but should be %s" % (path, attrib['current_group'], entry.get('group'))) if (wanted_mode and oct_mode(int(attrib['current_mode'], 8)) != oct_mode(wanted_mode)): errors.append("Permissions for path %s are incorrect. " "Current permissions are %s but should be %s" % (path, attrib['current_mode'], entry.get('mode'))) if entry.get('mtime'): attrib['current_mtime'] = mtime if mtime != entry.get('mtime', '-1'): errors.append("mtime for path %s is incorrect. " "Current mtime is %s but should be %s" % (path, mtime, entry.get('mtime'))) if HAS_SELINUX: wanted_secontext = None if entry.get("secontext") == "__default__": try: wanted_secontext = \ selinux.matchpathcon( path, ondisk[stat.ST_MODE])[1].split(":")[2] except OSError: errors.append("%s has no default SELinux context" % entry.get("name")) elif entry.get("secontext"): wanted_secontext = entry.get("secontext").split(":")[2] if (wanted_secontext and attrib['current_secontext'] != wanted_secontext): errors.append("SELinux context for path %s is incorrect. " "Current context is %s but should be %s" % (path, attrib['current_secontext'], wanted_secontext)) if errors: for error in errors: self.logger.debug("POSIX: " + error) entry.set('qtext', "\n".join([entry.get('qtext', '')] + errors)) if path == entry.get("name"): for attr, val in attrib.items(): if val is not None: entry.set(attr, str(val)) return self._verify_acls(entry, path=path) and len(errors) == 0
from ..errors import * from . import DeviceFormat, register_device_format from pyanaconda import iutil from pyanaconda.flags import flags from parted import fileSystemType from pyanaconda.anaconda_log import log_method_call import logging log = logging.getLogger("storage") import gettext _ = lambda x: gettext.ldgettext("anaconda", x) try: lost_and_found_context = selinux.matchpathcon("/lost+found", 0)[1] except OSError: lost_and_found_context = None fs_configs = {} def get_kernel_filesystems(): fs_list = [] for line in open("/proc/filesystems").readlines(): fs_list.append(line.split()[-1]) return fs_list global kernel_filesystems kernel_filesystems = get_kernel_filesystems()
def _verify_metadata(self, entry, path=None): # pylint: disable=R0912 """ generic method to verify mode, owner, group, secontext, acls, and mtime """ # allow setting an alternate path for recursive permissions checking if path is None: path = entry.get('name') attrib = dict() ondisk, attrib['current_owner'], attrib['current_group'], \ attrib['current_mode'], attrib['current_secontext'] = \ self._gather_data(path)[0:5] if not ondisk: entry.set('current_exists', 'false') return False # we conditionally verify every bit of metadata only if it's # specified on the entry. consequently, canVerify() and # fully_specified() are preconditions of _verify_metadata(), # since they will ensure that everything that needs to be # specified actually is. this lets us gracefully handle # symlink and hardlink entries, which have SELinux contexts # but not other permissions, optional secontext and mtime # attrs, and so on. wanted_owner, wanted_group, wanted_mode, mtime = None, None, None, -1 if entry.get('mtime', '-1') != '-1': mtime = str(ondisk[stat.ST_MTIME]) if entry.get("owner"): wanted_owner = str(self._norm_entry_uid(entry)) if entry.get("group"): wanted_group = str(self._norm_entry_gid(entry)) if entry.get("mode"): while len(entry.get('mode', '')) < 4: entry.set('mode', '0' + entry.get('mode', '')) wanted_mode = int(entry.get('mode'), 8) errors = [] if wanted_owner and attrib['current_owner'] != wanted_owner: errors.append("Owner for path %s is incorrect. " "Current owner is %s but should be %s" % (path, attrib['current_owner'], entry.get('owner'))) if wanted_group and attrib['current_group'] != wanted_group: errors.append("Group for path %s is incorrect. " "Current group is %s but should be %s" % (path, attrib['current_group'], entry.get('group'))) if (wanted_mode and oct_mode(int(attrib['current_mode'], 8)) != oct_mode(wanted_mode)): errors.append("Permissions for path %s are incorrect. " "Current permissions are %s but should be %s" % (path, attrib['current_mode'], entry.get('mode'))) if entry.get('mtime'): attrib['current_mtime'] = mtime if mtime != entry.get('mtime', '-1'): errors.append("mtime for path %s is incorrect. " "Current mtime is %s but should be %s" % (path, mtime, entry.get('mtime'))) if HAS_SELINUX: wanted_secontext = None if entry.get("secontext") == "__default__": try: wanted_secontext = \ selinux.matchpathcon( path, ondisk[stat.ST_MODE])[1].split(":")[2] except OSError: errors.append("%s has no default SELinux context" % entry.get("name")) else: wanted_secontext = entry.get("secontext") if (wanted_secontext and attrib['current_secontext'] != wanted_secontext): errors.append("SELinux context for path %s is incorrect. " "Current context is %s but should be %s" % (path, attrib['current_secontext'], wanted_secontext)) if errors: for error in errors: self.logger.debug("POSIX: " + error) entry.set('qtext', "\n".join([entry.get('qtext', '')] + errors)) if path == entry.get("name"): for attr, val in attrib.items(): if val is not None: entry.set(attr, str(val)) return self._verify_acls(entry, path=path) and len(errors) == 0
from ..errors import * from . import DeviceFormat, register_device_format import iutil from flags import flags from parted import fileSystemType from ..storage_log import log_method_call import logging log = logging.getLogger("storage") import gettext _ = lambda x: gettext.ldgettext("anaconda", x) try: lost_and_found_context = selinux.matchpathcon("/lost+found", 0)[1] except OSError: lost_and_found_context = None fs_configs = {} def get_kernel_filesystems(): fs_list = [] for line in open("/proc/filesystems").readlines(): fs_list.append(line.split()[-1]) return fs_list global kernel_filesystems kernel_filesystems = get_kernel_filesystems() def fsConfigFromFile(config_file):