# HG changeset patch
# User Bob Owen <bobowencode@gmail.com>
# Date 1709836178 0
#      Thu Mar 07 18:29:38 2024 +0000
# Node ID 2b9ab7e6c5a1630b497fe1543634cbaebdc395f8
# Parent  f9c20c064d639a146ffa09ec832aee6dff44643d
Bug 1889932 p1: Set process ACL to the delayed integrity level in LowerToken. r=yjuglaret!

This allows us to maintain the same access to our process when the integrity
level on our access token is dropped.
This uses a lower level function for setting the label instead if the chromium
wrappers, so that processes that haven't loaded ntmarta.dll don't need to.

Differential Revision: https://phabricator.services.mozilla.com/D206784

diff --git a/sandbox/win/src/target_services.cc b/sandbox/win/src/target_services.cc
--- a/sandbox/win/src/target_services.cc
+++ b/sandbox/win/src/target_services.cc
@@ -95,16 +95,38 @@ bool SetProcessIntegrityLevel(IntegrityLevel integrity_level) {
       base::win::AccessToken::FromCurrentProcess(/*impersonation=*/false,
                                                  TOKEN_ADJUST_DEFAULT);
   if (!token) {
     return false;
   }
   return token->SetIntegrityLevel(*rid);
 }

+void SetProcessAclIntegrityLevel(IntegrityLevel integrity_level) {
+  std::optional<DWORD> rid = GetIntegrityLevelRid(integrity_level);
+  if (!rid) {
+    // No mandatory level specified, we don't change it.
+    return;
+  }
+
+  // Set the integrity level for our process ACL, so we retain access to it.
+  // We ignore failures in non-debug because this is not a security measure,
+  // but some functionality may fail later in the process.
+  base::win::SecurityDescriptor sdWrapper;
+  if (!sdWrapper.SetMandatoryLabel(*rid, 0, 0)) {
+    DCHECK(false);
+    return;
+  }
+
+  SECURITY_DESCRIPTOR sd = sdWrapper.ToAbsolute();
+  BOOL success = ::SetKernelObjectSecurity(::GetCurrentProcess(),
+                                           LABEL_SECURITY_INFORMATION, &sd);
+  DCHECK(success);
+}
+
 // Used as storage for g_target_services, because other allocation facilities
 // are not available early. We can't use a regular function static because on
 // VS2015, because the CRT tries to acquire a lock to guard initialization, but
 // this code runs before the CRT is initialized.
 char g_target_services_memory[sizeof(TargetServicesBase)];
 TargetServicesBase* g_target_services = nullptr;

 }  // namespace
@@ -142,21 +165,23 @@ void TargetServicesBase::LowerToken() {
   if (ERROR_SUCCESS != ::RegDisablePredefinedCache())
     ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CACHEDISABLE);
   if (!WarmupWindowsLocales())
     ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_WARMUP);
   bool is_csrss_connected = true;
   if (!CloseOpenHandles(&is_csrss_connected))
     ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CLOSEHANDLES);
   process_state_.SetCsrssConnected(is_csrss_connected);
-  // Enabling mitigations must happen last otherwise handle closing breaks
+  // Enabling mitigations must happen after the above measures otherwise handle
+  // closing breaks.
   if (g_shared_delayed_mitigations &&
       !LockDownSecurityMitigations(g_shared_delayed_mitigations)) {
     ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_MITIGATION);
   }
+  SetProcessAclIntegrityLevel(g_shared_delayed_integrity_level);
   process_state_.SetInitCompleted();
 }

 ProcessState* TargetServicesBase::GetState() {
   return &process_state_;
 }

 TargetServicesBase* TargetServicesBase::GetInstance() {
