Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Impersonation memory leak

On http://msdn.microsoft.com/en-us/library/w070t6ka(v=VS.100).aspx there is an example on how to do impersonation with .net 4.0. We have used this example in a class that inherits IDisposable for ease of use. However, when we use this class in a asp.net web application, we notice a slight but steady increase of Pool Paged Bytes in performance monitor. After a week, the application crashes.

I've tried different implementations of the impersonation-class, using http://msdn.microsoft.com/en-us/library/w070t6ka(v=VS.90).aspx and http://support.microsoft.com/kb/306158 as reference, but they all show the same leak.

Where does this leak come from? Is there a problem with the windows api? We are running Windows 2008 R2.

This is our current version of the impersonation class:

public class Impersonator : IDisposable
{
    public Impersonator(string username, string domain, string password)
    {
        if (!ImpersonateValidUser(username, domain, password))
        {
            throw new SecurityException("Could not impersonate. Wrong username / password");
        }
    }

    public void Dispose()
    {
        UndoImpersonation();
    }

    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);

    private const int LOGON32_PROVIDER_DEFAULT = 0;
    private const int LOGON32_LOGON_INTERACTIVE = 2; //This parameter causes LogonUser to create a primary token.

    private WindowsImpersonationContext impersonatedUser;

    private bool ImpersonateValidUser(string username, string domain, string password)
    {
        SafeTokenHandle safeTokenHandle;

        // Call LogonUser to obtain a handle to an access token.
        bool success = LogonUser(username, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle);

        if (success)
        {
            using (safeTokenHandle)
            {
                // Use the token handle returned by LogonUser.
                WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle());
                impersonatedUser = newId.Impersonate();
            }
        }

        return success;
    }

    private void UndoImpersonation()
    {
        // Releasing the context object stops the impersonation
        if (impersonatedUser != null)
        {
            impersonatedUser.Undo();
            impersonatedUser.Dispose();
        }
    }
}

public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
{
    private SafeTokenHandle() : base(true)
    {
    }

    [DllImport("kernel32.dll")]
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    [SuppressUnmanagedCodeSecurity]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool CloseHandle(IntPtr handle);

    protected override bool ReleaseHandle()
    {
        return CloseHandle(handle);
    }
}

And this is the performance monitor graph of two webservers using different versions of the class:

perfmon http://img222.imageshack.us/img222/5388/captureyog.png

When we disable the class, and use global impersonation via web.config, those lines are completely flat.


Update

I have made a test-application that successfully reproduce the problem. It can be downloaded here:

http://rapidshare.com/files/447325211/ImpersonationTest.zip

The result over 18 hours looks like this:

testapp http://img689.imageshack.us/img689/2055/impersonationtest.png

like image 276
TheQ Avatar asked Feb 09 '11 14:02

TheQ


1 Answers

Hard to tell. At the very least, WindowsIdentity itself is also an IDisposable, and the newId variable is never disposed of. Also, I would check if all uses of the Impersonator class are properly disposed of.

like image 75
Willem van Rumpt Avatar answered Sep 21 '22 12:09

Willem van Rumpt