linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Bart Van Assche <bvanassche@acm.org>
To: Peter Zijlstra <peterz@infradead.org>
Cc: mingo@redhat.com, tj@kernel.org, longman@redhat.com,
	johannes.berg@intel.com, linux-kernel@vger.kernel.org,
	Paul McKenney <paulmck@linux.vnet.ibm.com>
Subject: Re: [PATCH v6 00/16] locking/lockdep: Add support for dynamic keys
Date: Fri, 18 Jan 2019 18:34:20 -0800	[thread overview]
Message-ID: <1250147c-27bc-92e1-3ff5-211f3ba56891@acm.org> (raw)
In-Reply-To: <20190118094808.GA27931@hirez.programming.kicks-ass.net>

On 1/18/19 1:48 AM, Peter Zijlstra wrote:
> On Mon, Jan 14, 2019 at 08:52:33AM -0800, Bart Van Assche wrote:
>> On Mon, 2019-01-14 at 13:52 +0100, Peter Zijlstra wrote:
>>> On Fri, Jan 11, 2019 at 09:01:41AM -0800, Bart Van Assche wrote:
>>>> The list_del_rcu() call must only happen once.
>>>
>>> Yes; obviously. But if we need to check all @pf's, that means the entry
>>> is still reachable after a single reset_lock()/free_key_range(), which
>>> is a bug.
>>>
>>>> I ran into complaints reporting that
>>>> the list_del_rcu() call triggered list corruption. This change made these complaints
>>>> disappear.
>>>
>>> I'm saying this solution buggy, because that means the entry is still
>>> reachable after we do call_rcu() (which is a straight up UAF).
>>>
>>> Also put it differently, what guarantees checking those two @pf's is
>>> sufficient. Suppose your earlier @pf already did the RCU callback and
>>> freed stuff while the second is in progress. Then you're poking into
>>> dead space.
>>
>> zap_class() only examines elements of the list_entries[] array for which the
>> corresponding bit in list_entries_in_use has been set. The RCU callback clears
>> the bits in the list_entries_in_use that correspond to elements that have been
>> freed. The graph lock serializes zap_class() calls and the code inside the
>> RCU callback. So it's not clear to me why you are claiming that zap_class()
>> would trigger a use-after-free?
> 
> The scenario is like:
> 
> 
> CPU0					CPU1					CPU2
> 
> lockdep_reset_lock_reg()
>    pf = get_pending_free_lock() // pf[0]
>    __lockdep_reset_lock(pf)
>      zap_class()
>    schedule_free_zapped_classes(pf)
>      call_rcu()
> 
> 
>    // here is wbere the objects 'freed' in zap_class()
>    // can still be used through references obtained
>    // __before__ we did call_rcu().
> 
> 
> 					lockdep_reset_lock_reg()
> 					  pf = get_pending_free_lock() // pf[1]
> 					  __lockdep_reset_lock(pf)
> 					    zap_class()
> 					      list_entry_being_freed()
> 						// checks: pf[0]
> 
> 						// this is a problem, it
> 						// should _NEVER_ match
> 						// anything from pf[0]
> 
> 						// those entries should
> 						// be unreachable,
> 						// otherwise:
> 
> 
> 										rcu_read_lock()
> 										entry = rcu_dereference()
> 
> <rcu-callback>
>    free_zapped_classes()
> 
> 										entry->class // UAF, just freed by rcu-callback
> 
> 										rcu_read_unlock()
> 
> 
> 
> 
> Now, arguably, I'm having a really hard time actually finding the RCU user of
> lock_list::entry, the comment in add_lock_to_list() seems to mention
> look_up_lock_class(), but the only RCU usage there is the
> lock_class::hash_entry, not lock_list::entry.
> 
> If lock_class is not indeed RCU used, that would simplify things. Please
> double check.
> 
> But in any case, the normal RCU pattern is:
> 
> lock()
> add-to-data-structure()
> unlock()
> 
> 				rcu_read_lock()
> 				obj = obtain-from-data-structure();
> 
> lock()
> remove-from-data-structure()
>    call_rcu()
> unlock();
> 
> 				use(obj);
> 				rcu_read_unlock();
> 
> 
> <rcu-callback>
>    actually-free-obj()
> 
> 
> 
> Fundamentally RCU delays the callback to the point where the last observer
> that started before call_rcu() has finished and no later (in practise it often
> is much later, but no guarantees there). So being able to reach an object
> after you did call_rcu() on it is a fundamental fail.

