From patchwork Mon Feb 12 05:15:47 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joel Stanley X-Patchwork-Id: 127930 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp2879477ljc; Sun, 11 Feb 2018 21:18:21 -0800 (PST) X-Google-Smtp-Source: AH8x225sN0KEuioP5MJcqUvv5CUiYgSdtIvgPLQF2PfR9ec4gxFA05DRSt6f1Vna2d/Rsny5Y2SN X-Received: by 2002:a17:902:fa2:: with SMTP id 31-v6mr10046338plz.346.1518412701478; Sun, 11 Feb 2018 21:18:21 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518412701; cv=none; d=google.com; s=arc-20160816; b=q8gMyGQXjdsIQiiTckR+RX/7Qy/ZckXghgOljR4OwdcJ6vZHxMDSaUUmnRWvbwCSPh gCv+4YVQnMkXvB80DbnIyiSkciXCU5fUSqZg3Hyrv+ehggHKu53PzA7+R1/RJQuVZkpR Bd1qZO4gYSqZjyDeDObswr2pfsfYwhx4uLLh7JRpNmTb/YZqNioKqEZyLhK/vb/SSFwo MhfCUEP23UiK83+QSEBKo7XU3ukDBsoUW9691Z7up9c6S7SKzUgl9spmt2z7i2tul2w+ TQQrlRcITLlX4ZWHM9zNMkdu68jy3wxSIaR8Eb01qYK5/gHA4JO1A3x30C2V0nj4VCJf 8KIw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=B7eddgQ2fGlz7MNVOtGON1OIZLIyyZdsrEn1FPOB0qQ=; b=DtcQ+FqGuRMXxJOFP5Bq0XEDpN6H1XSKCvdvH+NHOldC6fHs9wq5EqJQdsuWur2TPx thMDMAVIc6TtaI1i+D8teRnBo7CF8AwXeIarfr8v6PFKRpRoI5mPuokvn1qgzm2nesop zMqPZjBo4QpF5Ekl4DXG0XowCObMzIHLuyDBspmT1soR0alnDq/ogeakIZHiUrvbxC0D VhexbCU2EiAAOodQrgRBl+cLgJ74rMwCPpvUoHvaUZFhhQu9+mAJbrfaY3DhmjmT8+Nv s+tzOgf+o2eH1U7cVA1cGAkL0fUGIBYgSeqX18o1P3/p/CWNktWl/Per/rk1xXXr4BMm j9rQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20161025 header.b=pJ+Oa51r; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 62-v6si5382074ple.267.2018.02.11.21.18.21; Sun, 11 Feb 2018 21:18:21 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com header.s=20161025 header.b=pJ+Oa51r; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932788AbeBLFSR (ORCPT + 13 others); Mon, 12 Feb 2018 00:18:17 -0500 Received: from mail-pg0-f65.google.com ([74.125.83.65]:42924 "EHLO mail-pg0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932648AbeBLFRT (ORCPT ); Mon, 12 Feb 2018 00:17:19 -0500 Received: by mail-pg0-f65.google.com with SMTP id m28so6816161pgc.9; Sun, 11 Feb 2018 21:17:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=B7eddgQ2fGlz7MNVOtGON1OIZLIyyZdsrEn1FPOB0qQ=; b=pJ+Oa51rZ4gmrw/mYkqIIgEAtQ1h0HsE05QKKDqAwhc1YSQgx45wBzJsBY4DKFFl3S CjobH4aXBS6BZuhaZNJtOLaX4LTBRTJYaOBP6yriN/3ahlx5wBv/wF4MiuAcgwu0mOgw mGdJIrGMT4dc23SMur9OHPhFMwzRBAUldu/P7fW6nJ/FjzRE526sUNFyT/KZ6mqoJyVd /iSMT9mntGsDMwT3JdzS0eVl6YkO2hDxkGbibf3F6J6zx11CzI3PAx9kFmpIwHwX2Dda 9pU+J1MgI0wZJ5Ca2nhSvUjeW0ra6AYCE4SKJd5p2Z7Rh6VQwms5U7F4ChFuNXeUyc5o Z8uw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=B7eddgQ2fGlz7MNVOtGON1OIZLIyyZdsrEn1FPOB0qQ=; b=HXG8U7BXThamwtvDQFY6592fTIsE37BKKmMxntrhwJ6IXmiawEUCTVc6eLz78Owb1V RzV7sTtEGTt8PfcCoStJRq7txmcx1rAK9Djo9Vnun1NH32/GSze4VTq5EYNpn9VJeH0l DhPv++6VHH9K35apPkBVEqi/Fd0gRiYY1YGBMjeQ/kASst0rGAKUyUrFijaOJfslw9qu EZuy1Go45OdeN9i7DDASJv57w+ziHux+SyfRE9ZwPAVTuzraaqudOPHAyeLgkeMgfPVr qqDOylmiZLOmKeZM3lb6r60XDsKXqKJiFmm857tbWRQI6vVZUQF5ND0vXl6xBlxZzwu6 Hkag== X-Gm-Message-State: APf1xPDmaMhaMH+qJbvhB0ney61624vhibUqbH6hOUVZR7Yxwt5rjRtp 01OsVsTSLEld+hmNnjmxLk2t6fR2 X-Received: by 10.101.81.197 with SMTP id i5mr8537431pgq.220.1518412638944; Sun, 11 Feb 2018 21:17:18 -0800 (PST) Received: from aurora.jms.id.au ([203.0.153.9]) by smtp.gmail.com with ESMTPSA id g15sm20444426pgu.52.2018.02.11.21.17.14 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sun, 11 Feb 2018 21:17:18 -0800 (PST) Received: by aurora.jms.id.au (sSMTP sendmail emulation); Mon, 12 Feb 2018 15:47:11 +1030 From: Joel Stanley To: Greg Kroah-Hartman , Rob Herring , Mark Rutland Cc: Jeremy Kerr , Christopher Bostic , Brad Bishop , Edward James , linux-kernel@vger.kernel.org, devicetree@vger.kernel.org Subject: [PATCH 08/10] fsi: master: Clarify master lifetimes & fix use-after-free in hub master Date: Mon, 12 Feb 2018 15:45:47 +1030 Message-Id: <20180212051549.8575-9-joel@jms.id.au> X-Mailer: git-send-email 2.15.1 In-Reply-To: <20180212051549.8575-1-joel@jms.id.au> References: <20180212051549.8575-1-joel@jms.id.au> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Jeremy Kerr Once we call fsi_master_unregister, the core will put_device, potentially freeing the hub master. This change adds a comment explaining the lifetime of an allocated fsi_master. We then add a reference from the driver to the hub master, so it stays around until we've finished ->remove(). Signed-off-by: Jeremy Kerr Tested-by: Christopher Bostic Signed-off-by: Joel Stanley --- drivers/fsi/fsi-master-hub.c | 21 ++++++++++++++++++--- drivers/fsi/fsi-master.h | 15 +++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) -- 2.15.1 diff --git a/drivers/fsi/fsi-master-hub.c b/drivers/fsi/fsi-master-hub.c index 5e4cd3134bc0..5885fc4a1ef0 100644 --- a/drivers/fsi/fsi-master-hub.c +++ b/drivers/fsi/fsi-master-hub.c @@ -288,10 +288,19 @@ static int hub_master_probe(struct device *dev) hub_master_init(hub); rc = fsi_master_register(&hub->master); - if (!rc) - return 0; + if (rc) + goto err_release; + + /* At this point, fsi_master_register performs the device_initialize(), + * and holds the sole reference on master.dev. This means the device + * will be freed (via ->release) during any subsequent call to + * fsi_master_unregister. We add our own reference to it here, so we + * can perform cleanup (in _remove()) without it being freed before + * we're ready. + */ + get_device(&hub->master.dev); + return 0; - kfree(hub); err_release: fsi_slave_release_range(fsi_dev->slave, FSI_HUB_LINK_OFFSET, FSI_HUB_LINK_SIZE * links); @@ -306,6 +315,12 @@ static int hub_master_remove(struct device *dev) fsi_slave_release_range(hub->upstream->slave, hub->addr, hub->size); of_node_put(hub->master.dev.of_node); + /* + * master.dev will likely be ->release()ed after this, which free()s + * the hub + */ + put_device(&hub->master.dev); + return 0; } diff --git a/drivers/fsi/fsi-master.h b/drivers/fsi/fsi-master.h index 18bd4ad79356..ee0b46086026 100644 --- a/drivers/fsi/fsi-master.h +++ b/drivers/fsi/fsi-master.h @@ -37,6 +37,21 @@ struct fsi_master { #define dev_to_fsi_master(d) container_of(d, struct fsi_master, dev) +/** + * fsi_master registration & lifetime: the fsi_master_register() and + * fsi_master_unregister() functions will take ownership of the master, and + * ->dev in particular. The registration path performs a get_device(), which + * takes the first reference on the device. Similarly, the unregistration path + * performs a put_device(), which may well drop the last reference. + * + * This means that master implementations *may* need to hold their own + * reference (via get_device()) on master->dev. In particular, if the device's + * ->release callback frees the fsi_master, then fsi_master_unregister will + * invoke this free if no other reference is held. + * + * The same applies for the error path of fsi_master_register; if the call + * fails, dev->release will have been invoked. + */ extern int fsi_master_register(struct fsi_master *master); extern void fsi_master_unregister(struct fsi_master *master);