locked
Writing to Global Shared memory from an Application in Vista. RRS feed

  • Question

  • Hi all,

    Global shared memory is created by a service which is used by my user mode application to communicate with the service through global mutexes and events.

    This as of now works well in Vista RC1.

    1) Are there any restrictions that an application should not write to global shared memory already created by service ? This application does not has any elevated privileges.

    2) Can application created global named objects like event and mutex ? Again the application is running under a standard user privilege and not as admin.

    3) Can a 32bit application on a 64bit machine get interfaces to a 64bit Local server COM object ? Is there any special processing required in the 32bit app or in the 64bit local server COM object.

    Regards,

    Vijay Chegu

     

     

    Thursday, September 21, 2006 9:59 AM

All replies

  • 1) I assume you're using named objects.
    As long as the client opens the object specifying Global\ to refer to the global namespace, and the service allowed logged on users to access it by setting the appropriate security descriptor at object creation time, this should work.

    2) By default, the answer is no, because standard users don't get the privilege to create global objects.

    Wednesday, October 18, 2006 10:14 PM
  • I believe that #2 above is incorrect: standard users DO have the rights to create global named objects like events and mutexes. The only exception is global file mappings (i.e. global shared memory), which since 2003 can only be created by standard users if running in session 0 - which under Vista basically means never, since only services run in session 0 on Vista. But I repeat: other global named objects are allowed, and I just tested this with a gloval event on Vista RC2.
    Thursday, October 19, 2006 9:05 AM
  • Hello there

    I have a situation very similar to your description. I have Win32 Service running under LocalSystem account . this service creates MemoryMapped file + Mutex and Events with "Global\ " prefix names.

     These global objects are being opened form User mode apps for IPC. Data was  written/read from the both sides. Initially I created all these objects with NULL SECURITY_ATTRIBUTES . All this worked fine on WinXP/2K machines. When I tried to test my app on Vista problems start to pop up.  My user app failed to open existing global objects. I applied security attribs using (::ConvertStringSecurityDescriptorToSecurityDescriptor() API. Creation of objects in Service still works , however user applications still cannot open objects. What's strange is that OpenMutex for instance does not return any valid handle, and GetLastError() returns 0! I tried different combinations of SDDL strings , sometimes I get Access denied (5) error. Anyway something wrong there I cannot get my system back on track. It seem you have some experience in this filed can you please help me with this issue.

    Best regards David.

     

    Thursday, October 19, 2006 3:52 PM
  • You're right. I stand corrected. I had never noticed the check for object type...
    Sorry about this.

    Thursday, October 19, 2006 8:03 PM
  • To David_bubu: Passing NULL for the LPSECURITY_ATTRIBUTES parameter of CreateEvent, CreateMutex and CreateFileMapping is definitely a bad idea: this creates the object with the default security attributes, which means that a process running as a different user will not be able to access the object, and this is true in 2000 and XP as well. Thus, even before dealing with Vista, we would pass &secAttr, initializing it as follows:

        SECURITY_ATTRIBUTES secAttr;
        char secDesc[ SECURITY_DESCRIPTOR_MIN_LENGTH ];
        secAttr.nLength = sizeof(secAttr);
        secAttr.bInheritHandle = FALSE;
        secAttr.lpSecurityDescriptor = &secDesc;
        InitializeSecurityDescriptor(secAttr.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
        SetSecurityDescriptorDacl(secAttr.lpSecurityDescriptor, TRUE, 0, FALSE);

    This means that absolutely everyone has read & write privileges on the object. You could modify this to give a more specific access list.

    With Vista, there is a new variable in the equation: integrity level. This is independent of the DACL - it is specified via the SACL. If a SACL is not set (as it is not above), the default intergrity level is used. For a process running as administrator or system, this will be high integrity, which means that medium and low integrity processes will not be able to modify the object - or even to open it for write access. Thus, if your process running as system is creating an object that is going to have to be modified by processes running without admin privileges - and thus with medium or low integrity - you had better create the object with medium or low integrity. This is how we do it with low integrity (tack this on to the code above):

        PSECURITY_DESCRIPTOR pSD;
        ConvertStringSecurityDescriptorToSecurityDescriptor(
            "S:(ML;;NW;;;LW)", // this means "low integrity"
            SDDL_REVISION_1,
            &pSD,
            NULL);
        PACL pSacl = NULL;                  // not allocated
        BOOL fSaclPresent = FALSE;
        BOOL fSaclDefaulted = FALSE;
        GetSecurityDescriptorSacl(
            pSD,
            &fSaclPresent,
            &pSacl,
            &fSaclDefaulted);
        SetSecurityDescriptorSacl(secAttr.lpSecurityDescriptor, TRUE, pSacl, FALSE);

    I would guess that this applies to any kind of object - event, mutex, or shared memory.

    To Eric Perlin: What do you mean when you say "I had never noticed the check for object type"? Where are you looking that you see a check? Are we talking Windows source code here?

    Sunday, October 22, 2006 2:57 PM
  • I was wrong when I said above "For a process running as administrator or system, this will be high integrity, which means that medium and low integrity processes will not be able to modify the object - or even to open it for write access." I wrote a test service running as LocalSystem on Vista RC2, and had it create a global event and global shared memory, using SECURITY_ATTRIBUTES with an empty DACL as shown above. However, I did not do anything to the SACL and did not use the second piece of code above. Unlike my assumption above, a process running without admin privileges was able to open the global event and the global shared memory for write access and write to them (SetEvent in the case of the event). I am not sure why. If anyone has any clue, please speak up.
    Monday, October 23, 2006 12:19 PM
  • Hi thank you for response!

    I made some further investigations regarding this problem.

    There is a diffrence between Mutexes and rest of global objects. As you already have mentioned it IS possible to create and access Events ans MeoryMapped files created with NULL security descriptor.  However this is not working with Mutex object. I created Mutex with explicit security attributes :

    SECURITY_ATTRIBUTES * pSA;

    TCHAR * szSecDescString = TEXT("(A;OICI;GA;;;WD)");   // I tried diffrent SDDL strings here

    InitializeSecurityDescriptor(&m_sd,SECURITY_DESCRIPTOR_REVISION);

    m_sa.nLength=sizeof (SECURITY_ATTRIBUTES);

    m_sa.lpSecurityDescriptor = &m_sd;

    m_sa.bInheritHandle = TRUE; // Child process can inherit

    if(ConvertStringSecurityDescriptorToSecurityDescriptor(szSecDescString ,SDDL_REVISION_1, &(m_sa.lpSecurityDescriptor), NULL)== ERROR_SUCCESS)

    { // so something here ............

    }

    This security attribute I pass to CreateMutex function. On the client side I try 

    OpenMutex(MUTEX_ALL_ACCESS, .....)  this yelds error 5 on Vista. I tried to call OpenMutex(MUTEX_MODIFY_STATE, .....) this works I got handle to the existing mujtex object! However when I try to WaitSingleObject() on this mutex handle  it again returns 5 (Access denied).  There is something wrong and inconsistent in this behaviour. I tried to find clearer expalantion on Microsft but in vain.

    Can you please clarify about integrity levels? Is there some kind of refernce in MSDN ? 


    Regards, David  

     

    Monday, October 23, 2006 12:57 PM
  • Sorry, but I am getting the exact same results for mutexes as events. Please note that I am NOT passing NULL for the PSECURITY_ATTRIBUTES, but building SECURITY_ATTRIBUTES with an empty DACL, which are two very different things.

    Here is the code I am using:

    #include <windows.h>
    #include <stdio.h>

    int main() {
        SECURITY_ATTRIBUTES secAttr;
        char secDesc[ SECURITY_DESCRIPTOR_MIN_LENGTH ];
        secAttr.nLength = sizeof(secAttr);
        secAttr.bInheritHandle = FALSE;
        secAttr.lpSecurityDescriptor = &secDesc;
        InitializeSecurityDescriptor(secAttr.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
        SetSecurityDescriptorDacl(secAttr.lpSecurityDescriptor, TRUE, 0, FALSE);

        HANDLE hEvent = CreateEvent(&secAttr, FALSE, FALSE, "Global\\globevent");
        if (hEvent == NULL)
            printf("CreateEvent for global event failed, err %u\n", GetLastError());
        else
            printf("CreateEvent for global event succeeded\n");

        HANDLE hMutex = CreateMutex(&secAttr, FALSE, "Global\\globmutex");
        if (hMutex == NULL)
            printf("CreateMutex for global mutex failed, err %u\n", GetLastError());
        else
            printf("CreateMutex for global mutex succeeded\n");

        void* pMem = NULL;
        HANDLE hMap = CreateFileMapping(
            (HANDLE)0xFFFFFFFF, &secAttr, PAGE_READWRITE, 0, 128, "Global\\globalmem");
        if (hMap == NULL)
            printf("CreateFileMapping for global memory failed, err %u\n", GetLastError());
        else {
            printf("CreateFileMapping for global memory succeeded\n");
            pMem = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0);
            if (pMem == NULL)
                printf("MapViewOfFile for global memory failed, err %u\n", GetLastError());
            else
                printf("MapViewOfFile for global memory succeeded\n");
        }

        if (hEvent || hMutex || hMap) {

            getchar();

            if (hEvent) {
                if (SetEvent(hEvent))
                    printf("SetEvent on global event succeeded\n");
                else
                    printf("SetEvent on global event failed, err %u\n", GetLastError());
                CloseHandle(hEvent);
            }

            if (hMutex) {
                WaitForSingleObject(hMutex, INFINITE);
                if (ReleaseMutex(hMutex))
                    printf("ReleaseMutex on global mutex succeeded\n");
                else
                    printf("ReleaseMutex on global mutex failed, err %u\n", GetLastError());
                CloseHandle(hMutex);
            }

            if (pMem)
                UnmapViewOfFile(pMem);

            if (hMap)
                CloseHandle(hMap);
        }

        return 0;
    }

    To test, run this as admin. Then, before hitting Enter, fast user switch, log in as a non-admin, and run it there. Hit Enter, log out, go back to the admin session, and hit Enter there. Everything should succeed (it does for me).

    Integrity levels are new to Vista and are quite poorly documented, although you will find some articles on MSDN. Every object has an integrity level and every process has an integrity level, and there are basically three levels: high, medium, and low. System and admin processes have high integrity; most user-initiated processes are medium integrity, and protected-mode IE has low integrity. A process whose integrity is lower than that of an object will not be allowed to write it. This issue seems to come mostly when writing code that has to run inside the IE process, e.g. ActiveX's.

    Monday, October 23, 2006 4:16 PM
  • The NULL DACL is equivalent to giving MUTEX_ALL_ACCESS to Everyone.
    The SDDL above had couple issues:
    You don't need to specify inheritance flag for mutexes (it's not a container object).
    Using GA (a generic mapping) was the other. Specify the mapped value instead. For example 0x00100001 for SYNCHRONIZE | MUTEX_MODIFY_STATE.
    You probably don't really need the client to have other kind of access.

    Then the rights requested at Open time need to match what's going to be done with the object.
    Request SYNCHRONIZE when you'll WaitForSingleObject on the object, MUTEX_MODIFY_STATE when calling ReleaseMutex.

    The APIs description typically specifies the access right required.

    Monday, October 23, 2006 6:06 PM
  • Thank you for your help!

    My initial code was the same as yours , however Im getting Access Denied error (5) in my user moide application  on this line :

     HANDLE hMap = CreateFileMapping( (HANDLE)0xFFFFFFFF, &secAttr, PAGE_READWRITE, 0, 128, "Global\\globalmem");

    The same happens to your app as well, I followed your instructions exactly! 

     I tried to apply security attributes to the objects, however Im still have problem accessing Mutex from non-prioviledge user.

     Perhaps you are developing on machine with modified security policy? 

    David.

    Wednesday, October 25, 2006 10:19 AM
  • Regarding CreateFileMapping: With admin or system privileges, it is supposed to succeed. Without them, it is supposed to succeed only if the file mapping already exists, i.e. if you have run the program with admin privileges and have not yet pressed Enter (and thus the mapping created by the admin process still exists). If the mapping does not yet exist, the non-admin's CreateFileMapping is supposed to fail with ERROR_ACCESS_DENIED, as you have experienced. That's because non-admins are not allowed to create global shared memory, but are allowed to use it if it already exists. That's the special thing about global shared memory, and it is NOT true re other global named objects. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/termserv/termserv/kernel_object_namespaces.asp (and keep in mind that in Vista, only services run in session 0).

    Regarding the mutex: What I am experiencing, on both XP and Vista RC2, both of which do not have any special configuration, that my program succeeds in creating the mutex, waiting on the mutex, and releasing the mutex regardless of whether it is run as admin or not. If that is not what you are getting, I have no explanation for this.

    • Proposed as answer by Kenneth_Wang Friday, April 15, 2011 9:05 AM
    • Unproposed as answer by Kenneth_Wang Friday, April 15, 2011 9:05 AM
    Wednesday, October 25, 2006 2:15 PM
  • If the file mapping already exists, CreateFileMapping is in fact equivalent to OpenFileMapping.
    The actual creation of a global file mapping requires SeCreateGlobalPrivilege (unless the code runs in session 0, which is reserved for services in Vista).
    Opening the file mapping afterwards (using either OpenFileMapping or CreateFileMapping (the latter indicates the pre-existence by setting GetLastError)) is bound by the security descriptor set by the creator.

    Wednesday, October 25, 2006 6:46 PM
  • Hi to all participants.

    Eventually everybody are right here ! All global objects MUST be created by Session 0 / Service app.  Apps running in other sessions can only open these objects - bound to security  priviledges of the objects. In my case this means to re-write a lot of code         

    Thanks to everybody, David

    Thursday, October 26, 2006 9:34 AM
  • That's not really accurate (and I apologize if my previous post lead you to believe this).
    As the sample is this thread shows it, the actual creation of Global\ named file mappings works from sessions other than 0 if the caller has the SeCreateGlobalPrivilege.
    Other Global\ named objects (events, mutexes, ...) can be created regardless of privileges.

    Once the object exists, it's not a creation anymore. The object is opened and access depends on the ACL set by the creator.

    If a "creation" API is used instead of an "open", the API will behave as an open but typically set the last error to ERROR_ALREADY_EXIST even in case of success.
    This allows the creator to react in case it doesn't expect the object to already exist (squatting attacks).

    Is this any clearer?

    Thursday, October 26, 2006 6:52 PM
  • Yeah you are correct. The only problem is that by fefault Vista users do not have  SeCreateGlobalPrivilege set on. Though it is possible to change it using  Security Policy MMC it is not acceptable solution. Thank you for you clarification, your input was very valuable.

    David 

    Sunday, October 29, 2006 10:12 AM
  • Thanks for your clarifications. Your posts (all the people here) where really useful.

    David  

    Monday, October 30, 2006 6:08 PM
  • david, did you find any solution. I have the same problem. Windows service contains my business logic. ASP files are trying to talk to service through COM. My COM is getting error 5 when i try to CreateEvent().

    Please et me know what have you done.


    Jack
    Friday, November 3, 2006 1:27 AM
  • Hello all,

    I have the same problem the CreateFileMapping with name "Global\\.." fails for non admin user in the session 1 and works correctly if I run program as Adminstrator . I attempting to implement setting  SeCreateGlobalPrivilege for the caller but  the CreateFileMapping  fails in ths case too.(return access denied also).

    What is wrong in this code represented the CreateFileMapping problem ?

    Thank for any help.

    BOOL SetPrivilege(
        HANDLE hToken,          // access token handle
        LPCTSTR lpszPrivilege,  // name of privilege to enable/disable
        BOOL bEnablePrivilege   // to enable or disable privilege
        )
    {
    TOKEN_PRIVILEGES tp;
    LUID luid;

    if ( !LookupPrivilegeValue(
            NULL,            // lookup privilege on local system
            lpszPrivilege,   // privilege to lookup
            &luid ) )        // receives LUID of privilege
    {
       
        return FALSE;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if (bEnablePrivilege)
        tp.Privileges[0].Attributes =SE_PRIVILEGE_ENABLED;
    else
        tp.Privileges[0].Attributes = 0;

    // Enable the privilege or disable all privileges.

    if ( !AdjustTokenPrivileges(
           hToken,
           FALSE,
           &tp,
           sizeof(TOKEN_PRIVILEGES),
           (PTOKEN_PRIVILEGES) NULL,
           (PDWORD) NULL))
                return FALSE;

      return TRUE;
    }

     

    int main(int argc, char* argv[])
    {
        char                    tSD [SECURITY_DESCRIPTOR_MIN_LENGTH];
        PSECURITY_DESCRIPTOR    pSD = tSD;
        SECURITY_ATTRIBUTES     ntsa;       // Security attributes for NT
        ntsa.nLength              = sizeof(ntsa);
        ntsa.lpSecurityDescriptor = pSD;
        ntsa.bInheritHandle       = TRUE;
        LPSECURITY_ATTRIBUTES   psa = NULL;   // pointer for security attributes
        DWORD rc;

     HANDLE TokenHandle;
     HANDLE ProcessHandle = GetCurrentProcess();
     if(TRUE != OpenProcessToken( ProcessHandle,  TOKEN_ADJUST_PRIVILEGES, &TokenHandle)){
       CloseHandle( ProcessHandle);
       return FALSE;
     }

     if (TRUE != SetPrivilege(TokenHandle,   SE_CREATE_GLOBAL_NAME, TRUE)) { //set  SeCreateGlobalPrivilege 
       CloseHandle( ProcessHandle);
       CloseHandle( TokenHandle);
       return FALSE;
      
     }


        if (! InitializeSecurityDescriptor (ntsa.lpSecurityDescriptor,
                                                SECURITY_DESCRIPTOR_REVISION))
                   return FALSE;
        if (! SetSecurityDescriptorDacl (ntsa.lpSecurityDescriptor, TRUE, (PACL) NULL,
                                                FALSE))
                   return FALSE;

        void* pMem = NULL;
        HANDLE hMap = CreateFileMapping(
            (HANDLE)0xFFFFFFFF, psa, PAGE_READWRITE, 0, 128, "Global\\globalmem");
        if (hMap == NULL)
            printf("CreateFileMapping for global memory failed, err %u\n", GetLastError());
        else {
            printf("CreateFileMapping for global memory succeeded\n");
            pMem = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0);
            if (pMem == NULL)
                printf("MapViewOfFile for global memory failed, err %u\n", GetLastError());
            else
                printf("MapViewOfFile for global memory succeeded\n");
        }
        if (pMem)
            UnmapViewOfFile(pMem);

            if (hMap)
                CloseHandle(hMap);

        return 0;
    }

     

    I

     

     

    Tuesday, November 28, 2006 1:45 PM
  • There is no way for a non-elevated process to create global shared memory in Vista (or in a session other than 0 even on Windows 2003). In other words, tough luck. If you need global shared memory, write a service to create it.
    Wednesday, November 29, 2006 5:12 PM
  • Nice, that means, that if I have my own service to create the global shared memory for my process running non-eleveated and my process actually starts BEFORE my service, then I have bad luck, because the process cannot create that shared memory :-( This is happenning to our customers world wide, so do not think it's utopia. Is there any setting to say windows it should run my service before my process? Some dependency mechanism?
    Monday, December 4, 2006 12:42 PM
  • I am not saying that this is the way it should be. In fact, I think it stinks, because I do not understand the motivation for it, and because it forced us to jump through hoops with our application too. But that is the way it is. (And BTW, I have no connection to Microsoft.)
    Monday, December 4, 2006 12:56 PM
  • Sorry, if you felt I blame you for this bahviour or I claim that you think this is right as is. I do not. I just wanted to express my disappointment about the fact, the evidently there is no other sollution to my problem than wait for my service to start up and create the shared memory.
    Monday, December 4, 2006 1:05 PM
  • Hi,

    I am having an issue with global memory mapped files. I have taken this code and added it to a test service, running under LocalSystem, that creates a memory mapped file as part of its startup processing. The mapped file was created with a DACl that allows r/w access and I lowered the integrity level of it to low.

    I have an application that attempts to opens that global memory mapped file and it gets error code 2 (file not found), when it tries to access the mapped file. I get the same error if I run that client application as an administrator.

    What is confusing to me is if I run the service as a desktop application all works as expected and I am able to communicate across two different logged on users.

    The memory mapped file is created in the global space so I dont see what could be going on.

    Any ideas?

     

    Friday, December 8, 2006 4:58 PM
  • Hi Efratian,
    you seem to have deep knowledge in this issue, maybe you can help me. I was trying like you suggested earlier in this thread, but it's not working yet. First of all, I'm using VC++ 6.0 and there is no ConvertStringSecurityDescriptorToSecurityDescriptor function available. I've copied the sddl.h and the AdvAPI32.lib from VC++ 7.0 to be able to compile the my app. I needed to change that line in sddl.h as well to get it run:
    #if(_WIN32_WINNT >= 0x0500)
    I agree, this is not a good way but I see no other way. Maybe this is why your example is not working on my pc.
    The error is visible after that call:
    GetSecurityDescriptorSacl(
            pSD,
            &fSaclPresent,
            &pSacl,
            &fSaclDefaulted);
    This function should change the pSacl, but in my case it is still NULL after calling that function.

    Is there a way to change the integrity level with VC++ 6.0?

    Thanks a lot for your help.

    Wednesday, March 7, 2007 3:05 PM
  • The motivation is the threat of squatting (i.e. an unprivileged application creating the section before the service).
    All clients in any sessions would pick up the content of that memory. If the creator was malicious, who knows what it could cause the clients to do.

    Monday, March 12, 2007 12:43 AM
  • Did you really prefix the section name with Global\ ?
    The symptoms here point to a local section.

    Monday, March 12, 2007 12:45 AM
  • Mabad, you need to install the platform SDK and change your project settings to use the SDK's include files and librairies.

    Monday, March 12, 2007 12:48 AM
  •  

    efratian,

     

    I want to thank you for this post.  I have a global hook dll that uses a memory mapped file to share data.  It was causing IE on Vista to hang.  The code you posted solved this problem.  Thank you.  Thank you.  Thank you.

    Thursday, March 29, 2007 3:03 PM
  • Hello All,

    Hello All,

    I too have a same problem... I have an exe and Dll and they communicate to each other through shared memory. but it is not working in Vista when UAC is on .. Is there any mechanism so that without turning off UAC, my DLL can use the shared memory created by EXE.

    Exe Code :

    handleMapFile = CreateFileMapping( INVALID_HANDLE_VALUE,        // use paging file
                                        NULL,                        // default security
                                        PAGE_READWRITE,                // read/write access
                                        0,                            // max. object size
                                        dwSharedMemSize,            // buffer size 
                                        "XYZ");


    DLL Code :
    handleMapFile = OpenFileMapping( FILE_MAP_ALL_ACCESS,    // read/write access
                                    FALSE,                    // do not inherit the name
                                   "XYZ");        


    Do i need  to change the default security parameter of  CreateFileMapping method or is there any other way so that we can access the shared memory object.

    Reply ASAP.

    ALok

    Thursday, April 17, 2008 8:02 AM
  • No, according to the posts above, there is no way to "cheat" so that global, shared memory can be allocated by an application running on Vista with "normal" privileges.

    Since this effectively breaks the whole purpose of using global, shared memory (what security risk to other applications or the system is it if my application wants to share its memory globally?) I think it stinks, too.  There is no rhyme nor reason for Microsoft to have introduced this change, and (in particular) it has not been documented well, if AT ALL.  Looking at the current documentation for CreateFileMapping, there is no mention of this new restriction.  Very poor from Microsoft, and another reason why Vista is getting a poor reputation.

     

    Monday, June 23, 2008 8:56 AM
  • If the object name is similar to "XYZ" (or at least not prefixed with Global\), then the object is local to the session and that thread doesn't apply. Applications are able to create local named sections in their own session.

    Which call is failing? With which error code?

    Monday, June 23, 2008 9:00 PM
  • A few remarks:

    * Is a global (shared by all currently logged on users of the machine) file mapping really necessary to your application?

    A local mapping will be accessible to all applications running as the currently logged on user within a session.

    * The purpose of the privilege required is not to protect anyone from an application sharing memory globally, but to prevent squatting of an object name by malicious application.

    * The requirement for this privilege is not new. It has existed since XPSP2. It would have been required if the application had been tested with Terminal Services or Fast User Switching.

    What's changed in Vista is that by default users log on in sessions other than session 0, now always triggering the check mentioned below.

    * This is actually documented in CreateFileMapping.

    Under the explanation of the lpName parameter:

     

    Terminal Services:   The name can have a "Global\" or "Local\" prefix to explicitly create the object in the global or session namespace. The remainder of the name can contain any character except the backslash character (\). Creating a file mapping object in the global namespace from a session other than session zero requires the SeCreateGlobalPrivilege privilege. For more information, see Kernel Object Namespaces.
    Windows XP:   Fast user switching is implemented by using Terminal Services sessions. The first user to log on uses session 0 (zero), the next user to log on uses session 1 (one), and so on. Kernel object names must follow the guidelines that are outlined for Terminal Services so that applications can support multiple users.

     

    Monday, June 23, 2008 9:15 PM
  •  Eric Perlin - MSFT wrote:

    A few remarks:

    * Is a global (shared by all currently logged on users of the machine) file mapping really necessary to your application?

     

    Irrelevant to Microsoft!

     

     Eric Perlin - MSFT wrote:

    A local mapping will be accessible to all applications running as the currently logged on user within a session.

    * The purpose of the privilege required is not to protect anyone from an application sharing memory globally, but to prevent squatting of an object name by malicious application.

     

    Surely that is the responsibility of the user (or the application)?  In doing this, Microsoft is applying a "Nanny" attitude to perfectly valid applications, rather than tackling the cause of malicious applications.

     

     Eric Perlin - MSFT wrote:

    * The requirement for this privilege is not new. It has existed since XPSP2. It would have been required if the application had been tested with Terminal Services or Fast User Switching.

    What's changed in Vista is that by default users log on in sessions other than session 0, now always triggering the check mentioned below.

    * This is actually documented in CreateFileMapping.

    Under the explanation of the lpName parameter:

     

    Terminal Services:   The name can have a "Global\" or "Local\" prefix to explicitly create the object in the global or session namespace. The remainder of the name can contain any character except the backslash character (\). Creating a file mapping object in the global namespace from a session other than session zero requires the SeCreateGlobalPrivilege privilege. For more information, see Kernel Object Namespaces.
    Windows XP:   Fast user switching is implemented by using Terminal Services sessions. The first user to log on uses session 0 (zero), the next user to log on uses session 1 (one), and so on. Kernel object names must follow the guidelines that are outlined for Terminal Services so that applications can support multiple users.

     

    Except that documentation quote says nothing about Vista!  You have to infer from other documentation about Vista and session 0 what the above means for Vista.  The documentation ought to be updated and clarified.

     

    Thanks for the response, though.

    Wednesday, June 25, 2008 2:04 PM
  • Code Snippet
    Irrelevant to Microsoft!

    Relevant to Eric.  If someone is trying to help you, they generally like to know what you're doing.  It sounds like you have hit a brick wall.  Do you want help in getting around it?

     

    Code Snippet
    Surely that is the responsibility of the user (or the application)?  In doing this, Microsoft is applying a "Nanny" attitude to perfectly valid applications, rather than tackling the cause of malicious applications.

    Users and application writers don't always have coincidental interests.

     

    Microsoft is trying to make Windows stable, functional, and secure.  The unfortunate fact is that no OS design is perfect, and the system slowly changes over time as the design is refined from version to version.  Microsoft certainly isn't trying to 'Nanny' applications; it's fixing problems.  SeCreateGlobalPrivilege is not new - it's been here since the one of the Windows 2000 service packs, and it's raises the quality of the OS. Session 0 isolation for services helps prevent the shatter attack (see wikipedia if you want a description and some nightmares).

     

    If you want to create global object that will be present in all sessions on the system, you still can, but you will need to do it from a context which has the SeCreateGlobalPrivilege - most likely, a service configured with the privilege.  If you need to create a local object, that will work inside your session?  You can do that from anywhere.

     

    Code Snippet

    Except that documentation quote says nothing about Vista!  You have to infer from other documentation about Vista and session 0 what the above means for Vista.  The documentation ought to be updated and clarified.

    Unfortunately, there is a great deal of information on MSDN, and a lot of it is interrelated.  The end result is either that you will have to read a number of related articles to understand a subsystem, or you will wind up with very long articles.  Maybe a link reminding the reader of session 0 isolation for services in Vista wouldn't be a bad idea, though.

    Wednesday, June 25, 2008 8:27 PM
  • My question about Global vs. Local was mostly rhetorical, allowing me to point out the difference between the 2.

    There have been some misconceptions about this before...

    In any case, there are only 2 scenarios where it makes a difference:

    * FUS: I'm not sure this is worth designing for. The actual usage of that feature is really small...

    * TS: Given the amount of effort that went into session isolation, global shared memory seems contradictory (it pretty much has to be writable by anyone. If it were only writable by the creator, and that creator logged off, there wouldn't be a writer anymore).

     

    Note that services don't need the SeCreateGlobalPrivilege, since they live in session 0 (the privilege only control cross-session named object creation).

     

    Even though I haven't tried it, one workaround might be a per-session local mapping to a single file.

     

    Wednesday, June 25, 2008 10:21 PM
  • Hi,

     

    I am seeing an apparently different behaviour on Windows Server 2008. My scenario:

    - I have a service running under account A. The service creates a global shared memory object.

    - I have an application that must access the same global shared memory object.

    - Of course, if I log in as Administrator and start the application, everything works fine.

    - If I log in as user A and start the application, the call to CreateFileMapping() fails with ERROR_ACCESS_DENIED.

    - I have assigned the 'Create global objects' right to account A, using the Local Security Policy applet.

    - I have tried specifying a NULL DACL in the CreateFileMapping() call - no effect.

    - I have tried setting a 'low integrity' SACL in the DACL in the CreateFileMapping() call - no effect.

     

    Code:

      SECURITY_ATTRIBUTES securityAttributes;
      char secDesc[SECURITY_DESCRIPTOR_MIN_LENGTH];
      securityAttributes.nLength = sizeof(securityAttributes);
      securityAttributes.bInheritHandle = FALSE;
      securityAttributes.lpSecurityDescriptor = &secDesc;
      InitializeSecurityDescriptor(securityAttributes.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
      SetSecurityDescriptorDacl(securityAttributes.lpSecurityDescriptor, TRUE, 0, FALSE);
    
      PSECURITY_DESCRIPTOR pSD;
      ConvertStringSecurityDescriptorToSecurityDescriptorA("S:(ML;;NW;;;LW)", // this means "low integrity"
                                SDDL_REVISION_1,
                                &pSD,
                                NULL);
      PACL pSacl = NULL;         // not allocated
      BOOL fSaclPresent = FALSE;
      BOOL fSaclDefaulted = FALSE;
      GetSecurityDescriptorSacl(pSD,
                   &fSaclPresent,
                   &pSacl,
                   &fSaclDefaulted);
      SetSecurityDescriptorSacl(securityAttributes.lpSecurityDescriptor, TRUE, pSacl, FALSE);
    
      string globalKey = string("Global\\") + _key;
      
      m_hFile = CreateFileMappingA(INVALID_HANDLE_VALUE,  // Create object in paging file
                    &securityAttributes,   // Allow everyone R/W access
                    PAGE_READWRITE,
                    0, _uiSize,       // Size (64-bit)
                    globalKey.c_str());
    
    

    Tuesday, January 4, 2011 11:01 AM