penguin/monok8s

k8s image for Mono Gateway Dev Kit

patches/ask/dpa/0004-cdx-stash-userspace-fman-nested-pointers.patch

raw ยท 6353 bytes

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: monok8s <monok8s@example.invalid>
Date: Sun, 10 May 2026 00:00:00 +0000
Subject: [PATCH 4/4] cdx: stash userspace fman nested pointers before cleanup

cdx_ioc_set_dpa_params() copies struct cdx_fman_info from userspace.
The nested portinfo and tbl_info members are userspace pointers at that
point, but release_cfg_info() treats non-NULL nested pointers as
kernel-owned allocations.

If setup fails before get_port_info() or get_cctbl_info() replaces those
members with kernel allocations, the error path can kfree a userspace
address and panic in kfree()/virt_to_folio().

Stash the userspace pointers in temporary arrays, clear the nested
members in fman_info immediately, and pass the stashed pointers into the
copy helpers explicitly. Also route early setup failures through the same
cleanup path so partial state is released consistently.
---
diff --git a/cdx/dpa_cfg.c b/cdx/dpa_cfg.c
index c678d5d..55b910d 100644
--- a/cdx/dpa_cfg.c
+++ b/cdx/dpa_cfg.c
@@ -267,10 +267,9 @@ static void *get_dist_info_by_fman_params(struct cdx_fman_info *finfo, uint32_t
 #endif //CDX_RTP_RELAY
 
 //allocate and copy port releated info from uspace 
-static int get_port_info(struct cdx_fman_info *finfo) 
+static int get_port_info(struct cdx_fman_info *finfo, void *uspace_info)
 {	
 	struct cdx_port_info *port_info;
-	void *uspace_info;
 	void **uspace_dist_info;
 	uint32_t mem_size;
 	uint32_t ii;
@@ -298,7 +297,6 @@ static int get_port_info(struct cdx_fman_info *finfo)
 		return -ENOMEM;
 	}
 
-	uspace_info = finfo->portinfo;
 	finfo->portinfo = port_info;
 	if (copy_from_user(port_info, uspace_info, mem_size)) {
 		DPA_ERROR("%s::Read port_info failed\n",
@@ -355,7 +353,7 @@ static int get_port_info(struct cdx_fman_info *finfo)
 	}
 	port_info = finfo->portinfo;
 	for (ii = 0; ii < finfo->max_ports; ii++) {
-		int retval;
+		int retval = 0;
 		//get dist info for this port
 		retval = get_dist_info(port_info, uspace_dist_info[ii]);
 		if (retval) {
@@ -369,11 +367,10 @@ static int get_port_info(struct cdx_fman_info *finfo)
 }	
 
 //allocate and copy cc table infor from uspace
-static int get_cctbl_info(struct cdx_fman_info *finfo) 
+static int get_cctbl_info(struct cdx_fman_info *finfo, void *uspace_info)
 {	
 	struct table_info *tbl_info;
 	uint32_t mem_size;
-	void *uspace_info;
 
 	//allocate table information area
 	mem_size = (sizeof(struct table_info) * finfo->num_tables);
@@ -384,7 +381,6 @@ static int get_cctbl_info(struct cdx_fman_info *finfo)
 		return -ENOMEM;
 	}
 	memset(tbl_info, 0, mem_size);
-	uspace_info = finfo->tbl_info;
 	finfo->tbl_info = tbl_info;
 	//copy table related info from user space	
 	if (copy_from_user(tbl_info, (void *)uspace_info, mem_size)) {
@@ -625,9 +621,11 @@ int cdx_ioc_set_dpa_params(unsigned long args)
 {
 	struct cdx_ctrl_set_dpa_params params;
 	struct cdx_fman_info *finfo;
+	void **uspace_port_info = NULL;
+	void **uspace_tbl_info = NULL;
 	uint32_t ii;	
 	uint32_t mem_size;
-	int retval;
+	int retval = 0;
 
 	if (copy_from_user(&params, (void *)args, 
 				sizeof(struct cdx_ctrl_set_dpa_params))) {
@@ -655,6 +653,35 @@ int cdx_ioc_set_dpa_params(unsigned long args)
 		retval = -EIO;
 		goto err_ret;
 	}
+	uspace_port_info = kcalloc(num_fmans, sizeof(*uspace_port_info),
+			GFP_KERNEL);
+	uspace_tbl_info = kcalloc(num_fmans, sizeof(*uspace_tbl_info),
+			GFP_KERNEL);
+	if (!uspace_port_info || !uspace_tbl_info) {
+		DPA_ERROR("%s::unable to allocate user pointer stash\n",
+				__func__);
+		for (ii = 0; ii < num_fmans; ii++) {
+			fman_info[ii].portinfo = NULL;
+			fman_info[ii].tbl_info = NULL;
+		}
+		retval = -ENOMEM;
+		goto err_ret;
+	}
+
+	/*
+	 * fman_info is copied from userspace.  Its nested portinfo and
+	 * tbl_info members are userspace pointers until get_port_info() and
+	 * get_cctbl_info() replace them with kernel allocations.  Never leave
+	 * raw userspace pointers in fman_info, because release_cfg_info() owns
+	 * and frees non-NULL nested pointers on error paths.
+	 */
+	for (ii = 0; ii < num_fmans; ii++) {
+		uspace_port_info[ii] = fman_info[ii].portinfo;
+		uspace_tbl_info[ii] = fman_info[ii].tbl_info;
+		fman_info[ii].portinfo = NULL;
+		fman_info[ii].tbl_info = NULL;
+	}
+
 	if (copy_from_user(&ipr_info, (void *)params.ipr_info,
 				sizeof(struct cdx_ipr_info))) {
 		DPA_ERROR("%s::Read iprv_info failed\n", 
@@ -665,22 +688,26 @@ int cdx_ioc_set_dpa_params(unsigned long args)
 	//init the fman handles 
 	finfo = fman_info;
 	for (ii = 0; ii < num_fmans; ii++) {
-		if (cdxdrv_get_fman_handles(finfo))
-			return -1;
+		if (cdxdrv_get_fman_handles(finfo)) {
+			retval = -EIO;
+			goto err_ret;
+		}
 		finfo++;
 	}
 	finfo = fman_info;
 	//init interface stats module
-	if (cdxdrv_init_stats(finfo->muram_handle))
-		return -1;
+	if (cdxdrv_init_stats(finfo->muram_handle)) {
+		retval = -EIO;
+		goto err_ret;
+	}
 
 	for (ii = 0; ii < num_fmans; ii++) {
 		//get port info
-		retval = get_port_info(finfo);
+		retval = get_port_info(finfo, uspace_port_info[ii]);
 		if (retval)
 			goto err_ret;
 		//get cc table info
-		retval = get_cctbl_info(finfo);
+		retval = get_cctbl_info(finfo, uspace_tbl_info[ii]);
 		if (retval)
 			goto err_ret;
 		finfo++;
@@ -727,29 +754,43 @@ int cdx_ioc_set_dpa_params(unsigned long args)
 		finfo++;
 	}
 
-	if (cdx_create_port_fqs())
-		return -1;
+	if (cdx_create_port_fqs()) {
+		retval = -EIO;
+		goto err_ret;
+	}
 	//create cp rate limit policier profiles
 	if (cdxdrv_create_missaction_policer_profiles(fman_info)) {
+		retval = -EIO;
 		goto err_ret;
 	}
 #ifdef ENABLE_INGRESS_QOS
 	if (cdxdrv_create_ingress_qos_policer_profiles(fman_info)) {
+		retval = -EIO;
 		goto err_ret;
 	}
 #endif
 #ifdef ENABLE_EGRESS_QOS
-	if(ceetm_init_cq_plcr())
+	if(ceetm_init_cq_plcr()) {
+		retval = -EIO;
 		goto err_ret;
+	}
 #endif
 	//init the fman and its ports
 	for (ii = 0; ii < num_fmans; ii++) {
-		if (cdxdrv_set_miss_action(ii))
+		if (cdxdrv_set_miss_action(ii)) {
+			retval = -EIO;
 			goto err_ret;
+		}
 	}
 	display_dpa_cfg();
+	kfree(uspace_port_info);
+	kfree(uspace_tbl_info);
 	return 0;
 err_ret:
+	DPA_ERROR("%s::error path retval %d, releasing partial DPA cfg\n",
+			__func__, retval);
+	kfree(uspace_port_info);
+	kfree(uspace_tbl_info);
 	release_cfg_info();
 	return retval;
 }
-- 
2.39.5