Unverified Commit 5c41e485 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!5175 arm64/mpam: Fix use-after-free when deleting resource groups

Merge Pull Request from: @ci-robot 
 
PR sync from: Zeng Heng <zengheng4@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/BPAM6M57IH3QWQ6BIIGVSIHZH2AZNK4Q/ 
Wang ShaoBo (1):
  arm64/mpam: remove kernfs_get() calls() and add kernfs_put() calls to
    prevent refcount leak

Zeng Heng (1):
  arm64/mpam: Fix use-after-free when deleting resource groups


--
2.25.1
 
https://gitee.com/openeuler/kernel/issues/I975PZ 
 
Link:https://gitee.com/openeuler/kernel/pulls/5175

 

Reviewed-by: default avatarWang ShaoBo <bobo.shaobowang@huawei.com>
Reviewed-by: default avatarWei Li <liwei391@huawei.com>
Reviewed-by: default avatarzhangyi (F) <yi.zhang@huawei.com>
Reviewed-by: default avatarLiu YongQiang <liuyongqiang13@huawei.com>
Signed-off-by: default avatarZhang Changzhong <zhangchangzhong@huawei.com>
parents c4311485 d07b938a
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -505,5 +505,23 @@ static inline u32 resctrl_navie_closid(struct sd_closid closid)
	return closid.intpartid;
}

/**
 * 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 inline void rdtgroup_remove(struct rdtgroup *rdtgrp)
{
	kernfs_put(rdtgrp->kn);
	kfree(rdtgrp);
}

#endif
#endif /* _ASM_ARM64_RESCTRL_H */
+0 −8
Original line number Diff line number Diff line
@@ -818,7 +818,6 @@ static int resctrl_group_mkdir_info_resdir(struct resctrl_resource *r,
	if (IS_ERR(kn_subdir))
		return PTR_ERR(kn_subdir);

	kernfs_get(kn_subdir);
	ret = resctrl_group_kn_set_ugid(kn_subdir);
	if (ret)
		return ret;
@@ -844,7 +843,6 @@ int resctrl_group_create_info_dir(struct kernfs_node *parent_kn,
	*kn_info = kernfs_create_dir(parent_kn, "info", parent_kn->mode, NULL);
	if (IS_ERR(*kn_info))
		return PTR_ERR(*kn_info);
	kernfs_get(*kn_info);

	ret = resctrl_group_add_files(*kn_info, RF_TOP_INFO);
	if (ret)
@@ -879,12 +877,6 @@ int resctrl_group_create_info_dir(struct kernfs_node *parent_kn,
		}
	}

	/*
	 m This extra ref will be put in kernfs_remove() and guarantees
	 * that @rdtgrp->kn is always accessible.
	 */
	kernfs_get(*kn_info);

	ret = resctrl_group_kn_set_ugid(*kn_info);
	if (ret)
		goto out_destroy;
+1 −1
Original line number Diff line number Diff line
@@ -1379,7 +1379,7 @@ static void move_myself(struct callback_head *head)
	    (rdtgrp->flags & RDT_DELETED)) {
		current->closid = 0;
		current->rmid = 0;
		kfree(rdtgrp);
		rdtgroup_remove(rdtgrp);
	}

	preempt_disable();
+13 −24
Original line number Diff line number Diff line
@@ -212,8 +212,7 @@ void resctrl_group_kn_unlock(struct kernfs_node *kn)
	if (atomic_dec_and_test(&rdtgrp->waitcount) &&
	    (rdtgrp->flags & RDT_DELETED)) {
		kernfs_unbreak_active_protection(kn);
		kernfs_put(rdtgrp->kn);
		kfree(rdtgrp);
		rdtgroup_remove(rdtgrp);
	} else {
		kernfs_unbreak_active_protection(kn);
	}
