From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758054AbdELP3o convert rfc822-to-8bit (ORCPT ); Fri, 12 May 2017 11:29:44 -0400 Received: from mx1.redhat.com ([209.132.183.28]:33652 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757997AbdELP3m (ORCPT ); Fri, 12 May 2017 11:29:42 -0400 DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 8EB7FC059756 Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=dhowells@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 8EB7FC059756 Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 From: David Howells In-Reply-To: <20170512140023.GA18818@leverpostej> References: <20170512140023.GA18818@leverpostej> To: Mark Rutland Cc: dhowells@redhat.com, linux-kernel@vger.kernel.org, Elena Reshetova , keyrings@vger.kernel.org, Kees Cook , Hans Liljestrand , David Windsor , James Morris , Peter Zijlstra , Ingo Molnar Subject: Re: next-20170510 refcount_inc() on zero / use-after-free in key_lookup() MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-ID: <1264.1494602978.1@warthog.procyon.org.uk> Content-Transfer-Encoding: 8BIT Date: Fri, 12 May 2017 16:29:39 +0100 Message-ID: <1265.1494602979@warthog.procyon.org.uk> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Fri, 12 May 2017 15:29:41 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Mark Rutland wrote: > From a quick look at key_lookup(), the following looks very suspicious: > > found: > /* pretend it doesn't exist if it is awaiting deletion */ > if (refcount_read(&key->usage) == 0) > goto not_found; > > /* this races with key_put(), but that doesn't matter since key_put() > * doesn't actually change the key > */ > __key_get(key); > > ... as if we can race with key_put(), we can see a zero refcount here, > and the race *does* matter. No, it doesn't. If key_put() reduces a refcount to 0, it doesn't do anything other than poke the gc thread: void key_put(struct key *key) { if (key) { key_check(key); if (refcount_dec_and_test(&key->usage)) schedule_work(&key_gc_work); } } in particular, no indication of the reduced key is passed. The gc thread scans the entire key serial tree under the key_serial_lock looking for keys that are no longer ref'd. No one else is allowed to remove keys from the tree. This means that the gc thread can safely leave a cursor pointing into the midst of the tree with no locks held whilst it yields to the scheduler. The code you quoted above in key_lookup() is inside the key_serial_lock, so it prevents the gc thread from culling a key when it resurrects it. So the problem isn't the key code, it's the refcount code. As I've said before, the refcount code needs an increment op that permits inc-from-0. In this case, it's perfectly okay. David