コード例 #1
0
 def testFdLeakage(self):
     """Make sure we don't leak any fds."""
     fds_before = os.listdir('/proc/self/fd/')
     lock = locking.PipeLock()
     fds_after = os.listdir('/proc/self/fd/')
     self.assertEqual(len(fds_before), len(fds_after) - 2)
     del lock
     fds_finished = os.listdir('/proc/self/fd/')
     self.assertEqual(fds_before, fds_finished)
コード例 #2
0
 def testSimple(self):
     """Test we can Wait/Post."""
     # If this fails, we'd just hang :).
     with timeout_util.Timeout(30):
         lock = locking.PipeLock()
         lock.Post()
         lock.Post()
         lock.Wait()
         lock.Wait()
         del lock
コード例 #3
0
    def testParallel(self):
        """Test interprocesses actually sync."""
        write_lock = locking.PipeLock()
        read_lock = locking.PipeLock()

        with osutils.TempDir() as tempdir:
            # Let the child create a file, but make sure the parent holds us off.
            # Then make the parent wait for the child to tell us it's done.
            flag_file = os.path.join(tempdir, 'foo')

            pid = os.fork()
            if pid == 0:
                # Child.
                # pylint: disable=protected-access
                try:
                    write_lock.Wait()
                    del write_lock
                    osutils.Touch(flag_file)
                    read_lock.Post()
                    del read_lock
                except Exception:
                    os._exit(1)
                finally:
                    # No matter what happens, we must exit w/out running handlers.
                    os._exit(0)
            else:
                # Parent.
                time.sleep(0.5)
                self.assertNotExists(flag_file)
                write_lock.Post()
                del write_lock
                read_lock.Wait()
                del read_lock
                self.assertExists(flag_file)

                status = os.waitpid(pid, 0)[1]
                self.assertEqual(process_util.GetExitStatus(status), 0)
コード例 #4
0
def CreatePidNs():
    """Start a new pid namespace

  This will launch all the right manager processes.  The child that returns
  will be isolated in a new pid namespace.

  If functionality is not available, then it will return w/out doing anything.

  A note about the processes generated as a result of calling this function:
  You call CreatePidNs() in pid X
  - X launches Pid Y,
    - Pid X will now do nothing but wait for Pid Y to finish and then sys.exit()
      with that return code
    - Y launches Pid Z
      - Pid Y will now do nothing but wait for Pid Z to finish and then
        sys.exit() with that return code
      - **Pid Z returns from CreatePidNs**. So, the caller of this function
        continues in a different process than the one that made the call.
          - All SIGTERM/SIGINT signals are forwarded down from pid X to pid Z to
            handle.
          - SIGKILL will only kill pid X, and leak Pid Y and Z.

  Returns:
    The last pid outside of the namespace. (i.e., pid X)
  """
    first_pid = os.getpid()

    try:
        # First create the namespace.
        Unshare(CLONE_NEWPID)
    except OSError as e:
        if e.errno == errno.EINVAL:
            # For older kernels, or the functionality is disabled in the config,
            # return silently.  We don't want to hard require this stuff.
            return first_pid
        else:
            # For all other errors, abort.  They shouldn't happen.
            raise

    # Used to make sure process groups are in the right state before we try to
    # forward the controlling terminal.
    lock = locking.PipeLock()

    # Now that we're in the new pid namespace, fork.  The parent is the master
    # of it in the original namespace, so it only monitors the child inside it.
    # It is only allowed to fork once too.
    pid = os.fork()
    if pid:
        proctitle.settitle('pid ns', 'external init')

        # We forward termination signals to the child and trust the child to respond
        # sanely. Later, ExitAsStatus propagates the exit status back up.
        _ForwardToChildPid(pid, signal.SIGINT)
        _ForwardToChildPid(pid, signal.SIGTERM)

        # Forward the control of the terminal to the child so it can manage input.
        _SafeTcSetPgrp(sys.stdin.fileno(), pid)

        # Signal our child it can move forward.
        lock.Post()
        del lock

        # Reap the children as the parent of the new namespace.
        process_util.ExitAsStatus(_ReapChildren(pid))
    else:
        # Make sure to unshare the existing mount point if needed.  Some distros
        # create shared mount points everywhere by default.
        try:
            osutils.Mount('none', '/proc', 0,
                          osutils.MS_PRIVATE | osutils.MS_REC)
        except OSError as e:
            if e.errno != errno.EINVAL:
                raise

        # The child needs its own proc mount as it'll be different.
        osutils.Mount(
            'proc', '/proc', 'proc', osutils.MS_NOSUID | osutils.MS_NODEV
            | osutils.MS_NOEXEC | osutils.MS_RELATIME)

        # Wait for our parent to finish initialization.
        lock.Wait()
        del lock

        # Resetup the locks for the next phase.
        lock = locking.PipeLock()

        pid = os.fork()
        if pid:
            proctitle.settitle('pid ns', 'init')

            # We forward termination signals to the child and trust the child to
            # respond sanely. Later, ExitAsStatus propagates the exit status back up.
            _ForwardToChildPid(pid, signal.SIGINT)
            _ForwardToChildPid(pid, signal.SIGTERM)

            # Now that we're in a new pid namespace, start a new process group so that
            # children have something valid to use.  Otherwise getpgrp/etc... will get
            # back 0 which tends to confuse -- you can't setpgrp(0) for example.
            os.setpgrp()

            # Forward the control of the terminal to the child so it can manage input.
            _SafeTcSetPgrp(sys.stdin.fileno(), pid)

            # Signal our child it can move forward.
            lock.Post()
            del lock

            # Watch all of the children.  We need to act as the master inside the
            # namespace and reap old processes.
            process_util.ExitAsStatus(_ReapChildren(pid))

    # Wait for our parent to finish initialization.
    lock.Wait()
    del lock

    # Create a process group for the grandchild so it can manage things
    # independent of the init process.
    os.setpgrp()

    # The grandchild will return and take over the rest of the sdk steps.
    return first_pid