Hi Peter,

I agree with what you wrote. The only code I know of that accesses list
entries using RCU is the __bfs() function. In that function I found the
following loop:

	list_for_each_entry_rcu(entry, head, entry) { [ ... ] }

Since zap_class() calls list_del_rcu(&entry->entry), since a grace period
occurs between the call_rcu() invocation and the RCU callback function,
since at least an RCU reader lock must be held around RCU loops and since
sleeping is not allowed while holding an RCU read lock I think there is
no risk that __bfs() will examine a list entry after it has been freed.

Bart.

  reply	other threads:[~2019-01-19  2:34 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-01-09 21:01 [PATCH v6 00/16] locking/lockdep: Add support for dynamic keys Bart Van Assche
2019-01-09 21:01 ` [PATCH v6 01/16] locking/lockdep: Fix reported required memory size Bart Van Assche
2019-01-09 21:01 ` [PATCH v6 02/16] locking/lockdep: Avoid that add_chain_cache() adds an invalid chain to the cache Bart Van Assche
2019-01-09 21:01 ` [PATCH v6 03/16] locking/lockdep: Make zap_class() remove all matching lock order entries Bart Van Assche
2019-01-09 21:01 ` [PATCH v6 04/16] locking/lockdep: Reorder struct lock_class members Bart Van Assche
2019-01-09 21:01 ` [PATCH v6 05/16] locking/lockdep: Initialize the locks_before and locks_after lists earlier Bart Van Assche
2019-01-09 21:01 ` [PATCH v6 06/16] locking/lockdep: Split lockdep_free_key_range() and lockdep_reset_lock() Bart Van Assche
2019-01-09 21:01 ` [PATCH v6 07/16] locking/lockdep: Make it easy to detect whether or not inside a selftest Bart Van Assche
2019-01-09 21:01 ` [PATCH v6 08/16] locking/lockdep: Free lock classes that are no longer in use Bart Van Assche
2019-01-09 21:01 ` [PATCH v6 09/16] locking/lockdep: Reuse list entries " Bart Van Assche
2019-01-09 21:01 ` [PATCH v6 10/16] locking/lockdep: Introduce lockdep_next_lockchain() and lock_chain_count() Bart Van Assche
2019-01-09 21:01 ` [PATCH v6 11/16] locking/lockdep: Reuse lock chains that have been freed Bart Van Assche
2019-01-09 21:02 ` [PATCH v6 12/16] locking/lockdep: Check data structure consistency Bart Van Assche
2019-01-09 21:02 ` [PATCH v6 13/16] locking/lockdep: Verify whether lock objects are small enough to be used as class keys Bart Van Assche
2019-01-09 21:02 ` [PATCH v6 14/16] locking/lockdep: Add support for dynamic keys Bart Van Assche
2019-01-09 21:02 ` [PATCH v6 15/16] kernel/workqueue: Use dynamic lockdep keys for workqueues Bart Van Assche
2019-01-09 21:02 ` [PATCH v6 16/16] lockdep tests: Test dynamic key registration Bart Van Assche
2019-01-11 12:48 ` [PATCH v6 00/16] locking/lockdep: Add support for dynamic keys Peter Zijlstra
2019-01-11 15:55   ` Bart Van Assche
2019-01-11 16:55     ` Peter Zijlstra
2019-01-11 17:01       ` Bart Van Assche
2019-01-14 12:52         ` Peter Zijlstra
2019-01-14 16:52           ` Bart Van Assche
2019-01-18  9:48             ` Peter Zijlstra
2019-01-19  2:34               ` Bart Van Assche [this message]
2019-02-01 12:15                 ` Peter Zijlstra
2019-02-03 17:36                   ` Bart Van Assche
2019-02-08 11:43                     ` Will Deacon
2019-02-08 16:31                       ` Bart Van Assche
2019-02-13 22:32                       ` Bart Van Assche

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1250147c-27bc-92e1-3ff5-211f3ba56891@acm.org \
    --to=bvanassche@acm.org \
    --cc=johannes.berg@intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=longman@redhat.com \
    --cc=mingo@redhat.com \
    --cc=paulmck@linux.vnet.ibm.com \
    --cc=peterz@infradead.org \
    --cc=tj@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).