@@ -235,12 +234,6 @@ mongroup_create_dir(struct kernfs_node *parent_kn, struct resctrl_group *prgrp,
	if (dest_kn)
		*dest_kn = kn;

	/*
	 * This extra ref will be put in kernfs_remove() and guarantees
	 * that @rdtgrp->kn is always accessible.
	 */
	kernfs_get(kn);

	ret = resctrl_group_kn_set_ugid(kn);
	if (ret)
		goto out_destroy;
@@ -373,7 +366,6 @@ static struct dentry *resctrl_mount(struct file_system_type *fs_type,
			dentry = ERR_PTR(ret);
			goto out_info;
		}
		kernfs_get(kn_mongrp);

		ret = mkdir_mondata_all_prepare(&resctrl_group_default);
		if (ret < 0) {
@@ -386,7 +378,7 @@ static struct dentry *resctrl_mount(struct file_system_type *fs_type,
			dentry = ERR_PTR(ret);
			goto out_mongrp;
		}
		kernfs_get(kn_mondata);

		resctrl_group_default.mon.mon_data_kn = kn_mondata;
	}

@@ -474,7 +466,10 @@ static void free_all_child_rdtgrp(struct resctrl_group *rdtgrp)
		/* rmid may not be used */
		rmid_free(sentry->mon.rmid);
		list_del(&sentry->mon.crdtgrp_list);
		kfree(sentry);
		if (atomic_read(&sentry->waitcount) != 0)
			sentry->flags = RDT_DELETED;
		else
			rdtgroup_remove(sentry);
	}
}

@@ -508,7 +503,10 @@ static void rmdir_all_sub(void)

		kernfs_remove(rdtgrp->kn);
		list_del(&rdtgrp->resctrl_group_list);
		kfree(rdtgrp);
		if (atomic_read(&rdtgrp->waitcount) != 0)
			rdtgrp->flags = RDT_DELETED;
		else
			rdtgroup_remove(rdtgrp);
	}
	/* Notify online CPUs to update per cpu storage and PQR_ASSOC MSR */
	update_closid_rmid(cpu_online_mask, &resctrl_group_default);
@@ -645,7 +643,7 @@ static int mkdir_resctrl_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
	 * resctrl_group_kn_unlock(kn} call below. Take one extra reference
	 * here, which will be dropped inside resctrl_group_kn_unlock().
	 * here, which will be dropped inside rdtgroup_remove().
	 */
	kernfs_get(kn);

@@ -685,6 +683,7 @@ static int mkdir_resctrl_prepare(struct kernfs_node *parent_kn,
out_prepare_clean:
	mkdir_mondata_all_prepare_clean(rdtgrp);
out_destroy:
	kernfs_put(rdtgrp->kn);
	kernfs_remove(rdtgrp->kn);
out_free_rmid:
	rmid_free(rdtgrp->mon.rmid);
@@ -701,7 +700,7 @@ static int mkdir_resctrl_prepare(struct kernfs_node *parent_kn,
static void mkdir_resctrl_prepare_clean(struct resctrl_group *rgrp)
{
	kernfs_remove(rgrp->kn);
	kfree(rgrp);
	rdtgroup_remove(rgrp);
}

/*
@@ -866,11 +865,6 @@ static int resctrl_group_rmdir_mon(struct kernfs_node *kn, struct resctrl_group
{
	resctrl_group_rm_mon(rdtgrp, tmpmask);

	/*
	 * one extra hold on this, will drop when we kfree(rdtgrp)
	 * in resctrl_group_kn_unlock()
	 */
	kernfs_get(kn);
	kernfs_remove(rdtgrp->kn);

	return 0;
@@ -919,11 +913,6 @@ static int resctrl_group_rmdir_ctrl(struct kernfs_node *kn, struct resctrl_group
{
	resctrl_group_rm_ctrl(rdtgrp, tmpmask);

	/*
	 * one extra hold on this, will drop when we kfree(rdtgrp)
	 * in resctrl_group_kn_unlock()
	 */
	kernfs_get(kn);
	kernfs_remove(rdtgrp->kn);

	return 0;