コード例 #5
0
ファイル: cros_sdk.py プロジェクト: zhaozhangpeng/chromium.bb
def _ProxySimSetup(options):
  """Set up proxy simulator, and return only in the child environment.

  TODO: Ideally, this should support multiple concurrent invocations of
  cros_sdk --proxy-sim; currently, such invocations will conflict with each
  other due to the veth device names and IP addresses.  Either this code would
  need to generate fresh, unused names for all of these before forking, or it
  would need to support multiple concurrent cros_sdk invocations sharing one
  proxy and allowing it to exit when unused (without counting on any local
  service-management infrastructure on the host).
  """

  may_need_mpm = False
  apache_bin = osutils.Which('apache2')
  if apache_bin is None:
    apache_bin = osutils.Which('apache2', PROXY_APACHE_FALLBACK_PATH)
    if apache_bin is None:
      _ReportMissing(('apache2',))
  else:
    may_need_mpm = True

  # Module names and .so names included for ease of grepping.
  apache_modules = [('proxy_module', 'mod_proxy.so'),
                    ('proxy_connect_module', 'mod_proxy_connect.so'),
                    ('proxy_http_module', 'mod_proxy_http.so'),
                    ('proxy_ftp_module', 'mod_proxy_ftp.so')]

  # Find the apache module directory, and make sure it has the modules we need.
  module_dirs = {}
  for g in PROXY_APACHE_MODULE_GLOBS:
    for mod, so in apache_modules:
      for f in glob.glob(os.path.join(g, so)):
        module_dirs.setdefault(os.path.dirname(f), []).append(so)
  for apache_module_path, modules_found in module_dirs.iteritems():
    if len(modules_found) == len(apache_modules):
      break
  else:
    # Appease cros lint, which doesn't understand that this else block will not
    # fall through to the subsequent code which relies on apache_module_path.
    apache_module_path = None
    raise SystemExit(
        'Could not find apache module path containing all required modules: %s'
        % ', '.join(so for mod, so in apache_modules))

  def check_add_module(name):
    so = 'mod_%s.so' % name
    if os.access(os.path.join(apache_module_path, so), os.F_OK):
      mod = '%s_module' % name
      apache_modules.append((mod, so))
      return True
    return False

  check_add_module('authz_core')
  if may_need_mpm:
    for mpm in PROXY_APACHE_MPMS:
      if check_add_module('mpm_%s' % mpm):
        break

  veth_host = '%s-host' % PROXY_VETH_PREFIX
  veth_guest = '%s-guest' % PROXY_VETH_PREFIX

  # Set up locks to sync the net namespace setup.  We need the child to create
  # the net ns first, and then have the parent assign the guest end of the veth
  # interface to the child's new network namespace & bring up the proxy.  Only
  # then can the child move forward and rely on the network being up.
  ns_create_lock = locking.PipeLock()
  ns_setup_lock = locking.PipeLock()

  pid = os.fork()
  if not pid:
    # Create our new isolated net namespace.
    namespaces.Unshare(namespaces.CLONE_NEWNET)

    # Signal the parent the ns is ready to be configured.
    ns_create_lock.Post()
    del ns_create_lock

    # Wait for the parent to finish setting up the ns/proxy.
    ns_setup_lock.Wait()
    del ns_setup_lock

    # Set up child side of the network.
    commands = (
        ('ip', 'link', 'set', 'up', 'lo'),
        ('ip', 'address', 'add',
         '%s/%u' % (PROXY_GUEST_IP, PROXY_NETMASK),
         'dev', veth_guest),
        ('ip', 'link', 'set', veth_guest, 'up'),
    )
    try:
      for cmd in commands:
        cros_build_lib.RunCommand(cmd, print_cmd=False)
    except cros_build_lib.RunCommandError:
      raise SystemExit('Running %r failed!' % (cmd,))

    proxy_url = 'http://%s:%u' % (PROXY_HOST_IP, PROXY_PORT)
    for proto in ('http', 'https', 'ftp'):
      os.environ[proto + '_proxy'] = proxy_url
    for v in ('all_proxy', 'RSYNC_PROXY', 'no_proxy'):
      os.environ.pop(v, None)
    return

  # Set up parent side of the network.
  uid = int(os.environ.get('SUDO_UID', '0'))
  gid = int(os.environ.get('SUDO_GID', '0'))
  if uid == 0 or gid == 0:
    for username in PROXY_APACHE_FALLBACK_USERS:
      try:
        pwnam = pwd.getpwnam(username)
        uid, gid = pwnam.pw_uid, pwnam.pw_gid
        break
      except KeyError:
        continue
    if uid == 0 or gid == 0:
      raise SystemExit('Could not find a non-root user to run Apache as')

  chroot_parent, chroot_base = os.path.split(options.chroot)
  pid_file = os.path.join(chroot_parent, '.%s-apache-proxy.pid' % chroot_base)
  log_file = os.path.join(chroot_parent, '.%s-apache-proxy.log' % chroot_base)

  # Wait for the child to create the net ns.
  ns_create_lock.Wait()
  del ns_create_lock

  apache_directives = [
      'User #%u' % uid,
      'Group #%u' % gid,
      'PidFile %s' % pid_file,
      'ErrorLog %s' % log_file,
      'Listen %s:%u' % (PROXY_HOST_IP, PROXY_PORT),
      'ServerName %s' % PROXY_HOST_IP,
      'ProxyRequests On',
      'AllowCONNECT %s' % ' '.join(map(str, PROXY_CONNECT_PORTS)),
  ] + [
      'LoadModule %s %s' % (mod, os.path.join(apache_module_path, so))
      for (mod, so) in apache_modules
  ]
  commands = (
      ('ip', 'link', 'add', 'name', veth_host,
       'type', 'veth', 'peer', 'name', veth_guest),
      ('ip', 'address', 'add',
       '%s/%u' % (PROXY_HOST_IP, PROXY_NETMASK),
       'dev', veth_host),
      ('ip', 'link', 'set', veth_host, 'up'),
      ([apache_bin, '-f', '/dev/null'] +
       [arg for d in apache_directives for arg in ('-C', d)]),
      ('ip', 'link', 'set', veth_guest, 'netns', str(pid)),
  )
  cmd = None # Make cros lint happy.
  try:
    for cmd in commands:
      cros_build_lib.RunCommand(cmd, print_cmd=False)
  except cros_build_lib.RunCommandError:
    # Clean up existing interfaces, if any.
    cmd_cleanup = ('ip', 'link', 'del', veth_host)
    try:
      cros_build_lib.RunCommand(cmd_cleanup, print_cmd=False)
    except cros_build_lib.RunCommandError:
      logging.error('running %r failed', cmd_cleanup)
    raise SystemExit('Running %r failed!' % (cmd,))

  # Signal the child that the net ns/proxy is fully configured now.
  ns_setup_lock.Post()
  del ns_setup_lock

  process_util.ExitAsStatus(os.waitpid(pid, 0)[1])
