• Shawn Bohrer's avatar
    futex: Fix regression with read only mappings · 9ea71503
    Shawn Bohrer authored
    commit 7485d0d3 (futexes: Remove rw
    parameter from get_futex_key()) in 2.6.33 fixed two problems:  First, It
    prevented a loop when encountering a ZERO_PAGE. Second, it fixed RW
    MAP_PRIVATE futex operations by forcing the COW to occur by
    unconditionally performing a write access get_user_pages_fast() to get
    the page.  The commit also introduced a user-mode regression in that it
    broke futex operations on read-only memory maps.  For example, this
    breaks workloads that have one or more reader processes doing a
    FUTEX_WAIT on a futex within a read only shared file mapping, and a
    writer processes that has a writable mapping issuing the FUTEX_WAKE.
    
    This fixes the regression for valid futex operations on RO mappings by
    trying a RO get_user_pages_fast() when the RW get_user_pages_fast()
    fails. This change makes it necessary to also check for invalid use
    cases, such as anonymous RO mappings (which can never change) and the
    ZERO_PAGE which the commit referenced above was written to address.
    
    This patch does restore the original behavior with RO MAP_PRIVATE
    mappings, which have inherent user-mode usage problems and don't really
    make sense.  With this patch performing a FUTEX_WAIT within a RO
    MAP_PRIVATE mapping will be successfully woken provided another process
    updates the region of the underlying mapped file.  However, the mmap()
    man page states that for a MAP_PRIVATE mapping:
    
      It is unspecified whether changes made to the file after
      the mmap() call are visible in the mapped region.
    
    So user-mode users attempting to use futex operations on RO MAP_PRIVATE
    mappings are depending on unspecified behavior.  Additionally a
    RO MAP_PRIVATE mapping could fail to wake up in the following case.
    
      Thread-A: call futex(FUTEX_WAIT, memory-region-A).
                get_futex_key() return inode based key.
                sleep on the key
      Thread-B: call mprotect(PROT_READ|PROT_WRITE, memory-region-A)
      Thread-B: write memory-region-A.
                COW happen. This process's memory-region-A become related
                to new COWed private (ie PageAnon=1) page.
      Thread-B: call futex(FUETX_WAKE, memory-region-A).
                get_futex_key() return mm based key.
                IOW, we fail to wake up Thread-A.
    
    Once again doing something like this is just silly and users who do
    something like this get what they deserve.
    
    While RO MAP_PRIVATE mappings are nonsensical, checking for a private
    mapping requires walking the vmas and was deemed too costly to avoid a
    userspace hang.
    
    This Patch is based on Peter Zijlstra's initial patch with modifications to
    only allow RO mappings for futex operations that need VERIFY_READ access.
    Reported-by: default avatarDavid Oliver <david@rgmadvisors.com>
    Signed-off-by: default avatarShawn Bohrer <sbohrer@rgmadvisors.com>
    Acked-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
    Signed-off-by: default avatarDarren Hart <dvhart@linux.intel.com>
    Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
    Cc: peterz@infradead.org
    Cc: eric.dumazet@gmail.com
    Cc: zvonler@rgmadvisors.com
    Cc: hughd@google.com
    Link: http://lkml.kernel.org/r/1309450892-30676-1-git-send-email-sbohrer@rgmadvisors.com
    Cc: stable@kernel.org
    Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
    9ea71503
futex.c 70.6 KB