The /cnxk/ipsec/sa_info handler would silently wrap 32 bit value
to 16 bit port id.
An out-of-range port such as 65536 narrowed to a valid port
for the check and then read past the array.
Reject port ids >= RTE_MAX_ETHPORTS before the lookup.
The /cnxk/ipsec/info handler has similar issue with
strtoul().
Rework parse_params() to walk the string with strtoul()/endptr
rather than strtok(), which is not thread safe and races when the
telemetry callbacks run on per-connection threads. This drops the
strdup()/free(), range checks each value against UINT32_MAX, and
passes an unsigned char to isdigit().
Fixes: d74ed1628f7e ("net/cnxk: add SA info telemetry")
Cc: [email protected]
Signed-off-by: Stephen Hemminger <[email protected]>
---
drivers/net/cnxk/cnxk_ethdev_sec_telemetry.c | 50 ++++++++++----------
1 file changed, 24 insertions(+), 26 deletions(-)
diff --git a/drivers/net/cnxk/cnxk_ethdev_sec_telemetry.c
b/drivers/net/cnxk/cnxk_ethdev_sec_telemetry.c
index 86c2453c09..0c1533e3d7 100644
--- a/drivers/net/cnxk/cnxk_ethdev_sec_telemetry.c
+++ b/drivers/net/cnxk/cnxk_ethdev_sec_telemetry.c
@@ -211,33 +211,30 @@ copy_inb_sa_10k(struct rte_tel_data *d, uint32_t i, void
*sa)
static int
parse_params(const char *params, uint32_t *vals, size_t n_vals)
{
- char dlim[2] = ",";
- char *params_args;
size_t count = 0;
- char *token;
- if (vals == NULL || params == NULL || strlen(params) == 0)
+ if (params == NULL || !isdigit((unsigned char)params[0]))
return -1;
- /* strtok expects char * and param is const char *. Hence on using
- * params as "const char *" compiler throws warning.
- */
- params_args = strdup(params);
- if (params_args == NULL)
- return -1;
+ while (count < n_vals) {
+ char *end;
+ unsigned long v;
- token = strtok(params_args, dlim);
- while (token && isdigit(*token) && count < n_vals) {
- vals[count++] = strtoul(token, NULL, 10);
- token = strtok(NULL, dlim);
- }
+ errno = 0;
+ v = strtoul(params, &end, 10);
+ if (errno != 0 || v > UINT32_MAX)
+ return -EINVAL;
+ vals[count++] = v;
- free(params_args);
+ if (*end == '\0')
+ break;
- if (count < n_vals)
- return -1;
+ if (*end != ',' || !isdigit((unsigned char)end[1]))
+ return -EINVAL;
+ params = end + 1;
+ }
- return 0;
+ return count == n_vals ? 0 : -EINVAL;
}
static int
@@ -252,13 +249,13 @@ ethdev_sec_tel_handle_sa_info(const char *cmd
__rte_unused, const char *params,
uint32_t i;
int ret;
- if (params == NULL || strlen(params) == 0 || !isdigit(*params))
- return -EINVAL;
-
if (parse_params(params, vals, RTE_DIM(vals)) < 0)
return -EINVAL;
port_id = vals[0];
+ if (port_id >= RTE_MAX_ETHPORTS)
+ return -EINVAL;
+
sa_idx = vals[1];
if (!rte_eth_dev_is_valid_port(port_id)) {
@@ -320,12 +317,13 @@ ethdev_sec_tel_handle_info(const char *cmd __rte_unused,
const char *params,
struct cnxk_eth_sec_sess *eth_sec, *tvar;
struct rte_eth_dev *eth_dev;
struct cnxk_eth_dev *dev;
- uint16_t port_id;
+ unsigned long port_id;
char *end_p;
- if (params == NULL || strlen(params) == 0 || !isdigit(*params))
+ if (params == NULL || !isdigit((unsigned char)*params))
return -EINVAL;
+ errno = 0;
port_id = strtoul(params, &end_p, 0);
if (errno != 0)
return -EINVAL;
@@ -333,8 +331,8 @@ ethdev_sec_tel_handle_info(const char *cmd __rte_unused,
const char *params,
if (*end_p != '\0')
plt_err("Extra parameters passed to telemetry, ignoring it");
- if (!rte_eth_dev_is_valid_port(port_id)) {
- plt_err("Invalid port id %u", port_id);
+ if (port_id >= RTE_MAX_ETHPORTS || !rte_eth_dev_is_valid_port(port_id))
{
+ plt_err("Invalid port id %lu", port_id);
return -EINVAL;
}
--
2.53.0