On 09/17/2015 07:08 AM, Michael Stefaniuc wrote:
Did you look at memfd as opposed to plain share memory and how that can simplify your memory corruption problem? I know that Michael Müller worked on that and proof of concept code is available, see https://github.com/wine-compholio/wine-staging/tree/master/patches/server-Sh...
I've gotten a bit behind and wasn't aware of create_memfd, so I've had to study up on this -- very interesting (found a nice LWN article https://lwn.net/Articles/593918). Also, I wish that each patch set in staging had a README so that I wouldn't have to analyze the whole patch set to figure out its purpose and theory of operation. This patch set is actually very exciting to me because it addresses some of the biggest problems with excessive wineserver call problems that I've seen in profiling (e.g., PeekMessage & GetForegroundWindow.). However, I still don't quite understand what memfd is buying in this case as opposed to just an mmap with MAP_ANONYMOUS. Please enlighten me if I'm missing something, but does create_memfd and sealing with SEAL_SHRINK & SEAL_GROW just prevent clients from being able to change the size of the underlying file? It looks like it's still writable and still up to the client to mmap it as read-only. I actually haven't gotten to play with the low level bits of shared memory too much yet. (any good reading material on this topic welcomed! :)
Anyway, in this case it looks like we're using the TEB's Reserved5[0] to point to a global share memory region and Reserved5[1] for a thread-specific one, but they are both mmaped read-only. I know that in this thread we've discussed a lot of different design ideas, but what I'm specifically discussing in *this* (most recent) proposal is read/write memory that both wineserver and clients can perform atomic operations on and that client threads and processes can futex each other with. As such, a rogue process can corrupt it. The concept here is a.) limiting the scope of possible corruption to other processes that are already sharing objects anyway (and would very likely be susceptible to the same corruption problems on windows as well) and b.) assuring that the wineserver is able to positively identify misuse of objects in this shared memory.
The basic concept for this is that each client will keep track of changes it has made to an object with a simple (32 or 64 bit) audit value -- e.g., for each time it releases a semaphore, it will add one to it, each time it completes a wait it will subtract one. The wineserver will periodically flip a bit in the shared portion of a synchronization object using an atomic fetch-and-add operation. Clients performing subsequent operations will then begin to log to an alternate buffer. The server will then request each processes' total change count for the last audit period. By adding them all together with the value of the object in the previous audit cycle, the server can verify that the memory has not been corrupted. If it has, it can simply emit an error message to the console, mark the object as "bad" and fail all subsequent and in-process operations on it (waits return WAIT_FAILED with an appropriate last error).
Daniel