Esempio n. 1
0
void
SandboxChroot::ThreadMain()
{
  // First, drop everything that isn't CAP_SYS_CHROOT.  (This code
  // assumes that this thread already has effective CAP_SYS_CHROOT,
  // because Prepare() checked for it before creating this thread.)
  LinuxCapabilities caps;
  caps.Effective(CAP_SYS_CHROOT) = true;
  if (!caps.SetCurrent()) {
    SANDBOX_LOG_ERROR("capset: %s", strerror(errno));
    MOZ_CRASH("Can't limit chroot thread's capabilities");
  }

  MOZ_ALWAYS_ZERO(pthread_mutex_lock(&mMutex));
  MOZ_ASSERT(mCommand == NO_THREAD);
  mCommand = NO_COMMAND;
  MOZ_ALWAYS_ZERO(pthread_cond_signal(&mWakeup));
  while (mCommand == NO_COMMAND) {
    MOZ_ALWAYS_ZERO(pthread_cond_wait(&mWakeup, &mMutex));
  }
  if (mCommand == DO_CHROOT) {
    MOZ_ASSERT(mFd >= 0);
    if (!ChrootToFileDesc(mFd)) {
      MOZ_CRASH("Failed to chroot");
    }
  } else {
    MOZ_ASSERT(mCommand == JUST_EXIT);
  }
  if (mFd >= 0) {
    AlwaysClose(mFd);
    mFd = -1;
  }
  mCommand = NO_THREAD;
  MOZ_ALWAYS_ZERO(pthread_mutex_unlock(&mMutex));
  // Drop the remaining capabilities; see note in SandboxChroot.h
  // about the potential unreliability of pthread_join.
  if (!LinuxCapabilities().SetCurrent()) {
    MOZ_CRASH("can't drop capabilities");
  }
}
Esempio n. 2
0
void
SandboxEarlyInit(GeckoProcessType aType, bool aIsNuwa)
{
    // Bug 1168555: Nuwa isn't reliably single-threaded at this point;
    // it starts an IPC I/O thread and then shuts it down before calling
    // the plugin-container entry point, but that thread may not have
    // finished exiting.  If/when any type of sandboxing is used for the
    // Nuwa process (e.g., unsharing the network namespace there instead
    // of for each content process, to save memory), this will need to be
    // changed by moving the SandboxEarlyInit call to an earlier point.
    if (aIsNuwa) {
        return;
    }

    MOZ_RELEASE_ASSERT(IsSingleThreaded());
    const SandboxInfo info = SandboxInfo::Get();

    // Which kinds of resource isolation (of those that need to be set
    // up at this point) can be used by this process?
    bool canChroot = false;
    bool canUnshareNet = false;
    bool canUnshareIPC = false;

    switch (aType) {
    case GeckoProcessType_Default:
        MOZ_ASSERT(false, "SandboxEarlyInit in parent process");
        return;
#ifdef MOZ_GMP_SANDBOX
    case GeckoProcessType_GMPlugin:
        if (!info.Test(SandboxInfo::kEnabledForMedia)) {
            break;
        }
        canUnshareNet = true;
        canUnshareIPC = true;
        // Need seccomp-bpf to intercept open().
        canChroot = info.Test(SandboxInfo::kHasSeccompBPF);
        break;
#endif
    // In the future, content processes will be able to use some of
    // these.
    default:
        // Other cases intentionally left blank.
        break;
    }

    // If there's nothing to do, then we're done.
    if (!canChroot && !canUnshareNet && !canUnshareIPC) {
        return;
    }

    {
        LinuxCapabilities existingCaps;
        if (existingCaps.GetCurrent() && existingCaps.AnyEffective()) {
            SANDBOX_LOG_ERROR("PLEASE DO NOT RUN THIS AS ROOT.  Strange things may"
                              " happen when capabilities are dropped.");
        }
    }

    // If capabilities can't be gained, then nothing can be done.
    if (!info.Test(SandboxInfo::kHasUserNamespaces)) {
        // Drop any existing capabilities; unsharing the user namespace
        // would implicitly drop them, so if we're running in a broken
        // configuration where that would matter (e.g., running as root
        // from a non-root-owned mode-0700 directory) this means it will
        // break the same way on all kernels and be easier to troubleshoot.
        LinuxCapabilities().SetCurrent();
        return;
    }

    // The failure cases for the various unshares, and setting up the
    // chroot helper, don't strictly need to be fatal -- but they also
    // shouldn't fail on any reasonable system, so let's take the small
    // risk of breakage over the small risk of quietly providing less
    // security than we expect.  (Unlike in SandboxInfo, this is in the
    // child process, so crashing here isn't as severe a response to the
    // unexpected.)
    if (!UnshareUserNamespace()) {
        SANDBOX_LOG_ERROR("unshare(CLONE_NEWUSER): %s", strerror(errno));
        // If CanCreateUserNamespace (SandboxInfo.cpp) returns true, then
        // the unshare shouldn't have failed.
        MOZ_CRASH("unshare(CLONE_NEWUSER)");
    }
    // No early returns after this point!  We need to drop the
    // capabilities that were gained by unsharing the user namesapce.

    if (canUnshareIPC && syscall(__NR_unshare, CLONE_NEWIPC) != 0) {
        SANDBOX_LOG_ERROR("unshare(CLONE_NEWIPC): %s", strerror(errno));
        MOZ_CRASH("unshare(CLONE_NEWIPC)");
    }

    if (canUnshareNet && syscall(__NR_unshare, CLONE_NEWNET) != 0) {
        SANDBOX_LOG_ERROR("unshare(CLONE_NEWNET): %s", strerror(errno));
        MOZ_CRASH("unshare(CLONE_NEWNET)");
    }

    if (canChroot) {
        gChrootHelper = MakeUnique<SandboxChroot>();
        if (!gChrootHelper->Prepare()) {
            SANDBOX_LOG_ERROR("failed to set up chroot helper");
            MOZ_CRASH("SandboxChroot::Prepare");
        }
    }

    if (!LinuxCapabilities().SetCurrent()) {
        SANDBOX_LOG_ERROR("dropping capabilities: %s", strerror(errno));
        MOZ_CRASH("can't drop capabilities");
    }
}
Esempio n. 3
0
void
SandboxEarlyInit(GeckoProcessType aType)
{
  const SandboxInfo info = SandboxInfo::Get();
  if (info.Test(SandboxInfo::kUnexpectedThreads)) {
    return;
  }
  MOZ_RELEASE_ASSERT(IsSingleThreaded());

  // Which kinds of resource isolation (of those that need to be set
  // up at this point) can be used by this process?
  bool canChroot = false;
  bool canUnshareNet = false;
  bool canUnshareIPC = false;

  switch (aType) {
  case GeckoProcessType_Default:
    MOZ_ASSERT(false, "SandboxEarlyInit in parent process");
    return;
#ifdef MOZ_GMP_SANDBOX
  case GeckoProcessType_GMPlugin:
    if (!info.Test(SandboxInfo::kEnabledForMedia)) {
      break;
    }
    canUnshareNet = true;
    canUnshareIPC = true;
    // Need seccomp-bpf to intercept open().
    canChroot = info.Test(SandboxInfo::kHasSeccompBPF);
    break;
#endif
    // In the future, content processes will be able to use some of
    // these.
  default:
    // Other cases intentionally left blank.
    break;
  }

  // If TSYNC is not supported, set up signal handler
  // used to enable seccomp on each thread.
  if (!info.Test(SandboxInfo::kHasSeccompTSync)) {
    gSeccompTsyncBroadcastSignum = FindFreeSignalNumber();
    if (gSeccompTsyncBroadcastSignum == 0) {
      SANDBOX_LOG_ERROR("No available signal numbers!");
      MOZ_CRASH();
    }

    void (*oldHandler)(int);
    oldHandler = signal(gSeccompTsyncBroadcastSignum, SetThreadSandboxHandler);
    if (oldHandler != SIG_DFL) {
      // See the comment on FindFreeSignalNumber about race conditions.
      SANDBOX_LOG_ERROR("signal %d in use by handler %p!\n",
        gSeccompTsyncBroadcastSignum, oldHandler);
      MOZ_CRASH();
    }
  }

  // If there's nothing to do, then we're done.
  if (!canChroot && !canUnshareNet && !canUnshareIPC) {
    return;
  }

  {
    LinuxCapabilities existingCaps;
    if (existingCaps.GetCurrent() && existingCaps.AnyEffective()) {
      SANDBOX_LOG_ERROR("PLEASE DO NOT RUN THIS AS ROOT.  Strange things may"
                        " happen when capabilities are dropped.");
    }
  }

  // If capabilities can't be gained, then nothing can be done.
  if (!info.Test(SandboxInfo::kHasUserNamespaces)) {
    // Drop any existing capabilities; unsharing the user namespace
    // would implicitly drop them, so if we're running in a broken
    // configuration where that would matter (e.g., running as root
    // from a non-root-owned mode-0700 directory) this means it will
    // break the same way on all kernels and be easier to troubleshoot.
    LinuxCapabilities().SetCurrent();
    return;
  }

  // The failure cases for the various unshares, and setting up the
  // chroot helper, don't strictly need to be fatal -- but they also
  // shouldn't fail on any reasonable system, so let's take the small
  // risk of breakage over the small risk of quietly providing less
  // security than we expect.  (Unlike in SandboxInfo, this is in the
  // child process, so crashing here isn't as severe a response to the
  // unexpected.)
  if (!UnshareUserNamespace()) {
    SANDBOX_LOG_ERROR("unshare(CLONE_NEWUSER): %s", strerror(errno));
    // If CanCreateUserNamespace (SandboxInfo.cpp) returns true, then
    // the unshare shouldn't have failed.
    MOZ_CRASH("unshare(CLONE_NEWUSER)");
  }
  // No early returns after this point!  We need to drop the
  // capabilities that were gained by unsharing the user namesapce.

  if (canUnshareIPC && syscall(__NR_unshare, CLONE_NEWIPC) != 0) {
    SANDBOX_LOG_ERROR("unshare(CLONE_NEWIPC): %s", strerror(errno));
    MOZ_CRASH("unshare(CLONE_NEWIPC)");
  }

  if (canUnshareNet && syscall(__NR_unshare, CLONE_NEWNET) != 0) {
    SANDBOX_LOG_ERROR("unshare(CLONE_NEWNET): %s", strerror(errno));
    MOZ_CRASH("unshare(CLONE_NEWNET)");
  }

  if (canChroot) {
    gChrootHelper = MakeUnique<SandboxChroot>();
    if (!gChrootHelper->Prepare()) {
      SANDBOX_LOG_ERROR("failed to set up chroot helper");
      MOZ_CRASH("SandboxChroot::Prepare");
    }
  }

  if (!LinuxCapabilities().SetCurrent()) {
    SANDBOX_LOG_ERROR("dropping capabilities: %s", strerror(errno));
    MOZ_CRASH("can't drop capabilities");
  }
}