Browse Source

Fixes verification after drop privileges

Ask Solem 11 years ago
parent
commit
a66c832ed3
2 changed files with 25 additions and 7 deletions
  1. 5 4
      celery/platforms.py
  2. 20 3
      celery/tests/utilities/test_platforms.py

+ 5 - 4
celery/platforms.py

@@ -18,6 +18,7 @@ import signal as _signal
 import sys
 
 from billiard import current_process
+from kombu.utils.compat import get_errno
 from kombu.utils.encoding import safe_str
 from contextlib import contextmanager
 
@@ -516,10 +517,10 @@ def maybe_drop_privileges(uid=None, gid=None):
         # ... and make sure privileges cannot be restored:
         try:
             setuid(0)
-        except OSError:
+        except OSError as exc:
             if get_errno(exc) != errno.EPERM:
                 raise
-            pass  # Can not restore privileges.
+            pass  # Good: cannot restore privileges.
         else:
             if uid:
                 raise RuntimeError(
@@ -690,7 +691,7 @@ else:
             '{0}:{1}'.format(progname, current_process().name), info=info)
 
 
-def get_errno(n):
+def get_errno_name(n):
     """Get errno for string, e.g. ``ENOENT``."""
     if isinstance(n, string_t):
         return getattr(errno, n)
@@ -715,7 +716,7 @@ def ignore_errno(*errnos, **kwargs):
                     defaults to :exc:`Exception`.
     """
     types = kwargs.get('types') or (Exception, )
-    errnos = [get_errno(errno) for errno in errnos]
+    errnos = [get_errno_name(errno) for errno in errnos]
     try:
         yield
     except types as exc:

+ 20 - 3
celery/tests/utilities/test_platforms.py

@@ -5,7 +5,7 @@ import os
 import resource
 import signal
 
-from mock import Mock, patch
+from mock import Mock, patch, call
 
 from celery import platforms
 from celery.five import open_fqdn
@@ -123,6 +123,10 @@ if not platforms.IS_WINDOWS:
 
             class pw_struct(object):
                 pw_gid = 50001
+            def raise_on_second_call(*args, **kwargs):
+                setuid.side_effect = OSError()
+                setuid.side_effect.errno = errno.EPERM
+            setuid.side_effect = raise_on_second_call
             getpwuid.return_value = pw_struct()
             parse_uid.return_value = 5001
             maybe_drop_privileges(uid='user')
@@ -130,7 +134,7 @@ if not platforms.IS_WINDOWS:
             getpwuid.assert_called_with(5001)
             setgid.assert_called_with(50001)
             initgroups.assert_called_with(5001, 50001)
-            setuid.assert_called_with(5001)
+            setuid.assert_has_calls([call(5001), call(0)])
 
         @patch('celery.platforms.parse_uid')
         @patch('celery.platforms.parse_gid')
@@ -139,6 +143,11 @@ if not platforms.IS_WINDOWS:
         @patch('celery.platforms.initgroups')
         def test_with_guid(self, initgroups, setuid, setgid,
                            parse_gid, parse_uid):
+
+            def raise_on_second_call(*args, **kwargs):
+                setuid.side_effect = OSError()
+                setuid.side_effect.errno = errno.EPERM
+            setuid.side_effect = raise_on_second_call
             parse_uid.return_value = 5001
             parse_gid.return_value = 50001
             maybe_drop_privileges(uid='user', gid='group')
@@ -146,7 +155,15 @@ if not platforms.IS_WINDOWS:
             parse_gid.assert_called_with('group')
             setgid.assert_called_with(50001)
             initgroups.assert_called_with(5001, 50001)
-            setuid.assert_called_with(5001)
+            setuid.assert_has_calls([call(5001), call(0)])
+
+            setuid.side_effect = None
+            with self.assertRaises(RuntimeError):
+                maybe_drop_privileges(uid='user', gid='group')
+            setuid.side_effect = OSError()
+            setuid.side_effect.errno = errno.EINVAL
+            with self.assertRaises(OSError):
+                maybe_drop_privileges(uid='user', gid='group')
 
         @patch('celery.platforms.setuid')
         @patch('celery.platforms.setgid')