chromium/sandbox/win/src/app_container_unittest.cc

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include <windows.h>

#include <string>
#include <vector>

#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/format_macros.h"
#include "base/path_service.h"
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/access_control_list.h"
#include "base/win/security_descriptor.h"
#include "base/win/security_util.h"
#include "base/win/sid.h"
#include "build/build_config.h"
#include "sandbox/features.h"
#include "sandbox/win/src/app_container_base.h"
#include "sandbox/win/src/security_capabilities.h"
#include "sandbox/win/src/win_utils.h"
#include "sandbox/win/tests/common/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace sandbox {

namespace {

bool ValidSecurityCapabilities(
    PSECURITY_CAPABILITIES security_capabilities,
    const base::win::Sid& package_sid,
    const std::vector<base::win::Sid>& capabilities) {
  if (!security_capabilities)
    return false;

  if (!package_sid.Equal(security_capabilities->AppContainerSid)) {
    return false;
  }

  // If empty then count and list of capabilities should be 0 and nullptr.
  if (capabilities.empty() && !security_capabilities->CapabilityCount &&
      !security_capabilities->Capabilities) {
    return true;
  }

  if (!security_capabilities->Capabilities)
    return false;

  if (security_capabilities->CapabilityCount != capabilities.size())
    return false;

  for (DWORD index = 0; index < security_capabilities->CapabilityCount;
       ++index) {
    if (!capabilities[index].Equal(
            security_capabilities->Capabilities[index].Sid)) {
      return false;
    }
    if (security_capabilities->Capabilities[index].Attributes !=
        SE_GROUP_ENABLED) {
      return false;
    }
  }

  return true;
}

bool CompareSidVectors(const std::vector<base::win::Sid>& left,
                       const std::vector<base::win::Sid>& right) {
  if (left.size() != right.size())
    return false;
  auto left_interator = left.cbegin();
  auto right_interator = right.cbegin();
  while (left_interator != left.cend()) {
    if (*left_interator != *right_interator)
      return false;
    ++left_interator;
    ++right_interator;
  }
  return true;
}

bool GetProfilePath(const std::wstring& package_name,
                    base::FilePath* profile_path) {
  base::FilePath local_app_data;
  if (!base::PathService::Get(base::DIR_LOCAL_APP_DATA, &local_app_data))
    return false;
  *profile_path = local_app_data.Append(L"Packages").Append(package_name);
  return true;
}

bool ProfileExist(const std::wstring& package_name) {
  base::FilePath profile_path;
  if (!GetProfilePath(package_name, &profile_path))
    return false;
  return base::PathExists(profile_path);
}

bool FindAce(const std::optional<base::win::AccessControlList>& acl,
             DWORD ace_type,
             const base::win::Sid& sid,
             DWORD flags,
             DWORD mask) {
  if (!acl || acl->is_null()) {
    return false;
  }
  PACL pacl = acl->get();
  for (DWORD ace_index = 0; ace_index < pacl->AceCount; ++ace_index) {
    PACCESS_ALLOWED_ACE ace = nullptr;
    if (::GetAce(pacl, ace_index, reinterpret_cast<LPVOID*>(&ace)) &&
        ace->Header.AceType == ace_type &&
        (ace->Header.AceFlags & flags) == flags && ace->Mask == mask &&
        sid.Equal(&ace->SidStart)) {
      return true;
    }
  }
  return false;
}

void CheckProfileDirectorySecurity(const base::FilePath& path,
                                   const base::win::Sid& package_sid) {
  DWORD flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
  std::optional<base::win::SecurityDescriptor> sd =
      base::win::SecurityDescriptor::FromFile(
          path, DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION);
  ASSERT_TRUE(sd);
  EXPECT_TRUE(FindAce(sd->dacl(), ACCESS_ALLOWED_ACE_TYPE, package_sid, flags,
                      FILE_ALL_ACCESS))
      << path.value();
  EXPECT_TRUE(
      FindAce(sd->sacl(), SYSTEM_MANDATORY_LABEL_ACE_TYPE,
              base::win::Sid::FromIntegrityLevel(SECURITY_MANDATORY_LOW_RID),
              flags, SYSTEM_MANDATORY_LABEL_NO_WRITE_UP))
      << path.value();
}

void CheckProfileDirectoryLayout(const AppContainerBase* profile) {
  base::FilePath profile_path;
  ASSERT_TRUE(GetProfilePath(profile->GetPackageName(), &profile_path));
  ASSERT_TRUE(base::DirectoryExists(profile_path));
  base::FilePath ac_path = profile_path.Append(L"AC");
  ASSERT_TRUE(base::DirectoryExists(ac_path));
  CheckProfileDirectorySecurity(ac_path, profile->GetPackageSid());
  base::FilePath tmp_path = ac_path.Append(L"Temp");
  ASSERT_TRUE(base::DirectoryExists(tmp_path));
  CheckProfileDirectorySecurity(tmp_path, profile->GetPackageSid());
}

std::wstring GenerateRandomPackageName() {
  return base::ASCIIToWide(base::StringPrintf(
      "%016" PRIX64 "%016" PRIX64, base::RandUint64(), base::RandUint64()));
}

base::win::SecurityDescriptor::SelfRelative CreateSdWithSid(
    const base::win::Sid& sid) {
  base::win::SecurityDescriptor sd;
  CHECK(sd.SetDaclEntry(base::win::WellKnownSid::kWorld,
                        base::win::SecurityAccessMode::kGrant, GENERIC_ALL, 0));
  CHECK(sd.SetDaclEntry(sid, base::win::SecurityAccessMode::kGrant, GENERIC_ALL,
                        0));
  return *sd.ToSelfRelative();
}

base::win::SecurityDescriptor::SelfRelative CreateSdWithSid(
    base::win::WellKnownSid known_sid) {
  return CreateSdWithSid(base::win::Sid(known_sid));
}

void AccessCheckFile(AppContainer* container,
                     const base::FilePath& path,
                     const base::win::Sid& sid,
                     DWORD desired_access,
                     DWORD expected_access,
                     BOOL expected_status) {
  auto sd = CreateSdWithSid(sid);
  SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), sd.get(), FALSE};
  base::win::ScopedHandle file_handle(::CreateFile(
      path.value().c_str(), DELETE, FILE_SHARE_READ | FILE_SHARE_DELETE, &sa,
      CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, nullptr));

  ASSERT_TRUE(file_handle.is_valid());
  DWORD granted_access;
  BOOL access_status;
  ASSERT_TRUE(container->AccessCheck(
      path.value().c_str(), base::win::SecurityObjectType::kFile,
      desired_access, &granted_access, &access_status));
  ASSERT_EQ(expected_status, access_status);
  if (access_status)
    ASSERT_EQ(expected_access, granted_access);
}

