Writing to Global Shared memory from an Application in Vista.

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




Answer this question

Writing to Global Shared memory from an Application in Vista.

  • MikeMorcilla

    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.



  • Mark The Archer Evans

    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.
  • meta_alucard

    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


  • ntsoo

    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.


  • rosakruten

    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.


  • Leonard Lee

    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.



  • Suganya Mahadevan

    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.


  • melkor

    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.
  • spshah

    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.



  • hrubesh

    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


  • james2887

    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



  • Jade Skaggs

    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.


  • Re2Porter

    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


  • Suwimol

    You're right. I stand corrected. I had never noticed the check for object type...
    Sorry about this.



  • Writing to Global Shared memory from an Application in Vista.