I'm looking for a possibility to create a shared memory block on Windows platforms that is write-protected for all processes except for the process that created the shared memory block.
In detail I need the following:
Process (1) has to create a shared memory block and should be able to modify the buffer.
Process (2) should be able to open and to read the created shared memory block but must not have permission to modify the content. This is important due to security/safty reasons.
Currently I have a solution creating a shared memory block using CreateFileMapping() together with MapViewOfFile() which then has read and write permission in process (1) and (2) like:
HANDLE handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, highSize, lowSize, L"uniquename");
void* sharedMemory = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
// now we can modify sharedMemory...
These two lines of code can be applied in both processes as the first process creates the shared memory block and the second process simply opens the shared memory.
However, obviously the second process will have write permission due to the provided access values (PAGE_READWRITE and FILE_MAP_ALL_ACCESS) during creation of the memory block.
I would need to create the shared memory block in process (1) by using access values PAGE_READONLY and FILE_MAP_READ but obviously than I'm not allowed to initialize/set/modify the memory block in process (1) which than is a useless memory buffer.
To my best knowledge, the definition of security attributes can not solve the problem as my problem does not depend on users or groups.
I even would be happy with a solution which creates a shared memory block in process (1) relying on memory content that is known before the creation of the shared memory block (and which will not be modified in process (1) afterwards).
Do you trust process #2 to use FILE_MAP_READ? That will prevent accidental overwrites from e.g. wild pointers corrupting the shared memory.
If you're trying to protect against malicious overwrites, then you need to use the OS-provided security principals and run process #2 in a different session with lesser credentials. If process #2 runs under the same security credentials as process #1, then it can perform any operation process #1 can perform (for example, by injecting code into process #1).
(On Windows, users are security principals and processes are not. Users are not the only level of restriction, for example User Access Control in Vista and later creates tokens corresponding to an administrative user both with and without the Administrators group membership)
Since you say process #1 doesn't need continuing write access, only one time, you could create the mapping, map it for write, then adjust the ACL using SetSecurityInfo so that future accesses cannot write.
Another possibility is to instead map a disk file, and open it with FILE_SHARE_READ (but not FILE_SHARE_WRITE) access from the first process.
But neither of these prevent process #2 from coercing process #1 to make changes on its behalf. Only using separate tokens can prevent coercion.
You don't explain why you can't provide different arguments in each case, so I'm going to assume you don't know which process is the creator until you have the file open. In which case, you might want to try:
HANDLE h = OpenFileMapping(FILE_MAP_READ, /*args*/);
if (h) {
v = MapViewOfFile(h, FILE_MAP_READ, 0, 0, 0);
} else {
h = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, highSize, lowSize, L"uniquename");
if (!h)
FirePhotonTorpedoes();
v = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
}
The CreateFileMapping function allows you to set an ACL for the file mapping object. If you create an ACL that only allows read-only access, other processes should be unable to open the file mapping object with read-write access.
Typically, when creating an object, the permissions you assign don't apply to the handle you obtain during creation. However, I haven't tested this with CreateFileMapping in particular.
This only provides weak protection. A malicious process could change the permissions on the file mapping object, or inject code into the process that created the object.
Related
I have a shared library that hands out an integer handle to a client after a successful connection request. Something like:
int ConnectionRequest(const std::string& authorization_token);
Subsequent actions then need to use that handle to access further operations:
result DoOperation(int handle, const std::string& payload);
It occurred to me that a second client could hijack the connection simply by presenting a plausible handle value to the interface. How do I uniquely link the handle to the client that made the original request? Is there a way to get the process ID from the client and check against it?
Internally I use a std::map to link the handle to a shared_ptr object. All this is in user space.
Coding on linux in C++.
Both Linux and Windows have already solved this problem - you can look to their implementations for a working method.
In short, use multiple tables.
When referencing handles given out by the kernel, the system needs to ensure that a rogue process can't just steal your file handle and access your data. To do so, the system creates a per-process handle table that contains only the handles relevant to your process. If a rogue process steals one of your handles and tries to use it, they won't be able to access your data - the OS will index their handle table, and find either nothing, or one of their resources.
You can duplicate this behavior by looking up a handle table via process ID first, then look up the structure with the handle provided. If the process ID doesn't exist in the handle table map, return an error. Otherwise, run the function on the structure referenced by the handle if it exists.
I have a Windows service (running in the system process) and a desktop application that need to share a configuration structure. The data originates in the app, but the user process doesn't have permission to create a global memory object so I create it when the service starts using CreateFileMapping() and a DACL based on this answer. This appears to work fine: I get a non-null handle back from CreateFileMapping() and GetLastError() is 0. The problem is that the app can't see the object -- OpenFileMapping() returns a NULL handle and ERROR_FILE_NOT_FOUND -- and I also can't see it if I manually browse the global objects with WinObj. What's keeping my object from being visible?
SECURITY_ATTRIBUTES security;
ZeroMemory(&security, sizeof(security));
security.nLength = sizeof(security);
ConvertStringSecurityDescriptorToSecurityDescriptor(
"D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GWGR;;;IU)",
SDDL_REVISION_1,
&security.lpSecurityDescriptor,
NULL);
HANDLE hFile = CreateFileMapping(INVALID_HANDLE_VALUE, &security, PAGE_READWRITE, 0, 1024*4, "Global\\gCONFIGXFILE");
DWORD fileMappingResult = GetLastError();
if (hFile)
{
CloseHandle(hFile);
}
LocalFree(security.lpSecurityDescriptor);
Your service is closing its handle to the file mapping immediately after creating it, thus the mapping is being destroyed before the app has a chance to open its handle to the mapping. Your service needs to leave its handle to the mapping open, at least until after the app has opened its handle to the mapping.
Since you are sharing configuration, you should probably be creating the mapping at service start and leave it open until service stop. You could use a named event via CreateEvent() to let the service tell the app when the mapping has actually been created, and maybe use another named event whenever the content of the mapping is changed by either process.
I want to create a Windows mutex by using WinAPI, CreateMutex() and OpenMutex(). But for security concern, I want the mutex be opened by those processes who know the "password" or the hard-code magic code. I don't want the mutex be accessed by every processes.
For example,
Create mutex with name "Globel\cd689f00-0462-11e5-b939-0800200c9a66".
So only the process who know the mutex name can access this mutex. But this is not a good solution because you can simply use Winobj.exe and you still have some chance to find this mutex.
I want this mutex be protected by something like ACL (Access Control Lists). The problem is, I can't find a way to create my own SID for ACL.
Here is what I know and what I want:
1. I know I can make mutex be accessed by many process by naming it likes "Global\MyMutexName".
2. I also try to understand ACL and SID mentioned on MSDN. But I still can't find a way to create my own SID (maybe that doesn't make sense?).
3. I don't want to elevated my processes to Admin.
What you're trying to do isn't natural to the security model that Windows uses. Permissions are always granted based on who is running the executable, not on the executable itself. However, depending on your scenario, there may be suitable options.
If all of the processes involved will be in the context of the same user, then you can use IPC (e.g., named pipes) to identify your "friendly" processes and DuplicateHandle() to pass a handle to an unnamed mutex between processes.
If the processes must be in different user contexts, one option would be to have a system service running in a privileged context to act as a broker. Of course, that requires that the system service be installed with admin privilege, but this is usually acceptable; it only has to be done once.
If the application must be portable (no installation, or able to be installed without admin access) and must cross user boundaries then I think you would have to use IPC to implement your own mutex. Of course, that would be very inefficient.
Keep in mind that in any of these scenarios, a malicious user can still get access to the mutex - the best you can do is make it slightly more difficult. If you use an actual mutex, for example, the attacker could enumerate the handles of one of the processes, identify the mutex, and duplicate the handle. (Or simply inject malicious code into one of the supposedly "friendly" processes to use the handle directly.) Even the IPC could be spied upon and duplicated.
You should seriously consider whether the marginal security benefit is worth the significant increase in complexity. IMO, it isn't likely to be.
(The proper solution, by the way, is for a system service to do all the work that requires access to the mutex; the application that the users run would typically be a thin client that does nothing but provide the GUI.)
You'd let Windows create a new SID; don't try to create one yourself. With that SID, you can then build an ACL (Access Control List) which grants access to all processes holding that SID, and (implicitly) denies everyone else that right. This ACL can then be applied to the mutex, which protects it.
Now to get access, you'd need to create an impersonation token for that SID. If I understand MSDN, the process is to open your thread token, set the TokenUser via SetTokenInformation, and then apply the modified token via SetThreadToken.
This impersonation token is now used when checking the ACL of the mutex.
MSDN isn't entirely clear on the process of creating a valid user SID; it might be necessary to replace "User SID" with "Group SID" in the process above.
I am trying to use shared memory between user process and kernel.
Option one - to let kernel to create section and let user mode app to open memory by name "Global\my_mem". It's working only in read-only mode. When I am trying to open section with FILE_MAP_WRITE it gives access denied(5). Not sure how to grant access or modify DACL.
Option two - pass handle back via IOCTL. This one is questionable since handle to section opened in KERNEL is 0xFFFFFFFF80001234. My understanding that handles that have any of upper bits set can not be used in user mode. Especially if app will be 32-bit :) Initially I expected that section handle will be somewhat similar to kernel file handle and I will be able to use it.
What would be the correct approach to establish shared memory channel between kernel and user mode?
For option 1, you can specify the security descriptor assigned to the newly created object via the SecurityDescriptor member of the OBJECT_ATTRIBUTES structure.
For option 2, you would need to create an additional handle as a user handle, which you do by not specifying the OBJ_KERNEL_HANDLE flag in the OBJECT_ATTRIBUTES structure. This will only work if you open the new handle while running in the context of a thread belonging to the user application's process, e.g., while processing an IOCTL received from the user application.
Another option is for the kernel driver to map the section into the user-mode application's address space itself, using ZwMapViewOfSection.
One issue with using a section is that the driver itself can only safely access it from a system thread. If that is a problem, you can share memory directly rather than via a section. If you allocate the memory in kernel mode, you can map it into the user-mode application's address space using MmMapLockedPagesSpecifyCache.
Yet another option is for the driver to access a memory buffer allocated by the user-mode process.
The downside to either of these approaches is that the buffer (or the part of it being shared) must be locked in memory, whereas using a section allows the buffer to be pageable.
Since you referred to 32bit app, I assume it is between a user process and a device driver - I would go with IOCTL - METHOD_IN_DIRECT (receives data in the buffer) and METHOD_OUT_DIRECT (write data into the buffer).
If shared memory is between multiple user processes and one or more device drivers - using shared Memory Object method is recommended .
I have the list of kernel objects that I recieved from function NtQUeryDirectoryObject().
How can I get a security descriptor of this objects? I need read DACL of all this objects, but all attempts fail with error "acces is denied".
From MSDN GetSecurityInfo() remarks:
*To read the owner, group, or DACL from the object's security descriptor, the calling process must have been granted READ_CONTROL access when the handle was opened. To get READ_CONTROL access, the caller must be the owner of the object or the object's DACL must grant the access.*
Basically as I understand DACL is zero plus access control entries. Each of these have kinda table with SID and accesses denied or granted. Now, DACL is controlled by object's owner. Owner can definitely give others control(search MSDN for appropriate API), or i think other s can also set it by call to something like SetKernelObjectSecurity(forgot params..:))..
I think it will make a difference depending on 'what' kernel object you are dealing with. Also about DACL - research it being about empty and null.