void AccessCheckFile(AppContainer* container,
                     const base::FilePath& path,
                     base::win::WellKnownSid known_sid,
                     DWORD desired_access,
                     DWORD expected_access,
                     BOOL expected_status) {
  AccessCheckFile(container, path, base::win::Sid(known_sid), desired_access,
                  expected_access, expected_status);
}

void AccessCheckFile(AppContainer* container,
                     const base::FilePath& path,
                     base::win::WellKnownCapability known_cap,
                     DWORD desired_access,
                     DWORD expected_access,
                     BOOL expected_status) {
  AccessCheckFile(container, path, base::win::Sid(known_cap), desired_access,
                  expected_access, expected_status);
}

void CheckDaclForPackageSid(HANDLE token,
                            const base::win::Sid& package_sid,
                            bool package_sid_required) {
  auto sd = *base::win::SecurityDescriptor::FromHandle(
      token, base::win::SecurityObjectType::kKernel, DACL_SECURITY_INFORMATION);

  EXPECT_EQ(package_sid_required,
            IsSidInDacl(*sd.dacl(), true, TOKEN_ALL_ACCESS, package_sid));
  EXPECT_NE(package_sid_required,
            IsSidInDacl(*sd.dacl(), true, TOKEN_ALL_ACCESS,
                        base::win::Sid(
                            base::win::WellKnownSid::kAllApplicationPackages)));
}

