2016-04-13 15 views
5

Podczas testowania aplikacji, uruchomiłem dziwne zachowanie. Niektóre testy używają personifikacji, aby uruchamiać kod jako inny użytkownik, ale zawsze były zawieszone, a nigdy kompletne.Tworzenie Mutex zawiesza się podczas podszywania się pod numer

Po pewnym badaniu problem został zawężony do użycia muteksów. Pierwotnie użyliśmy naszego własnego kodu personifikacji opartego na MSDN documentation, ale nawet w przypadku korzystania z SimpleImpersonation library problem nadal występuje. Oto minimalne przykład odtworzyć problem:

using (Impersonation.LogonUser(DOMAIN, USER, PASSWORD, LogonType.Interactive)) 
{ 
    Console.WriteLine("Impersonated"); 
    bool mine; 
    using (new Mutex(true, "Mutex", out mine)) 
    { 
     if (!mine) 
      throw new Exception("Couldn't get mutex"); 
     Console.WriteLine("Got mutex"); 
    } 
} 

Console.WriteLine("Finished"); 

To nigdy nie kończy, jest zatrzymany na linii z tworzeniem mutex. documentation stwierdza, że ​​powinien albo rzucić wyjątek, albo zwrócić coś, ale nie wspomina o blokowaniu.

Niektóre inne obserwacje, które mogą lub nie mogą być powiązane:

  • jeśli my „podszywać” bieżącego użytkownika, zwraca natychmiast
  • jeśli prowadzimy rzeczywistą aplikację i rozpocząć kolejny przykład jako inny użytkownik, wszystko działa zgodnie z oczekiwaniami.

Prawdopodobnie coś się dzieje z bazowymi zasobami systemu, ale nie mogliśmy tego rozgryźć. Jak to działa?

UPDATE: Zgodnie komentarzu Hans', próbowałem wyłączyć Windows Defender, to nie pomogło. Oto StackTrace od miejsca, w którym to wisi:

[email protected]() 
    [email protected]() 
    mscorlib.ni.dll!719c1867() 
    [Frames below may be incorrect and/or missing, native debugger attempting to walk managed call stack] 
    mscorlib.ni.dll!719c1852() 
    [Managed to Native Transition] 
    mscorlib.dll!System.Threading.Mutex.CreateMutexHandle(bool initiallyOwned, string name, Microsoft.Win32.Win32Native.SECURITY_ATTRIBUTES securityAttribute, out Microsoft.Win32.SafeHandles.SafeWaitHandle mutexHandle) 
     mscorlib.dll!System.Threading.Mutex.MutexTryCodeHelper.MutexTryCode(object userData) 
    [Native to Managed Transition] 
    [Managed to Native Transition] 
    mscorlib.dll!System.Threading.Mutex.CreateMutexWithGuaranteedCleanup(bool initiallyOwned, string name, out bool createdNew, Microsoft.Win32.Win32Native.SECURITY_ATTRIBUTES secAttrs) 
    mscorlib.dll!System.Threading.Mutex.Mutex(bool initiallyOwned, string name, out bool createdNew, System.Security.AccessControl.MutexSecurity mutexSecurity) 
    mscorlib.dll!System.Threading.Mutex.Mutex(bool initiallyOwned, string name, out bool createdNew)  
    MutexImpersonationTest.exe!MutexImpersonationTest.Program.Main(string[] args) Line 16 
+0

Bardzo dziwne. FWIW, jeśli nie otrzymasz dobrej odpowiedzi, rozwiązaniem alternatywnym byłoby zapominanie o klasach .net i użycie P/Invoke do bezpośredniego wywoływania interfejsu Win32 API. –

Odpowiedz

6

Wygląda kodu do nabycia Mutex jest utknięcie w nieskończoną pętlę, w moich testach, to pegging jeden rdzeń w 100% w ramach wezwania do new Mutex(...).

Powodem tego wydaje się, że kod ramy próbuje najpierw wywołanie Win32 CreateMutex, jeśli nie powiedzie się z „odmowa dostępu” błąd, próbuje nazywając OpenMutex zamiast. Jeśli wywołanie OpenMutex kończy się niepowodzeniem z błędem wskazującym, że muteks nie istnieje, ponownie powtarza cały proces, a zatem utknie w nieskończonej pętli, jeśli muteks nie istnieje.

Według CreateMutex documentation, to jest w zasadzie prawidłowe podejście, ale nie wydaje się stanowić przypadku gdy początkowe CreateMutex nie powiedzie się z Access Denied to nie powodu uprawnieniami na istniejącym mutex.

Jedną rzeczą, która wydawała się działać, gdy próbowałem, było przedrostek nazwy muteksa "Global \", mam nadzieję, że jest to odpowiednie obejście dla ciebie.

+0

Globalne muteksy mogą być stworzone w ten sposób, ale to ogranicza instancje wszystkich sesji użytkowników, co jest dramatyczną zmianą w zachowaniu ... –

+0

Ładne połapanie, ten krótki (prawdziwy) kod [jest tutaj] (http: // referencesource. microsoft.com/#mscorlib/system/threading/mutex.cs,9faa5b5e2b4c8f31). –

+1

@ MártonMolnár Jeśli chcesz wywołać sesję mutex, możesz mieć kilka opcji - możesz utworzyć mutex * przed * podszywanie się i ustawić na nim uprawnienia, aby umożliwić podszywanie się pod niego, lub użyć " Globalny \ "prefiks, ale włącz identyfikator sesji (" Proces.GetCurrentProcess(). SessionId') w nazwę muteksu, tworząc w ten sposób mutex "per session" w globalnej przestrzeni nazw. – Iridium

Powiązane problemy