コード例 #6
0
ファイル: namespaces.py プロジェクト: sjg20/chromite
def CreatePidNs():
    """Start a new pid namespace

  This will launch all the right manager processes.  The child that returns
  will be isolated in a new pid namespace.

  If functionality is not available, then it will return w/out doing anything.

  Returns:
    The last pid outside of the namespace.
  """
    first_pid = os.getpid()

    try:
        # First create the namespace.
        Unshare(CLONE_NEWPID)
    except OSError as e:
        if e.errno == errno.EINVAL:
            # For older kernels, or the functionality is disabled in the config,
            # return silently.  We don't want to hard require this stuff.
            return first_pid
        else:
            # For all other errors, abort.  They shouldn't happen.
            raise

    # Used to make sure process groups are in the right state before we try to
    # forward the controlling terminal.
    lock = locking.PipeLock()

    # Now that we're in the new pid namespace, fork.  The parent is the master
    # of it in the original namespace, so it only monitors the child inside it.
    # It is only allowed to fork once too.
    pid = os.fork()
    if pid:
        proctitle.settitle('pid ns', 'external init')

        # Mask SIGINT with the assumption that the child will catch & process it.
        # We'll pass that back up below.
        signal.signal(signal.SIGINT, signal.SIG_IGN)

        # Forward the control of the terminal to the child so it can manage input.
        _SafeTcSetPgrp(sys.stdin.fileno(), pid)

        # Signal our child it can move forward.
        lock.Post()
        del lock

        # Reap the children as the parent of the new namespace.
        process_util.ExitAsStatus(_ReapChildren(pid))
    else:
        # Make sure to unshare the existing mount point if needed.  Some distros
        # create shared mount points everywhere by default.
        try:
            osutils.Mount('none', '/proc', 0,
                          osutils.MS_PRIVATE | osutils.MS_REC)
        except OSError as e:
            if e.errno != errno.EINVAL:
                raise

        # The child needs its own proc mount as it'll be different.
        osutils.Mount(
            'proc', '/proc', 'proc', osutils.MS_NOSUID | osutils.MS_NODEV
            | osutils.MS_NOEXEC | osutils.MS_RELATIME)

        # Wait for our parent to finish initialization.
        lock.Wait()
        del lock

        # Resetup the locks for the next phase.
        lock = locking.PipeLock()

        pid = os.fork()
        if pid:
            proctitle.settitle('pid ns', 'init')

            # Mask SIGINT with the assumption that the child will catch & process it.
            # We'll pass that back up below.
            signal.signal(signal.SIGINT, signal.SIG_IGN)

            # Now that we're in a new pid namespace, start a new process group so that
            # children have something valid to use.  Otherwise getpgrp/etc... will get
            # back 0 which tends to confuse -- you can't setpgrp(0) for example.
            os.setpgrp()

            # Forward the control of the terminal to the child so it can manage input.
            _SafeTcSetPgrp(sys.stdin.fileno(), pid)

            # Signal our child it can move forward.
            lock.Post()
            del lock

            # Watch all of the children.  We need to act as the master inside the
            # namespace and reap old processes.
            process_util.ExitAsStatus(_ReapChildren(pid))

    # Wait for our parent to finish initialization.
    lock.Wait()
    del lock

    # Create a process group for the grandchild so it can manage things
    # independent of the init process.
    os.setpgrp()

    # The grandchild will return and take over the rest of the sdk steps.
    return first_pid