void CheckLowBoxToken(AppContainerBase* container,
                      const base::win::AccessToken& base_token,
                      bool impersonation,
                      size_t expected_cap_count) {
  std::optional<base::win::AccessToken> token =
      impersonation ? container->BuildImpersonationToken(base_token)
                    : container->BuildPrimaryToken(base_token);
  ASSERT_TRUE(token);
  EXPECT_EQ(token->User(), base_token.User());
  EXPECT_EQ(base::win::GetGrantedAccess(token->get()), DWORD{TOKEN_ALL_ACCESS});
  EXPECT_TRUE(token->IsAppContainer());
  EXPECT_EQ(impersonation, token->IsImpersonation());
  EXPECT_FALSE(token->IsIdentification());
  EXPECT_EQ(token->AppContainerSid(), container->GetPackageSid());
  const std::vector<base::win::Sid>& check_capabilities =
      impersonation ? container->GetImpersonationCapabilities()
                    : container->GetCapabilities();
  auto capabilities = token->Capabilities();
  ASSERT_EQ(capabilities.size(), check_capabilities.size());
  EXPECT_EQ(expected_cap_count, capabilities.size());
  for (size_t index = 0; index < capabilities.size(); ++index) {
    EXPECT_EQ(capabilities[index].GetAttributes(), DWORD{SE_GROUP_ENABLED});
    EXPECT_EQ(capabilities[index].GetSid(), check_capabilities[index]);
  }
  CheckDaclForPackageSid(token->get(), container->GetPackageSid(), true);
}

}  // namespace

TEST(AppContainerTest, SecurityCapabilities) {
  if (!features::IsAppContainerSandboxSupported())
    return;

  // This isn't a valid package SID but it doesn't matter for this test.
  base::win::Sid package_sid(base::win::WellKnownSid::kNull);

  std::vector<base::win::Sid> capabilities;
  SecurityCapabilities no_capabilities(package_sid);
  EXPECT_TRUE(
      ValidSecurityCapabilities(&no_capabilities, package_sid, capabilities));

  capabilities.emplace_back(base::win::WellKnownSid::kWorld);
  SecurityCapabilities one_capability(package_sid, capabilities);
  EXPECT_TRUE(
      ValidSecurityCapabilities(&one_capability, package_sid, capabilities));

  capabilities.emplace_back(base::win::WellKnownSid::kNetwork);
  SecurityCapabilities two_capabilities(package_sid, capabilities);
  EXPECT_TRUE(
      ValidSecurityCapabilities(&two_capabilities, package_sid, capabilities));
}

// TODO(crbug/347547524): re-enable the tests once they are passing on
// Windows ARM64.
#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_ARM64)
#define MAYBE_CreateAndDeleteAppContainerProfile \
  DISABLED_CreateAndDeleteAppContainerProfile
#else
#define MAYBE_CreateAndDeleteAppContainerProfile \
  CreateAndDeleteAppContainerProfile
#endif
TEST(AppContainerTest, MAYBE_CreateAndDeleteAppContainerProfile) {
  if (!features::IsAppContainerSandboxSupported())
    return;

  std::wstring package_name = GenerateRandomPackageName();
  EXPECT_FALSE(ProfileExist(package_name));
  std::unique_ptr<AppContainerBase> profile_container =
      AppContainerBase::CreateProfile(package_name.c_str(), L"Name",
                                      L"Description");
  ASSERT_NE(nullptr, profile_container.get());
  EXPECT_TRUE(ProfileExist(package_name));
  CheckProfileDirectoryLayout(profile_container.get());
  EXPECT_TRUE(AppContainerBase::Delete(package_name.c_str()));
  EXPECT_FALSE(ProfileExist(package_name));
}

