Received: by 2002:ac0:a5a6:0:0:0:0:0 with SMTP id m35-v6csp1832471imm; Mon, 3 Sep 2018 10:35:09 -0700 (PDT) X-Google-Smtp-Source: ANB0VdZdiJ9wO6ElsD8GR2FvZXS0Cv4q4TLJKWAbMaMClCQVstTIfQJ1yKLY8dB+S2DSzlhnOwH4 X-Received: by 2002:a63:e4b:: with SMTP id 11-v6mr26151399pgo.320.1535996109003; Mon, 03 Sep 2018 10:35:09 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1535996108; cv=none; d=google.com; s=arc-20160816; b=ybvkXdAJx35XGHkexT0LU3bxb0lhPcUMNOh69SKLHdS9E6iIj6SLdnUEUBpGPErSBV rgah113lW2YQEAw36FvqkwkSialS5+mC1RoirvrxMb0aflh187LFO8x6BzhbaTSHxOJg kLrVIlXsWl8ooacPrz7V6r+mISi1Ac2WznnIyBYnQflfkOgmIoQVLp2rmmWPvDXcC7KL iq+9alKUub7Pkn0ICdMwGaqGHgfIlEtP/CmJXDQu2Zjsv/jzsUkef6TrDhgOHkNEtxo/ 99sI0FcC3238W8hdA9tNEvmdfkwCZNIzMEIqNhxL74HpMtO52CljONhdTcCqKeOVitY0 B3hQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=Psa8eG9rvhxIGcza/1nLE4o1ZN1yBKeOHfMz5CtOFOY=; b=sQ9T3tGkiLijouVQBAa4VM4xMVu33+OCz/xYmQFVeS8fKS7sFDk6vvVyBowUdvCFPD lp1g0d9asqxGGP95L5tg3romihRk7hp7BNEl5pUKOjBN/5W3YfVV7RTDRwBgqJD0Tefy xAp4rO69WdY/W5mc7rHIQJNqkU0rMpwY5ihdxneHyYnVGH8wya9Oq0168mMZ6i1+3w3g bp8OQLHYRn+EENZQmGwf1RDxmtzAiEGLCzd+T/y0xv+AY3jqU+be+wLqpQI3BTVxlcFd bfZ5S2gqjHOCePACt+XnIrBp9myfoiSukj8BOQQ8gOmSTCOQWP9ju9vulRcRBEQRbOho enIA== ARC-Authentication-Results: i=1; mx.google.com; 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 k18-v6si18588755pgm.102.2018.09.03.10.34.53; Mon, 03 Sep 2018 10:35:08 -0700 (PDT) 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; 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 S1731287AbeICVyU (ORCPT + 99 others); Mon, 3 Sep 2018 17:54:20 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:47624 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728253AbeICVyU (ORCPT ); Mon, 3 Sep 2018 17:54:20 -0400 Received: from localhost (ip-213-127-74-90.ip.prioritytelecom.net [213.127.74.90]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id 289DAD18; Mon, 3 Sep 2018 17:33:09 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Jason Yan , John Garry , Taras Kondratiuk , Tejun Heo , "Martin K. Petersen" Subject: [PATCH 4.18 003/123] scsi: libsas: dynamically allocate and free ata host Date: Mon, 3 Sep 2018 18:55:47 +0200 Message-Id: <20180903165719.635976039@linuxfoundation.org> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180903165719.499675257@linuxfoundation.org> References: <20180903165719.499675257@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.18-stable review patch. If anyone has any objections, please let me know. ------------------ From: Jason Yan commit 2fa4a32613c9182b00e46872755b0662374424a7 upstream. Commit 2623c7a5f2 ("libata: add refcounting to ata_host") v4.17+ introduced refcounting to ata_host and will increase or decrease the refcount when adding or deleting transport ATA port. Now the ata host for libsas is embedded in domain_device, and the ->kref member is not initialized. Afer we add ata transport class, ata_host_get() will be called when adding transport ATA port and a warning will be triggered as below: refcount_t: increment on 0; use-after-free. WARNING: CPU: 2 PID: 103 at lib/refcount.c:153 refcount_inc+0x40/0x48 ...... Call trace: refcount_inc+0x40/0x48 ata_host_get+0x10/0x18 ata_tport_add+0x40/0x120 ata_sas_tport_add+0xc/0x14 sas_ata_init+0x7c/0xc8 sas_discover_domain+0x380/0x53c process_one_work+0x12c/0x288 worker_thread+0x58/0x3f0 kthread+0xfc/0x128 ret_from_fork+0x10/0x18 And also when removing transport ATA port ata_host_put() will be called and another similar warning will be triggered. If the refcount decreased to zero, the ata host will be freed. But this ata host is only part of domain_device, it cannot be freed directly. So we have to change this embedded static ata host to a dynamically allocated ata host and initialize the ->kref member. To use ata_host_get() and ata_host_put() in libsas, we need to move the declaration of these functions to the public libata.h and export them. Fixes: b6240a4df018 ("scsi: libsas: add transport class for ATA devices") Signed-off-by: Jason Yan CC: John Garry CC: Taras Kondratiuk CC: Tejun Heo Acked-by: Tejun Heo Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-core.c | 3 ++ drivers/ata/libata.h | 2 - drivers/scsi/libsas/sas_ata.c | 40 ++++++++++++++++++++++++------------- drivers/scsi/libsas/sas_discover.c | 2 + include/linux/libata.h | 2 + include/scsi/libsas.h | 2 - 6 files changed, 34 insertions(+), 17 deletions(-) --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6424,6 +6424,7 @@ void ata_host_init(struct ata_host *host host->n_tags = ATA_MAX_QUEUE; host->dev = dev; host->ops = ops; + kref_init(&host->kref); } void __ata_port_probe(struct ata_port *ap) @@ -7391,3 +7392,5 @@ EXPORT_SYMBOL_GPL(ata_cable_80wire); EXPORT_SYMBOL_GPL(ata_cable_unknown); EXPORT_SYMBOL_GPL(ata_cable_ignore); EXPORT_SYMBOL_GPL(ata_cable_sata); +EXPORT_SYMBOL_GPL(ata_host_get); +EXPORT_SYMBOL_GPL(ata_host_put); \ No newline at end of file --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -100,8 +100,6 @@ extern int ata_port_probe(struct ata_por extern void __ata_port_probe(struct ata_port *ap); extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log, u8 page, void *buf, unsigned int sectors); -extern void ata_host_get(struct ata_host *host); -extern void ata_host_put(struct ata_host *host); #define to_ata_port(d) container_of(d, struct ata_port, tdev) --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -557,34 +557,46 @@ int sas_ata_init(struct domain_device *f { struct sas_ha_struct *ha = found_dev->port->ha; struct Scsi_Host *shost = ha->core.shost; + struct ata_host *ata_host; struct ata_port *ap; int rc; - ata_host_init(&found_dev->sata_dev.ata_host, ha->dev, &sas_sata_ops); - ap = ata_sas_port_alloc(&found_dev->sata_dev.ata_host, - &sata_port_info, - shost); + ata_host = kzalloc(sizeof(*ata_host), GFP_KERNEL); + if (!ata_host) { + SAS_DPRINTK("ata host alloc failed.\n"); + return -ENOMEM; + } + + ata_host_init(ata_host, ha->dev, &sas_sata_ops); + + ap = ata_sas_port_alloc(ata_host, &sata_port_info, shost); if (!ap) { SAS_DPRINTK("ata_sas_port_alloc failed.\n"); - return -ENODEV; + rc = -ENODEV; + goto free_host; } ap->private_data = found_dev; ap->cbl = ATA_CBL_SATA; ap->scsi_host = shost; rc = ata_sas_port_init(ap); - if (rc) { - ata_sas_port_destroy(ap); - return rc; - } - rc = ata_sas_tport_add(found_dev->sata_dev.ata_host.dev, ap); - if (rc) { - ata_sas_port_destroy(ap); - return rc; - } + if (rc) + goto destroy_port; + + rc = ata_sas_tport_add(ata_host->dev, ap); + if (rc) + goto destroy_port; + + found_dev->sata_dev.ata_host = ata_host; found_dev->sata_dev.ap = ap; return 0; + +destroy_port: + ata_sas_port_destroy(ap); +free_host: + ata_host_put(ata_host); + return rc; } void sas_ata_task_abort(struct sas_task *task) --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -316,6 +316,8 @@ void sas_free_device(struct kref *kref) if (dev_is_sata(dev) && dev->sata_dev.ap) { ata_sas_tport_delete(dev->sata_dev.ap); ata_sas_port_destroy(dev->sata_dev.ap); + ata_host_put(dev->sata_dev.ata_host); + dev->sata_dev.ata_host = NULL; dev->sata_dev.ap = NULL; } --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1111,6 +1111,8 @@ extern struct ata_host *ata_host_alloc(s extern struct ata_host *ata_host_alloc_pinfo(struct device *dev, const struct ata_port_info * const * ppi, int n_ports); extern int ata_slave_link_init(struct ata_port *ap); +extern void ata_host_get(struct ata_host *host); +extern void ata_host_put(struct ata_host *host); extern int ata_host_start(struct ata_host *host); extern int ata_host_register(struct ata_host *host, struct scsi_host_template *sht); --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -161,7 +161,7 @@ struct sata_device { u8 port_no; /* port number, if this is a PM (Port) */ struct ata_port *ap; - struct ata_host ata_host; + struct ata_host *ata_host; struct smp_resp rps_resp ____cacheline_aligned; /* report_phy_sata_resp */ u8 fis[ATA_RESP_FIS_SIZE]; };