lkml.org 
[lkml]   [2019]   [Aug]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.2 162/162] rxrpc: Fix read-after-free in rxrpc_queue_local()
    Date
    From: David Howells <dhowells@redhat.com>

    commit 06d9532fa6b34f12a6d75711162d47c17c1add72 upstream.

    rxrpc_queue_local() attempts to queue the local endpoint it is given and
    then, if successful, prints a trace line. The trace line includes the
    current usage count - but we're not allowed to look at the local endpoint
    at this point as we passed our ref on it to the workqueue.

    Fix this by reading the usage count before queuing the work item.

    Also fix the reading of local->debug_id for trace lines, which must be done
    with the same consideration as reading the usage count.

    Fixes: 09d2bf595db4 ("rxrpc: Add a tracepoint to track rxrpc_local refcounting")
    Reported-by: syzbot+78e71c5bab4f76a6a719@syzkaller.appspotmail.com
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    include/trace/events/rxrpc.h | 6 +++---
    net/rxrpc/local_object.c | 19 ++++++++++---------
    2 files changed, 13 insertions(+), 12 deletions(-)

    --- a/include/trace/events/rxrpc.h
    +++ b/include/trace/events/rxrpc.h
    @@ -498,10 +498,10 @@ rxrpc_tx_points;
    #define E_(a, b) { a, b }

    TRACE_EVENT(rxrpc_local,
    - TP_PROTO(struct rxrpc_local *local, enum rxrpc_local_trace op,
    + TP_PROTO(unsigned int local_debug_id, enum rxrpc_local_trace op,
    int usage, const void *where),

    - TP_ARGS(local, op, usage, where),
    + TP_ARGS(local_debug_id, op, usage, where),

    TP_STRUCT__entry(
    __field(unsigned int, local )
    @@ -511,7 +511,7 @@ TRACE_EVENT(rxrpc_local,
    ),

    TP_fast_assign(
    - __entry->local = local->debug_id;
    + __entry->local = local_debug_id;
    __entry->op = op;
    __entry->usage = usage;
    __entry->where = where;
    --- a/net/rxrpc/local_object.c
    +++ b/net/rxrpc/local_object.c
    @@ -93,7 +93,7 @@ static struct rxrpc_local *rxrpc_alloc_l
    local->debug_id = atomic_inc_return(&rxrpc_debug_id);
    memcpy(&local->srx, srx, sizeof(*srx));
    local->srx.srx_service = 0;
    - trace_rxrpc_local(local, rxrpc_local_new, 1, NULL);
    + trace_rxrpc_local(local->debug_id, rxrpc_local_new, 1, NULL);
    }

    _leave(" = %p", local);
    @@ -321,7 +321,7 @@ struct rxrpc_local *rxrpc_get_local(stru
    int n;

    n = atomic_inc_return(&local->usage);
    - trace_rxrpc_local(local, rxrpc_local_got, n, here);
    + trace_rxrpc_local(local->debug_id, rxrpc_local_got, n, here);
    return local;
    }

    @@ -335,7 +335,8 @@ struct rxrpc_local *rxrpc_get_local_mayb
    if (local) {
    int n = atomic_fetch_add_unless(&local->usage, 1, 0);
    if (n > 0)
    - trace_rxrpc_local(local, rxrpc_local_got, n + 1, here);
    + trace_rxrpc_local(local->debug_id, rxrpc_local_got,
    + n + 1, here);
    else
    local = NULL;
    }
    @@ -343,16 +344,16 @@ struct rxrpc_local *rxrpc_get_local_mayb
    }

    /*
    - * Queue a local endpoint unless it has become unreferenced and pass the
    - * caller's reference to the work item.
    + * Queue a local endpoint and pass the caller's reference to the work item.
    */
    void rxrpc_queue_local(struct rxrpc_local *local)
    {
    const void *here = __builtin_return_address(0);
    + unsigned int debug_id = local->debug_id;
    + int n = atomic_read(&local->usage);

    if (rxrpc_queue_work(&local->processor))
    - trace_rxrpc_local(local, rxrpc_local_queued,
    - atomic_read(&local->usage), here);
    + trace_rxrpc_local(debug_id, rxrpc_local_queued, n, here);
    else
    rxrpc_put_local(local);
    }
    @@ -367,7 +368,7 @@ void rxrpc_put_local(struct rxrpc_local

    if (local) {
    n = atomic_dec_return(&local->usage);
    - trace_rxrpc_local(local, rxrpc_local_put, n, here);
    + trace_rxrpc_local(local->debug_id, rxrpc_local_put, n, here);

    if (n == 0)
    call_rcu(&local->rcu, rxrpc_local_rcu);
    @@ -454,7 +455,7 @@ static void rxrpc_local_processor(struct
    container_of(work, struct rxrpc_local, processor);
    bool again;

    - trace_rxrpc_local(local, rxrpc_local_processing,
    + trace_rxrpc_local(local->debug_id, rxrpc_local_processing,
    atomic_read(&local->usage), NULL);

    do {

    \
     
     \ /
      Last update: 2019-08-27 10:07    [W:4.088 / U:0.136 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site