206 lines
6.2 KiB
Diff
206 lines
6.2 KiB
Diff
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(¶ms, (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
|