Optimizing synchronization objects

Daniel Santos daniel.santos at pobox.com
Thu Sep 17 17:59:31 CDT 2015


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-Shared_Memory

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



More information about the wine-devel mailing list