lkml.org 
[lkml]   [2013]   [Jul]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[016/141] random: fix accounting race condition with lockless irq entropy_count update
    3.6.11.6 stable review patch.
    If anyone has any objections, please let me know.

    ------------------

    From: Jiri Kosina <jkosina@suse.cz>

    [ Upstream commit 10b3a32d292c21ea5b3ad5ca5975e88bb20b8d68 ]

    Commit 902c098a3663 ("random: use lockless techniques in the interrupt
    path") turned IRQ path from being spinlock protected into lockless
    cmpxchg-retry update.

    That commit removed r->lock serialization between crediting entropy bits
    from IRQ context and accounting when extracting entropy on userspace
    read path, but didn't turn the r->entropy_count reads/updates in
    account() to use cmpxchg as well.

    It has been observed, that under certain circumstances this leads to
    read() on /dev/urandom to return 0 (EOF), as r->entropy_count gets
    corrupted and becomes negative, which in turn results in propagating 0
    all the way from account() to the actual read() call.

    Convert the accounting code to be the proper lockless counterpart of
    what has been partially done by 902c098a3663.

    Signed-off-by: Jiri Kosina <jkosina@suse.cz>
    Cc: Theodore Ts'o <tytso@mit.edu>
    Cc: Greg KH <greg@kroah.com>
    Cc: <stable@vger.kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
    ---
    drivers/char/random.c | 24 ++++++++++++++++--------
    1 file changed, 16 insertions(+), 8 deletions(-)

    diff --git a/drivers/char/random.c b/drivers/char/random.c
    index b86eae9..35cfbb0 100644
    --- a/drivers/char/random.c
    +++ b/drivers/char/random.c
    @@ -867,16 +867,24 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
    if (r->entropy_count / 8 < min + reserved) {
    nbytes = 0;
    } else {
    + int entropy_count, orig;
    +retry:
    + entropy_count = orig = ACCESS_ONCE(r->entropy_count);
    /* If limited, never pull more than available */
    - if (r->limit && nbytes + reserved >= r->entropy_count / 8)
    - nbytes = r->entropy_count/8 - reserved;
    -
    - if (r->entropy_count / 8 >= nbytes + reserved)
    - r->entropy_count -= nbytes*8;
    - else
    - r->entropy_count = reserved;
    + if (r->limit && nbytes + reserved >= entropy_count / 8)
    + nbytes = entropy_count/8 - reserved;
    +
    + if (entropy_count / 8 >= nbytes + reserved) {
    + entropy_count -= nbytes*8;
    + if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
    + goto retry;
    + } else {
    + entropy_count = reserved;
    + if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
    + goto retry;
    + }

    - if (r->entropy_count < random_write_wakeup_thresh) {
    + if (entropy_count < random_write_wakeup_thresh) {
    wake_up_interruptible(&random_write_wait);
    kill_fasync(&fasync, SIGIO, POLL_OUT);
    }
    --
    1.7.10.4



    \
     
     \ /
      Last update: 2013-07-04 01:01    [W:5.130 / U:0.352 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site