Received: by 2002:a05:6a10:9e8c:0:0:0:0 with SMTP id y12csp1515377pxx; Fri, 30 Oct 2020 11:48:30 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyO7k6yDZ9O4jg8wBdDvKq8y2VdKqsqbit7hlEQYultxD7DChdpOT2PIZRv46XJPS7ClFBF X-Received: by 2002:a17:906:3fc5:: with SMTP id k5mr3995953ejj.158.1604083709976; Fri, 30 Oct 2020 11:48:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1604083709; cv=none; d=google.com; s=arc-20160816; b=BIU3nK3hgDAf68Wp/mqsvnsYrKcvxPuzi8dE5iD5j5uJQJugoI1mD78q1Tf1vY8/uQ p+z0gdGB2I8Atmw1ns5cH/3WPxVeKrms+auKTYkXwArjkqQhqexZm/x+Y6iAfqWY6Qvo tcj9LrED7RlDJKUzhGA5KP1Pq4wxL8bx7KJcWBvk7PBI3H+bpQOQZzgweBmGktJu8QOO K0A8+Ch9L/RsqahB1aSy6BUNBi2JkhywowlvzvoypIYSzX5qLSzyMZN69942uYoWMl+E g/agHyDGA3lNSYbMFW1oP5Th8ZhHBpFSYKbGrnYYqtDlrQMA3vZDsHChaKUTYTIG2Ecz TQKw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:references:in-reply-to:message-id:date:subject :cc:to:from:ironport-sdr:ironport-sdr; bh=EWNTekUHRX8tfS2zjj9+hD5y26Nzd7HMT4qFG0X4Uzo=; b=vzx1hcdaJfWU+dkwdmifHZz8OplFZwQKxKibuPWDYjcjs7myWLwaRKKRX27c6N1l1o yPYPRpYhiOFuyo6tQhb5SpG0VCvc9k8FSOIuHRzsPfcPmkFqLbHI3H2VlkwUQFQWfyhg Q5Qs5waDf1LEgvmeG7bDa1XudA83KmWd2lQ4esGDJuI9gitXkc+CnVDVeKlvgVxt66Wr ZPFp31NTDgFstc02KnJABRUtoTKuClRb0TkdCN3MhnSVWupvMrdtm5g38vwaveEPaPj6 cDlsf8YNf4NbKuIS3cUg8LF2MsYfEPZ6rkrAj7kXYRW9c3rT+IX8qz82jsDxnxRKXbKW prZg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id b7si5111241ejj.658.2020.10.30.11.48.07; Fri, 30 Oct 2020 11:48:29 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727230AbgJ3SqV (ORCPT + 99 others); Fri, 30 Oct 2020 14:46:21 -0400 Received: from mga01.intel.com ([192.55.52.88]:22960 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726061AbgJ3SqV (ORCPT ); Fri, 30 Oct 2020 14:46:21 -0400 IronPort-SDR: PIb51Zn4DN4M9zoFM8d4WsnxwheVSHEWLpDhdr1CXUYpAiRZR3Bz7o4gjqehl974IN9oqdSHR3 AhjJknPjPSOA== X-IronPort-AV: E=McAfee;i="6000,8403,9790"; a="186462741" X-IronPort-AV: E=Sophos;i="5.77,434,1596524400"; d="scan'208";a="186462741" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 30 Oct 2020 11:46:20 -0700 IronPort-SDR: gKxIQYlfEqDuQEjcyNssj0b+8imIMpiECSBoRMhWYjp5hSCCBKT3qosovXFnMPWPpY5Mj6sxPC 32gvg644sXZQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.77,434,1596524400"; d="scan'208";a="351958805" Received: from xshen14-linux.bj.intel.com ([10.238.155.105]) by fmsmga004.fm.intel.com with ESMTP; 30 Oct 2020 11:46:18 -0700 From: Xiaochen Shen To: tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, hpa@zytor.com, tony.luck@intel.com, fenghua.yu@intel.com, reinette.chatre@intel.com, willemb@google.com Cc: x86@kernel.org, linux-kernel@vger.kernel.org, pei.p.jia@intel.com, xiaochen.shen@intel.com Subject: [PATCH 2/3] x86/resctrl: Add necessary kernfs_put() calls to prevent refcount leak Date: Sat, 31 Oct 2020 03:11:28 +0800 Message-Id: <1604085088-31707-1-git-send-email-xiaochen.shen@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1604084530-31048-1-git-send-email-xiaochen.shen@intel.com> References: <1604084530-31048-1-git-send-email-xiaochen.shen@intel.com> Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On resource group creation via a mkdir an extra kernfs_node reference is obtained by kernfs_get() to ensure that the rdtgroup structure remains accessible for the rdtgroup_kn_unlock() calls where it is removed on deletion. Currently the extra kernfs_node reference count is only dropped by kernfs_put() in rdtgroup_kn_unlock() while the rdtgroup structure is removed in a few other locations that lack the matching reference drop. In call paths of rmdir and umount, when a control group is removed, kernfs_remove() is called to remove the whole kernfs nodes tree of the control group (including the kernfs nodes trees of all child monitoring groups), and then rdtgroup structure is freed by kfree(). The rdtgroup structures of all child monitoring groups under the control group are freed by kfree() in free_all_child_rdtgrp(). Before calling kfree() to free the rdtgroup structures, the kernfs node of the control group itself as well as the kernfs nodes of all child monitoring groups still take the extra references which will never be dropped to 0 and the kernfs nodes will never be freed. It leads to reference count leak and kernfs_node_cache memory leak. For example, reference count leak is observed in these two cases: (1) mount -t resctrl resctrl /sys/fs/resctrl mkdir /sys/fs/resctrl/c1 mkdir /sys/fs/resctrl/c1/mon_groups/m1 umount /sys/fs/resctrl (2) mkdir /sys/fs/resctrl/c1 mkdir /sys/fs/resctrl/c1/mon_groups/m1 rmdir /sys/fs/resctrl/c1 The same reference count leak issue also exists in the error exit paths of mkdir in mkdir_rdt_prepare() and rdtgroup_mkdir_ctrl_mon(). Fix this issue by following changes to make sure the extra kernfs_node reference on rdtgroup is dropped before freeing the rdtgroup structure. (1) Introduce rdtgroup removal helper rdtgroup_remove() to wrap up kernfs_put() and kfree(). (2) Call rdtgroup_remove() in rdtgroup removal path where the rdtgroup structure is about to be freed by kfree(). (3) Call rdtgroup_remove() or kernfs_put() as appropriate in the error exit paths of mkdir where an extra reference is taken by kernfs_get(). Cc: stable@vger.kernel.org Fixes: f3cbeacaa06e ("x86/intel_rdt/cqm: Add rmdir support") Fixes: e02737d5b826 ("x86/intel_rdt: Add tasks files") Fixes: 60cf5e101fd4 ("x86/intel_rdt: Add mkdir to resctrl file system") Reported-by: Willem de Bruijn Signed-off-by: Xiaochen Shen Reviewed-by: Reinette Chatre --- arch/x86/kernel/cpu/resctrl/rdtgroup.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index 2ab1266a5f14..6f4ca4bea625 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -507,6 +507,24 @@ static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of, return ret ?: nbytes; } +/** + * rdtgroup_remove - the helper to remove resource group safely + * @rdtgrp: resource group to remove + * + * On resource group creation via a mkdir, an extra kernfs_node reference is + * taken to ensure that the rdtgroup structure remains accessible for the + * rdtgroup_kn_unlock() calls where it is removed. + * + * Drop the extra reference here, then free the rdtgroup structure. + * + * Return: void + */ +static void rdtgroup_remove(struct rdtgroup *rdtgrp) +{ + kernfs_put(rdtgrp->kn); + kfree(rdtgrp); +} + struct task_move_callback { struct callback_head work; struct rdtgroup *rdtgrp; @@ -529,7 +547,7 @@ static void move_myself(struct callback_head *head) (rdtgrp->flags & RDT_DELETED)) { current->closid = 0; current->rmid = 0; - kfree(rdtgrp); + rdtgroup_remove(rdtgrp); } if (unlikely(current->flags & PF_EXITING)) @@ -2065,8 +2083,7 @@ void rdtgroup_kn_unlock(struct kernfs_node *kn) rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) rdtgroup_pseudo_lock_remove(rdtgrp); kernfs_unbreak_active_protection(kn); - kernfs_put(rdtgrp->kn); - kfree(rdtgrp); + rdtgroup_remove(rdtgrp); } else { kernfs_unbreak_active_protection(kn); } @@ -2341,7 +2358,7 @@ static void free_all_child_rdtgrp(struct rdtgroup *rdtgrp) if (atomic_read(&sentry->waitcount) != 0) sentry->flags = RDT_DELETED; else - kfree(sentry); + rdtgroup_remove(sentry); } } @@ -2383,7 +2400,7 @@ static void rmdir_all_sub(void) if (atomic_read(&rdtgrp->waitcount) != 0) rdtgrp->flags = RDT_DELETED; else - kfree(rdtgrp); + rdtgroup_remove(rdtgrp); } /* Notify online CPUs to update per cpu storage and PQR_ASSOC MSR */ update_closid_rmid(cpu_online_mask, &rdtgroup_default); @@ -2818,7 +2835,7 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn, * kernfs_remove() will drop the reference count on "kn" which * will free it. But we still need it to stick around for the * rdtgroup_kn_unlock(kn) call. Take one extra reference here, - * which will be dropped inside rdtgroup_kn_unlock(). + * which will be dropped by kernfs_put() in rdtgroup_remove(). */ kernfs_get(kn); @@ -2859,6 +2876,7 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn, out_idfree: free_rmid(rdtgrp->mon.rmid); out_destroy: + kernfs_put(rdtgrp->kn); kernfs_remove(rdtgrp->kn); out_free_rgrp: kfree(rdtgrp); @@ -2871,7 +2889,7 @@ static void mkdir_rdt_prepare_clean(struct rdtgroup *rgrp) { kernfs_remove(rgrp->kn); free_rmid(rgrp->mon.rmid); - kfree(rgrp); + rdtgroup_remove(rgrp); } /* -- 1.8.3.1