security/sandbox/win/src/restricted_token.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
     2 // Use of this source code is governed by a BSD-style license that can be
     3 // found in the LICENSE file.
     5 #include "sandbox/win/src/restricted_token.h"
     7 #include <vector>
     9 #include "base/logging.h"
    10 #include "sandbox/win/src/acl.h"
    11 #include "sandbox/win/src/win_utils.h"
    14 namespace sandbox {
    16 unsigned RestrictedToken::Init(const HANDLE effective_token) {
    17   DCHECK(!init_);
    18   if (init_)
    19     return ERROR_ALREADY_INITIALIZED;
    21   if (effective_token) {
    22     // We duplicate the handle to be able to use it even if the original handle
    23     // is closed.
    24     HANDLE effective_token_dup;
    25     if (::DuplicateHandle(::GetCurrentProcess(),
    26                           effective_token,
    27                           ::GetCurrentProcess(),
    28                           &effective_token_dup,
    29                           0,
    30                           FALSE,
    31                           DUPLICATE_SAME_ACCESS)) {
    32       effective_token_ = effective_token_dup;
    33     } else {
    34       return ::GetLastError();
    35     }
    36   } else {
    37     if (!::OpenProcessToken(::GetCurrentProcess(),
    38                             TOKEN_ALL_ACCESS,
    39                             &effective_token_))
    40       return ::GetLastError();
    41   }
    43   init_ = true;
    44   return ERROR_SUCCESS;
    45 }
    47 unsigned RestrictedToken::GetRestrictedTokenHandle(HANDLE *token_handle) const {
    48   DCHECK(init_);
    49   if (!init_)
    50     return ERROR_NO_TOKEN;
    52   size_t deny_size = sids_for_deny_only_.size();
    53   size_t restrict_size = sids_to_restrict_.size();
    54   size_t privileges_size = privileges_to_disable_.size();
    56   SID_AND_ATTRIBUTES *deny_only_array = NULL;
    57   if (deny_size) {
    58     deny_only_array = new SID_AND_ATTRIBUTES[deny_size];
    60     for (unsigned int i = 0; i < sids_for_deny_only_.size() ; ++i) {
    61       deny_only_array[i].Attributes = SE_GROUP_USE_FOR_DENY_ONLY;
    62       deny_only_array[i].Sid =
    63           const_cast<SID*>(sids_for_deny_only_[i].GetPSID());
    64     }
    65   }
    67   SID_AND_ATTRIBUTES *sids_to_restrict_array = NULL;
    68   if (restrict_size) {
    69     sids_to_restrict_array = new SID_AND_ATTRIBUTES[restrict_size];
    71     for (unsigned int i = 0; i < restrict_size; ++i) {
    72       sids_to_restrict_array[i].Attributes = 0;
    73       sids_to_restrict_array[i].Sid =
    74           const_cast<SID*>(sids_to_restrict_[i].GetPSID());
    75     }
    76   }
    78   LUID_AND_ATTRIBUTES *privileges_to_disable_array = NULL;
    79   if (privileges_size) {
    80     privileges_to_disable_array = new LUID_AND_ATTRIBUTES[privileges_size];
    82     for (unsigned int i = 0; i < privileges_size; ++i) {
    83       privileges_to_disable_array[i].Attributes = 0;
    84       privileges_to_disable_array[i].Luid = privileges_to_disable_[i];
    85     }
    86   }
    88   BOOL result = TRUE;
    89   HANDLE new_token = NULL;
    90   // The SANDBOX_INERT flag did nothing in XP and it was just a way to tell
    91   // if a token has ben restricted given the limiations of IsTokenRestricted()
    92   // but it appears that in Windows 7 it hints the AppLocker subsystem to
    93   // leave us alone.
    94   if (deny_size || restrict_size || privileges_size) {
    95     result = ::CreateRestrictedToken(effective_token_,
    96                                      SANDBOX_INERT,
    97                                      static_cast<DWORD>(deny_size),
    98                                      deny_only_array,
    99                                      static_cast<DWORD>(privileges_size),
   100                                      privileges_to_disable_array,
   101                                      static_cast<DWORD>(restrict_size),
   102                                      sids_to_restrict_array,
   103                                      &new_token);
   104   } else {
   105     // Duplicate the token even if it's not modified at this point
   106     // because any subsequent changes to this token would also affect the
   107     // current process.
   108     result = ::DuplicateTokenEx(effective_token_, TOKEN_ALL_ACCESS, NULL,
   109                                 SecurityIdentification, TokenPrimary,
   110                                 &new_token);
   111   }
   113   if (deny_only_array)
   114     delete[] deny_only_array;
   116   if (sids_to_restrict_array)
   117     delete[] sids_to_restrict_array;
   119   if (privileges_to_disable_array)
   120     delete[] privileges_to_disable_array;
   122   if (!result)
   123     return ::GetLastError();
   125   // Modify the default dacl on the token to contain Restricted and the user.
   126   if (!AddSidToDefaultDacl(new_token, WinRestrictedCodeSid, GENERIC_ALL))
   127     return ::GetLastError();
   129   if (!AddUserSidToDefaultDacl(new_token, GENERIC_ALL))
   130     return ::GetLastError();
   132   DWORD error = SetTokenIntegrityLevel(new_token, integrity_level_);
   133   if (ERROR_SUCCESS != error)
   134     return error;
   136   BOOL status = ::DuplicateHandle(::GetCurrentProcess(),
   137                                   new_token,
   138                                   ::GetCurrentProcess(),
   139                                   token_handle,
   140                                   TOKEN_ALL_ACCESS,
   141                                   FALSE,  // Don't inherit.
   142                                   0);
   144   if (new_token != effective_token_)
   145     ::CloseHandle(new_token);
   147   if (!status)
   148     return ::GetLastError();
   150   return ERROR_SUCCESS;
   151 }
   153 unsigned RestrictedToken::GetRestrictedTokenHandleForImpersonation(
   154     HANDLE *token_handle) const {
   155   DCHECK(init_);
   156   if (!init_)
   157     return ERROR_NO_TOKEN;
   159   HANDLE restricted_token_handle;
   160   unsigned err_code = GetRestrictedTokenHandle(&restricted_token_handle);
   161   if (ERROR_SUCCESS != err_code)
   162     return err_code;
   164   HANDLE impersonation_token;
   165   if (!::DuplicateToken(restricted_token_handle,
   166                         SecurityImpersonation,
   167                         &impersonation_token)) {
   168     ::CloseHandle(restricted_token_handle);
   169     return ::GetLastError();
   170   }
   172   ::CloseHandle(restricted_token_handle);
   174   BOOL status = ::DuplicateHandle(::GetCurrentProcess(),
   175                                   impersonation_token,
   176                                   ::GetCurrentProcess(),
   177                                   token_handle,
   178                                   TOKEN_ALL_ACCESS,
   179                                   FALSE,  // Don't inherit.
   180                                   0);
   182   ::CloseHandle(impersonation_token);
   184   if (!status)
   185     return ::GetLastError();
   187   return ERROR_SUCCESS;
   188 }
   190 unsigned RestrictedToken::AddAllSidsForDenyOnly(std::vector<Sid> *exceptions) {
   191   DCHECK(init_);
   192   if (!init_)
   193     return ERROR_NO_TOKEN;
   195   TOKEN_GROUPS *token_groups = NULL;
   196   DWORD size = 0;
   198   BOOL result = ::GetTokenInformation(effective_token_,
   199                                       TokenGroups,
   200                                       NULL,  // No buffer.
   201                                       0,  // Size is 0.
   202                                       &size);
   203   if (!size)
   204     return ::GetLastError();
   206   token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
   207   result = ::GetTokenInformation(effective_token_,
   208                                  TokenGroups,
   209                                  token_groups,
   210                                  size,
   211                                  &size);
   212   if (!result) {
   213     delete[] reinterpret_cast<BYTE*>(token_groups);
   214     return ::GetLastError();
   215   }
   217   // Build the list of the deny only group SIDs
   218   for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
   219     if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0 &&
   220         (token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == 0) {
   221       bool should_ignore = false;
   222       if (exceptions) {
   223         for (unsigned int j = 0; j < exceptions->size(); ++j) {
   224           if (::EqualSid(const_cast<SID*>((*exceptions)[j].GetPSID()),
   225                           token_groups->Groups[i].Sid)) {
   226             should_ignore = true;
   227             break;
   228           }
   229         }
   230       }
   231       if (!should_ignore) {
   232         sids_for_deny_only_.push_back(
   233             reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
   234       }
   235     }
   236   }
   238   delete[] reinterpret_cast<BYTE*>(token_groups);
   240   return ERROR_SUCCESS;
   241 }
   243 unsigned RestrictedToken::AddSidForDenyOnly(const Sid &sid) {
   244   DCHECK(init_);
   245   if (!init_)
   246     return ERROR_NO_TOKEN;
   248   sids_for_deny_only_.push_back(sid);
   249   return ERROR_SUCCESS;
   250 }
   252 unsigned RestrictedToken::AddUserSidForDenyOnly() {
   253   DCHECK(init_);
   254   if (!init_)
   255     return ERROR_NO_TOKEN;
   257   DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
   258   TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(new BYTE[size]);
   260   BOOL result = ::GetTokenInformation(effective_token_,
   261                                       TokenUser,
   262                                       token_user,
   263                                       size,
   264                                       &size);
   266   if (!result) {
   267     delete[] reinterpret_cast<BYTE*>(token_user);
   268     return ::GetLastError();
   269   }
   271   Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
   272   sids_for_deny_only_.push_back(user);
   274   delete[] reinterpret_cast<BYTE*>(token_user);
   276   return ERROR_SUCCESS;
   277 }
   279 unsigned RestrictedToken::DeleteAllPrivileges(
   280     const std::vector<std::wstring> *exceptions) {
   281   DCHECK(init_);
   282   if (!init_)
   283     return ERROR_NO_TOKEN;
   285   // Get the list of privileges in the token
   286   TOKEN_PRIVILEGES *token_privileges = NULL;
   287   DWORD size = 0;
   289   BOOL result = ::GetTokenInformation(effective_token_,
   290                                       TokenPrivileges,
   291                                       NULL,  // No buffer.
   292                                       0,  // Size is 0.
   293                                       &size);
   294   if (!size)
   295     return ::GetLastError();
   297   token_privileges = reinterpret_cast<TOKEN_PRIVILEGES*>(new BYTE[size]);
   298   result = ::GetTokenInformation(effective_token_,
   299                                  TokenPrivileges,
   300                                  token_privileges,
   301                                  size,
   302                                  &size);
   303   if (!result) {
   304     delete[] reinterpret_cast<BYTE *>(token_privileges);
   305     return ::GetLastError();
   306   }
   309   // Build the list of privileges to disable
   310   for (unsigned int i = 0; i < token_privileges->PrivilegeCount; ++i) {
   311     bool should_ignore = false;
   312     if (exceptions) {
   313       for (unsigned int j = 0; j < exceptions->size(); ++j) {
   314         LUID luid = {0};
   315         ::LookupPrivilegeValue(NULL, (*exceptions)[j].c_str(), &luid);
   316         if (token_privileges->Privileges[i].Luid.HighPart == luid.HighPart &&
   317             token_privileges->Privileges[i].Luid.LowPart == luid.LowPart) {
   318           should_ignore = true;
   319           break;
   320         }
   321       }
   322     }
   323     if (!should_ignore) {
   324         privileges_to_disable_.push_back(token_privileges->Privileges[i].Luid);
   325     }
   326   }
   328   delete[] reinterpret_cast<BYTE *>(token_privileges);
   330   return ERROR_SUCCESS;
   331 }
   333 unsigned RestrictedToken::DeletePrivilege(const wchar_t *privilege) {
   334   DCHECK(init_);
   335   if (!init_)
   336     return ERROR_NO_TOKEN;
   338   LUID luid = {0};
   339   if (LookupPrivilegeValue(NULL, privilege, &luid))
   340     privileges_to_disable_.push_back(luid);
   341   else
   342     return ::GetLastError();
   344   return ERROR_SUCCESS;
   345 }
   347 unsigned RestrictedToken::AddRestrictingSid(const Sid &sid) {
   348   DCHECK(init_);
   349   if (!init_)
   350     return ERROR_NO_TOKEN;
   352   sids_to_restrict_.push_back(sid);  // No attributes
   353   return ERROR_SUCCESS;
   354 }
   356 unsigned RestrictedToken::AddRestrictingSidLogonSession() {
   357   DCHECK(init_);
   358   if (!init_)
   359     return ERROR_NO_TOKEN;
   361   TOKEN_GROUPS *token_groups = NULL;
   362   DWORD size = 0;
   364   BOOL result = ::GetTokenInformation(effective_token_,
   365                                       TokenGroups,
   366                                       NULL,  // No buffer.
   367                                       0,  // Size is 0.
   368                                       &size);
   369   if (!size)
   370     return ::GetLastError();
   372   token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
   373   result = ::GetTokenInformation(effective_token_,
   374                                  TokenGroups,
   375                                  token_groups,
   376                                  size,
   377                                  &size);
   378   if (!result) {
   379     delete[] reinterpret_cast<BYTE*>(token_groups);
   380     return ::GetLastError();
   381   }
   383   SID *logon_sid = NULL;
   384   for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
   385     if ((token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) != 0) {
   386         logon_sid = static_cast<SID*>(token_groups->Groups[i].Sid);
   387         break;
   388     }
   389   }
   391   if (logon_sid)
   392     sids_to_restrict_.push_back(logon_sid);
   394   delete[] reinterpret_cast<BYTE*>(token_groups);
   396   return ERROR_SUCCESS;
   397 }
   399 unsigned RestrictedToken::AddRestrictingSidCurrentUser() {
   400   DCHECK(init_);
   401   if (!init_)
   402     return ERROR_NO_TOKEN;
   404   DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
   405   TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(new BYTE[size]);
   407   BOOL result = ::GetTokenInformation(effective_token_,
   408                                       TokenUser,
   409                                       token_user,
   410                                       size,
   411                                       &size);
   413   if (!result) {
   414     delete[] reinterpret_cast<BYTE*>(token_user);
   415     return ::GetLastError();
   416   }
   418   Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
   419   sids_to_restrict_.push_back(user);
   421   delete[] reinterpret_cast<BYTE*>(token_user);
   423   return ERROR_SUCCESS;
   424 }
   426 unsigned RestrictedToken::AddRestrictingSidAllSids() {
   427   DCHECK(init_);
   428   if (!init_)
   429     return ERROR_NO_TOKEN;
   431   // Add the current user to the list.
   432   unsigned error = AddRestrictingSidCurrentUser();
   433   if (ERROR_SUCCESS != error)
   434     return error;
   436   TOKEN_GROUPS *token_groups = NULL;
   437   DWORD size = 0;
   439   // Get the buffer size required.
   440   BOOL result = ::GetTokenInformation(effective_token_, TokenGroups, NULL, 0,
   441                                       &size);
   442   if (!size)
   443     return ::GetLastError();
   445   token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
   446   result = ::GetTokenInformation(effective_token_,
   447                                  TokenGroups,
   448                                  token_groups,
   449                                  size,
   450                                  &size);
   451   if (!result) {
   452     delete[] reinterpret_cast<BYTE*>(token_groups);
   453     return ::GetLastError();
   454   }
   456   // Build the list of restricting sids from all groups.
   457   for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
   458     if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0)
   459       AddRestrictingSid(reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
   460   }
   462   delete[] reinterpret_cast<BYTE*>(token_groups);
   464   return ERROR_SUCCESS;
   465 }
   467 unsigned RestrictedToken::SetIntegrityLevel(IntegrityLevel integrity_level) {
   468   integrity_level_ = integrity_level;
   469   return ERROR_SUCCESS;
   470 }
   472 }  // namespace sandbox

mercurial