1

I have two Windows services that should share data with each other, and I intend to use SharedMemory (FileMapping) for such purpose. Another process is running in the user space that also should be able to read from that memory.

Well, the FileMapping is created in one service and can be accessed for read from both the "other service" and the user process. However, it would if the "other service" can also write to this memory (while locking against by a mutex, of course). But if I only try to use OpenFileMapping with FILE_MAP_WRITE from the "other service", ERROR_ACCESS_DENIED (5) is returned (FILE_MAP_READ works - of course). The same happens when I try to aquire the mutex.

I assume that there is something wrong with the SSDL string below, but I have no idea what I have to put in there. Can anyone help, please?

Service creates the FileMapping as follows (error checking ommitted for better read; you maybe have already seen party of them):

PSECURITY_DESCRIPTOR getSecurityDescriptor(const QString &sddl)
{    
    QString m_sddl = sddl;
    PSECURITY_DESCRIPTOR m_pSecDesc;

    if ((DWORD)(LOBYTE(LOWORD(GetVersion()))) >= 6)
    {
        // Found this - is this really required??
        m_sddl += "S:(ML;;NW;;;ME)";
    }

    if(!ConvertStringSecurityDescriptorToSecurityDescriptorW(
           (LPCWSTR)*m_sddl.utf16(), SDDL_REVISION_1, &m_pSecDesc, nullptr))
    {
        return nullptr;
    }

    return m_pSecDesc;
}

bool publishData(...)
{
    PSECURITY_DESCRIPTOR m_pSecDesc = getSecurityDescriptor("D:(A;;GR;;;AU)(A;;GA;;;LS)");

    if (!m_pSecDesc)
    { 
        ...
        return false;
    }

    SECURITY_ATTRIBUTES secAttr;
    secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    secAttr.lpSecurityDescriptor = m_pSecDesc;
    secAttr.bInheritHandle = false;

    // Ommitted: We also create a mutex "Global\\MyMutex" here with the same SECURITY_ATTRIBUTES...

    QString m_mapFileName = "Global\\MySharedMemory";
    m_hMapFile = CreateFileMappingW(INVALID_HANDLE_VALUE, &secAttr, PAGE_READWRITE,
                                    0, data.size(), (LPCWSTR)(m_mapFileName.utf16()));

    ...

The "other service" attempt to open it this way:

hMapFile = OpenFileMappingW(FILE_MAP_WRITE, false, L"Global\\MySharedMemory");

The same happens if i try to aquire the mutex mentoined above by:

hMutex = OpenMutexW(MUTEX_MODIFY_STATE, false, L"Global\\MyMutex");
...
DWORD ret = WaitForSingleObject(hMutex, 1000);  // -> ERROR_ACCESS_DENIED (5)
Gertsen
  • 1,078
  • 20
  • 36
Willy K.
  • 397
  • 2
  • 14
  • You're only giving write access to the `NT AUTHORITY\LocalService` account (aka LS). Is the other service configured to run in that account? (Use `sc qc myservice` on the command line and look for the line saying SERVICE_START_NAME.) – Harry Johnston Nov 23 '15 at 20:06
  • Thanks for your reply, Herry Johnston. "sc qc" tells me that both services are running as "LocalSystem". I tried with replacing "(A;;GA;;;SU)" and "(A;;GA;;;SY)", but stillt get ERROR_NO_SUCCESS, even when using "(A;;GA;;;WD)". – Willy K. Nov 24 '15 at 08:49
  • I can't find a definition for `ERROR_NO_SUCCESS` in MSDN or in the header files on my machine. What is the actual return value of WaitForSingleObject? If it is WAIT_FAILED (defined as -1) what does GetLastError() return? – Harry Johnston Nov 24 '15 at 19:09
  • But actually I think [this](http://stackoverflow.com/q/19049412/886887) is your problem - GA doesn't include SYNCHRONIZE, and there is no SDDL string for SYNCHRONIZE, so you have to use a hex mask instead. – Harry Johnston Nov 24 '15 at 19:14
  • Thank you very much, Harry Johnston. I had to find out the proper hex mask, but in the end that worked for me. My code above applied the same SSDL to both mutex and file mapping, it seems that this was no good idea :-). You may answer the question with your input if you want to, otherwise I do it for you on your behalf. As mentoined, I had to try around until I found the proper hex mask, is there any documention for such purpose (what do I need to set for mutex, file mapping events, ...)? P.S: Regarding ERROR_NO_ACCES -> I corrected thsi to ERROR_ACCESS_DENIED. Thanks. – Willy K. Nov 25 '15 at 17:56

1 Answers1

1

There are two problems here. One is that you're granting access to the wrong account, LS (local service) rather than SY (local system). This applies to both the mapping and the mutex.

The second applies only to the mutex: you must have SYNCHRONIZE access, and as discussed in this question there is no SDDL syntax for that. You will need to use a hex mask.

As discussed here and here and as you point out in the comments, you really do need to use different access masks for different types of object, unless you're sticking to the generic access rights (or know exactly what you're doing).

Access rights for various object types are described in the documentation concerning those objects. For example, access rights for mutex objects are described in Synchronization Object Security and Access Rights under the general heading About Synchronization. (If you need to convert to a bitmask, you can use the SDK header files to determine the bits corresponding to the various names.)

Community
  • 1
  • 1
Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
  • In addition to that: I needed to use MUTEX_ALL_ACCESS, even if I only attempt to aquire the mutex. MUTEX_MODIFY_STATE is "for future use" as per documentation. – Willy K. Nov 26 '15 at 18:12
  • I think you could probably cut it down a bit from MUTEX_ALL_ACCESS if you wanted to, but some trial and error would be required. – Harry Johnston Nov 26 '15 at 19:37