Skip to content
  • Emilio G. Cota's avatar
    76b553b3
    qht: fix unlock-after-free segfault upon resizing · 76b553b3
    Emilio G. Cota authored
    
    
    The old map's bucket locks are being unlocked *after*
    that same old map has been passed to RCU for destruction.
    This is a bug that can cause a segfault, since there's
    no guarantee that the deletion will be deferred (e.g.
    there may be no concurrent readers).
    
    The segfault is easily triggered in RHEL6/CentOS6 with qht-test,
    particularly on a single-core system or by pinning qht-test
    to a single core.
    
    Fix it by unlocking the map's bucket locks right after having
    published the new map, and (crucially) before marking the map
    for deletion via call_rcu().
    
    While at it, expand qht_do_resize() to atomically do (1) a reset,
    (2) a resize, or (3) a reset+resize. This simplifies the calling
    code, since the new function (qht_do_resize_reset()) acquires
    and releases the buckets' locks.
    
    Note that no qht_do_reset inline is provided, since it would have
    no users--qht_reset() already performs a reset without taking
    ht->lock.
    
    Reported-by: default avatarPeter Maydell <peter.maydell@linaro.org>
    Reported-by: default avatarDaniel P. Berrange <berrange@redhat.com>
    Signed-off-by: default avatarEmilio G. Cota <cota@braap.org>
    Message-Id: <1475706880-10667-3-git-send-email-cota@braap.org>
    Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
    76b553b3
    qht: fix unlock-after-free segfault upon resizing
    Emilio G. Cota authored
    
    
    The old map's bucket locks are being unlocked *after*
    that same old map has been passed to RCU for destruction.
    This is a bug that can cause a segfault, since there's
    no guarantee that the deletion will be deferred (e.g.
    there may be no concurrent readers).
    
    The segfault is easily triggered in RHEL6/CentOS6 with qht-test,
    particularly on a single-core system or by pinning qht-test
    to a single core.
    
    Fix it by unlocking the map's bucket locks right after having
    published the new map, and (crucially) before marking the map
    for deletion via call_rcu().
    
    While at it, expand qht_do_resize() to atomically do (1) a reset,
    (2) a resize, or (3) a reset+resize. This simplifies the calling
    code, since the new function (qht_do_resize_reset()) acquires
    and releases the buckets' locks.
    
    Note that no qht_do_reset inline is provided, since it would have
    no users--qht_reset() already performs a reset without taking
    ht->lock.
    
    Reported-by: default avatarPeter Maydell <peter.maydell@linaro.org>
    Reported-by: default avatarDaniel P. Berrange <berrange@redhat.com>
    Signed-off-by: default avatarEmilio G. Cota <cota@braap.org>
    Message-Id: <1475706880-10667-3-git-send-email-cota@braap.org>
    Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Loading