// TODO(crbug/347529039): re-enable the tests once they are passing on
// Windows ARM64.
#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_ARM64)
#define MAYBE_CreateAndOpenAppContainer DISABLED_CreateAndOpenAppContainer
#else
#define MAYBE_CreateAndOpenAppContainer CreateAndOpenAppContainer
#endif
TEST(AppContainerTest, MAYBE_CreateAndOpenAppContainer) {
  if (!features::IsAppContainerSandboxSupported())
    return;

  std::wstring package_name = GenerateRandomPackageName();
  EXPECT_FALSE(ProfileExist(package_name));
  std::unique_ptr<AppContainerBase> profile_container =
      AppContainerBase::CreateProfile(package_name.c_str(), L"Name",
                                      L"Description");
  ASSERT_NE(nullptr, profile_container.get());
  EXPECT_TRUE(ProfileExist(package_name));
  CheckProfileDirectoryLayout(profile_container.get());
  std::unique_ptr<AppContainerBase> open_container =
      AppContainerBase::Open(package_name.c_str());
  ASSERT_NE(nullptr, open_container.get());
  EXPECT_TRUE(::EqualSid(profile_container->GetPackageSid().GetPSID(),
                         open_container->GetPackageSid().GetPSID()));
  EXPECT_TRUE(AppContainerBase::Delete(package_name.c_str()));
  EXPECT_FALSE(ProfileExist(package_name));
  std::unique_ptr<AppContainerBase> open_container2 =
      AppContainerBase::Open(package_name.c_str());
  EXPECT_FALSE(ProfileExist(package_name));
}

TEST(AppContainerTest, CreateAndDeleteAppContainerProfileNoFirewall) {
  if (!features::IsAppContainerSandboxSupported()) {
    return;
  }
  std::wstring package_name = GenerateRandomPackageName();
  EXPECT_FALSE(AppContainerBase::ProfileExists(package_name.c_str()));
  std::unique_ptr<AppContainerBase> profile_container =
      AppContainerBase::CreateProfileNoFirewall(package_name.c_str(), L"Name");
  ASSERT_NE(nullptr, profile_container.get());
  EXPECT_TRUE(AppContainerBase::ProfileExists(package_name.c_str()));
  CheckProfileDirectoryLayout(profile_container.get());
  EXPECT_TRUE(AppContainerBase::DeleteNoFirewall(package_name.c_str()));
  EXPECT_FALSE(AppContainerBase::ProfileExists(package_name.c_str()));
}

TEST(AppContainerTest, ReOpenAppContainerProfileNoFirewall) {
  if (!features::IsAppContainerSandboxSupported()) {
    return;
  }
  std::wstring package_name = GenerateRandomPackageName();
  EXPECT_FALSE(ProfileExist(package_name));
  std::unique_ptr<AppContainerBase> profile_container =
      AppContainerBase::CreateProfileNoFirewall(package_name.c_str(), L"Name");
  ASSERT_NE(nullptr, profile_container.get());
  EXPECT_TRUE(ProfileExist(package_name));
  CheckProfileDirectoryLayout(profile_container.get());
  std::unique_ptr<AppContainerBase> open_container =
      AppContainerBase::CreateProfileNoFirewall(package_name.c_str(), L"Name");
  ASSERT_NE(nullptr, open_container.get());
  EXPECT_EQ(profile_container->GetPackageSid(),
            open_container->GetPackageSid());
  EXPECT_TRUE(AppContainerBase::Delete(package_name.c_str()));
  EXPECT_FALSE(ProfileExist(package_name));
}

TEST(AppContainerTest, SetLowPrivilegeAppContainer) {
  if (!features::IsAppContainerSandboxSupported())
    return;
  std::wstring package_name = GenerateRandomPackageName();
  std::unique_ptr<AppContainerBase> container =
      AppContainerBase::Open(package_name.c_str());
  ASSERT_NE(nullptr, container.get());
  container->SetEnableLowPrivilegeAppContainer(true);
  EXPECT_TRUE(container->GetEnableLowPrivilegeAppContainer());
}

