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