Received: by 2002:ac0:a5b6:0:0:0:0:0 with SMTP id m51-v6csp3698878imm; Mon, 18 Jun 2018 02:32:01 -0700 (PDT) X-Google-Smtp-Source: ADUXVKKXSbVoa4/drnLELjdH+1M86PIWUMV+s6ok4zNldkPwlSGMyiF/sGgOn5XVWtLnqdTcgXpi X-Received: by 2002:a63:7553:: with SMTP id f19-v6mr10543981pgn.314.1529314321490; Mon, 18 Jun 2018 02:32:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1529314321; cv=none; d=google.com; s=arc-20160816; b=WRxVatw3tWXcNVkrOW8DNspY4FQ/PkDuPXa5Y9aDFiZLjB+xnbXsxqbmMz05F6WFvW aI2DwEsYW7mdWW8VGBGqx9vIhsC/VJfeyHtWPz16irgquMPVkcCQ7dXO0h0blLcPR9vr dcmzhGHHEOWZxSo1pk0kG+bpql+7R6aiGBU5hj+tFzzANGfIIi+tGbkCaE2IY947iJXi Gm9NRTXKSKHb608zF/OCf5bvpxZeD4EhCJoZZNqyuuMLD9h+O/mhv8e6RXCzqfh7tKby H8sYzY4ishjPfIhpyXQI+ZI+dsHQ0pTPeQh2VN1n1533GiugKT3T8I/4uZVWutQejbgY rJjw== 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=RWN3ZLvt0PDHjIiwXPmxodfugVEvvKeAYU9o6chH/UE=; b=V5J2igHTe+6yCwf5hwB8VjcEvmOsODbEvBcXyUQPcdF+yWJJ0cpw1PHAEGEI+7FfuZ HvMXXHKqw8zUYZfO2mOHUjbDCo5wvSoQAxbQZqVq0LZcjb2G641M+3DuSlc7YkULetA3 kz05qJZxtCvHY/JOb4gyzoSUpSg+lcwGJKEkPonxEz1uGTpSIfaLHP4q3a3jYGdCTw10 pe+1JNOXEjyuVtZQTfJyovXG0PVHegRY53Vk+7/ruGMDq5wbqQgy7+Yp+DRBKgctT04a nL6bm+IWQ3dWxKsJ9SnpiJ8u+zbYZ5EeOCqIQfFWOkV9Gsr8uggyVkn9O7DuxUXPovIM EpUw== 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 e7-v6si11721458pgf.317.2018.06.18.02.31.47; Mon, 18 Jun 2018 02:32:01 -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 S936405AbeFRIZE (ORCPT + 99 others); Mon, 18 Jun 2018 04:25:04 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:56150 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935926AbeFRIZA (ORCPT ); Mon, 18 Jun 2018 04:25:00 -0400 Received: from localhost (LFbn-1-12247-202.w90-92.abo.wanadoo.fr [90.92.61.202]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id 63EACC74; Mon, 18 Jun 2018 08:24:59 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Mike Marciniszyn , "Michael J. Ruhl" , Sebastian Sanchez , Dennis Dalessandro , Doug Ledford , Sasha Levin Subject: [PATCH 4.16 174/279] IB/{hfi1, rdmavt}: Fix memory leak in hfi1_alloc_devdata() upon failure Date: Mon, 18 Jun 2018 10:12:39 +0200 Message-Id: <20180618080616.082039671@linuxfoundation.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180618080608.851973560@linuxfoundation.org> References: <20180618080608.851973560@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.16-stable review patch. If anyone has any objections, please let me know. ------------------ From: Sebastian Sanchez [ Upstream commit e9777ad4399c26c70318c4945f94efac2ed95391 ] When allocating device data, if there's an allocation failure, the already allocated memory won't be freed such as per-cpu counters. Fix memory leaks in exception path by creating a common reentrant clean up function hfi1_clean_devdata() to be used at driver unload time and device data allocation failure. To accomplish this, free_platform_config() and clean_up_i2c() are changed to be reentrant to remove dependencies when they are called in different order. This helps avoid NULL pointer dereferences introduced by this patch if those two functions weren't reentrant. In addition, set dd->int_counter, dd->rcv_limit, dd->send_schedule and dd->tx_opstats to NULL after they're freed in hfi1_clean_devdata(), so that hfi1_clean_devdata() is fully reentrant. Reviewed-by: Mike Marciniszyn Reviewed-by: Michael J. Ruhl Signed-off-by: Sebastian Sanchez Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/hfi1/init.c | 37 ++++++++++++++++++++++++---------- drivers/infiniband/hw/hfi1/platform.c | 1 drivers/infiniband/hw/hfi1/qsfp.c | 2 + 3 files changed, 30 insertions(+), 10 deletions(-) --- a/drivers/infiniband/hw/hfi1/init.c +++ b/drivers/infiniband/hw/hfi1/init.c @@ -1209,30 +1209,49 @@ static void finalize_asic_data(struct hf kfree(ad); } -static void __hfi1_free_devdata(struct kobject *kobj) +/** + * hfi1_clean_devdata - cleans up per-unit data structure + * @dd: pointer to a valid devdata structure + * + * It cleans up all data structures set up by + * by hfi1_alloc_devdata(). + */ +static void hfi1_clean_devdata(struct hfi1_devdata *dd) { - struct hfi1_devdata *dd = - container_of(kobj, struct hfi1_devdata, kobj); struct hfi1_asic_data *ad; unsigned long flags; spin_lock_irqsave(&hfi1_devs_lock, flags); - idr_remove(&hfi1_unit_table, dd->unit); - list_del(&dd->list); + if (!list_empty(&dd->list)) { + idr_remove(&hfi1_unit_table, dd->unit); + list_del_init(&dd->list); + } ad = release_asic_data(dd); spin_unlock_irqrestore(&hfi1_devs_lock, flags); - if (ad) - finalize_asic_data(dd, ad); + + finalize_asic_data(dd, ad); free_platform_config(dd); rcu_barrier(); /* wait for rcu callbacks to complete */ free_percpu(dd->int_counter); free_percpu(dd->rcv_limit); free_percpu(dd->send_schedule); free_percpu(dd->tx_opstats); + dd->int_counter = NULL; + dd->rcv_limit = NULL; + dd->send_schedule = NULL; + dd->tx_opstats = NULL; sdma_clean(dd, dd->num_sdma); rvt_dealloc_device(&dd->verbs_dev.rdi); } +static void __hfi1_free_devdata(struct kobject *kobj) +{ + struct hfi1_devdata *dd = + container_of(kobj, struct hfi1_devdata, kobj); + + hfi1_clean_devdata(dd); +} + static struct kobj_type hfi1_devdata_type = { .release = __hfi1_free_devdata, }; @@ -1333,9 +1352,7 @@ struct hfi1_devdata *hfi1_alloc_devdata( return dd; bail: - if (!list_empty(&dd->list)) - list_del_init(&dd->list); - rvt_dealloc_device(&dd->verbs_dev.rdi); + hfi1_clean_devdata(dd); return ERR_PTR(ret); } --- a/drivers/infiniband/hw/hfi1/platform.c +++ b/drivers/infiniband/hw/hfi1/platform.c @@ -199,6 +199,7 @@ void free_platform_config(struct hfi1_de { /* Release memory allocated for eprom or fallback file read. */ kfree(dd->platform_config.data); + dd->platform_config.data = NULL; } void get_port_type(struct hfi1_pportdata *ppd) --- a/drivers/infiniband/hw/hfi1/qsfp.c +++ b/drivers/infiniband/hw/hfi1/qsfp.c @@ -204,6 +204,8 @@ static void clean_i2c_bus(struct hfi1_i2 void clean_up_i2c(struct hfi1_devdata *dd, struct hfi1_asic_data *ad) { + if (!ad) + return; clean_i2c_bus(ad->i2c_bus0); ad->i2c_bus0 = NULL; clean_i2c_bus(ad->i2c_bus1);