TEST(AppContainerTest, OpenAppContainerAndGetSecurityCapabilities) {
  if (!features::IsAppContainerSandboxSupported())
    return;

  std::wstring package_name = GenerateRandomPackageName();
  std::unique_ptr<AppContainerBase> container =
      AppContainerBase::Open(package_name.c_str());
  ASSERT_NE(nullptr, container.get());

  std::vector<base::win::Sid> capabilities;
  auto no_capabilities = container->GetSecurityCapabilities();
  ASSERT_TRUE(ValidSecurityCapabilities(
      no_capabilities.get(), container->GetPackageSid(), capabilities));

  container->AddCapability(L"FakeCapability");
  capabilities.push_back(
      base::win::Sid::FromNamedCapability(L"FakeCapability"));

  container->AddCapability(base::win::WellKnownCapability::kInternetClient);
  capabilities.emplace_back(base::win::WellKnownCapability::kInternetClient);
  const wchar_t kSddlSid[] = L"S-1-15-3-1";
  ASSERT_TRUE(container->AddCapabilitySddl(kSddlSid));
  capabilities.push_back(*base::win::Sid::FromSddlString(kSddlSid));
  auto with_capabilities = container->GetSecurityCapabilities();
  ASSERT_TRUE(ValidSecurityCapabilities(
      with_capabilities.get(), container->GetPackageSid(), capabilities));
}

TEST(AppContainerTest, AccessCheckFile) {
  if (!features::IsAppContainerSandboxSupported())
    return;

  // We don't need a valid profile to do the access check tests.
  std::wstring package_name = GenerateRandomPackageName();
  std::unique_ptr<AppContainerBase> container =
      AppContainerBase::Open(package_name.c_str());
  container->AddCapability(base::win::WellKnownCapability::kInternetClient);
  base::ScopedTempDir temp_dir;
  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
  base::FilePath path = temp_dir.GetPath().Append(package_name);

  AccessCheckFile(container.get(), path, base::win::WellKnownSid::kNull,
                  FILE_READ_DATA, 0, FALSE);
  AccessCheckFile(container.get(), path,
                  base::win::WellKnownSid::kAllApplicationPackages,
                  FILE_READ_DATA, FILE_READ_DATA, TRUE);
  AccessCheckFile(container.get(), path, container->GetPackageSid(),
                  FILE_READ_DATA, FILE_READ_DATA, TRUE);
  AccessCheckFile(container.get(), path,
                  base::win::WellKnownCapability::kInternetClient,
                  FILE_READ_DATA, FILE_READ_DATA, TRUE);

  // Check mapping generic access rights.
  AccessCheckFile(container.get(), path,
                  base::win::WellKnownSid::kAllApplicationPackages,
                  GENERIC_READ | GENERIC_EXECUTE,
                  FILE_GENERIC_READ | FILE_GENERIC_EXECUTE, TRUE);
  if (!features::IsAppContainerSandboxSupported())
    return;
  container->SetEnableLowPrivilegeAppContainer(true);
  AccessCheckFile(container.get(), path,
                  base::win::WellKnownSid::kAllApplicationPackages,
                  FILE_READ_DATA, 0, FALSE);
  AccessCheckFile(container.get(), path,
                  base::win::WellKnownSid::kAllRestrictedApplicationPackages,
                  FILE_READ_DATA, FILE_READ_DATA, TRUE);
}

TEST(AppContainerTest, AccessCheckRegistry) {
  if (!features::IsAppContainerSandboxSupported())
    return;

  // We don't need a valid profile to do the access check tests.
  std::wstring package_name = GenerateRandomPackageName();
  std::unique_ptr<AppContainerBase> container =
      AppContainerBase::Open(package_name.c_str());
  // Ensure the key doesn't exist.
  RegDeleteKey(HKEY_CURRENT_USER, package_name.c_str());
  auto sd = CreateSdWithSid(base::win::WellKnownSid::kAllApplicationPackages);
  SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), sd.get(), FALSE};
  HKEY key_handle;
  ASSERT_EQ(ERROR_SUCCESS,
            RegCreateKeyEx(HKEY_CURRENT_USER, package_name.c_str(), 0, nullptr,
                           REG_OPTION_VOLATILE, KEY_ALL_ACCESS, &sa,
                           &key_handle, nullptr));
  base::win::ScopedHandle key(key_handle);
  std::wstring key_name = L"CURRENT_USER\\";
  key_name += package_name;
  DWORD granted_access;
  BOOL access_status;

  ASSERT_TRUE(container->AccessCheck(
      key_name.c_str(), base::win::SecurityObjectType::kRegistry,
      KEY_QUERY_VALUE, &granted_access, &access_status));
  ASSERT_TRUE(access_status);
  ASSERT_EQ(DWORD{KEY_QUERY_VALUE}, granted_access);
  RegDeleteKey(HKEY_CURRENT_USER, package_name.c_str());
}

TEST(AppContainerTest, ImpersonationCapabilities) {
  if (!features::IsAppContainerSandboxSupported())
    return;

  std::wstring package_name = GenerateRandomPackageName();
  std::unique_ptr<AppContainerBase> container =
      AppContainerBase::Open(package_name.c_str());
  ASSERT_NE(nullptr, container.get());

  std::vector<base::win::Sid> capabilities;
  std::vector<base::win::Sid> impersonation_capabilities;

  container->AddCapability(base::win::WellKnownCapability::kInternetClient);
  capabilities.emplace_back(base::win::WellKnownCapability::kInternetClient);
  impersonation_capabilities.emplace_back(
      base::win::WellKnownCapability::kInternetClient);

  ASSERT_TRUE(CompareSidVectors(container->GetCapabilities(), capabilities));
  ASSERT_TRUE(CompareSidVectors(container->GetImpersonationCapabilities(),
                                impersonation_capabilities));

  container->AddImpersonationCapability(
      base::win::WellKnownCapability::kPrivateNetworkClientServer);
  impersonation_capabilities.emplace_back(
      base::win::WellKnownCapability::kPrivateNetworkClientServer);

  container->AddImpersonationCapability(L"FakeCapability");
  impersonation_capabilities.push_back(
      base::win::Sid::FromNamedCapability(L"FakeCapability"));

  const wchar_t kSddlSid[] = L"S-1-15-3-1";
  ASSERT_TRUE(container->AddImpersonationCapabilitySddl(kSddlSid));
  impersonation_capabilities.push_back(
      *base::win::Sid::FromSddlString(kSddlSid));
  ASSERT_TRUE(CompareSidVectors(container->GetCapabilities(), capabilities));
  ASSERT_TRUE(CompareSidVectors(container->GetImpersonationCapabilities(),
                                impersonation_capabilities));
}

TEST(AppContainerTest, BuildImpersonationToken) {
  if (!features::IsAppContainerSandboxSupported()) {
    return;
  }
  std::optional<base::win::AccessToken> base_token =
      base::win::AccessToken::FromCurrentProcess(
          /*impersonation=*/false, TOKEN_DUPLICATE);
  ASSERT_TRUE(base_token);
  std::wstring package_name = GenerateRandomPackageName();
  std::unique_ptr<AppContainerBase> container =
      AppContainerBase::Open(package_name.c_str());
  ASSERT_NE(nullptr, container.get());

  CheckLowBoxToken(container.get(), *base_token, true, 0);
  container->AddCapability(base::win::WellKnownCapability::kInternetClient);
  container->AddImpersonationCapability(
      base::win::WellKnownCapability::kPrivateNetworkClientServer);
  CheckLowBoxToken(container.get(), *base_token, true, 2);
}

TEST(AppContainerTest, BuildPrimaryToken) {
  if (!features::IsAppContainerSandboxSupported()) {
    return;
  }
  std::optional<base::win::AccessToken> base_token =
      base::win::AccessToken::FromCurrentProcess(
          /*impersonation=*/false, TOKEN_DUPLICATE);
  ASSERT_TRUE(base_token);
  std::wstring package_name = GenerateRandomPackageName();
  std::unique_ptr<AppContainerBase> container =
      AppContainerBase::Open(package_name.c_str());
  ASSERT_NE(nullptr, container.get());

  CheckLowBoxToken(container.get(), *base_token, false, 0);
  container->AddCapability(base::win::WellKnownCapability::kInternetClient);
  container->AddImpersonationCapability(
      base::win::WellKnownCapability::kPrivateNetworkClientServer);
  CheckLowBoxToken(container.get(), *base_token, false, 1);
}

}  // namespace sandbox