* [RFC 0/8] first steps in fixing buffer overflow
@ 2025-12-02 17:24 Stephen Hemminger
2025-12-02 17:24 ` [RFC 1/8] eal: use C library to parse filesystem table Stephen Hemminger
` (8 more replies)
0 siblings, 9 replies; 48+ messages in thread
From: Stephen Hemminger @ 2025-12-02 17:24 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
This is preliminary work to fix the format overflow issues
in EAL and related libraries. The biggest problem area
still needing work is all the cases where the created
path for <runtime_dir>/XXX could overflow the maximum limit
which is only 108 characters due to Unix Domain socket
restrictions.
Stephen Hemminger (8):
eal: use C library to parse filesystem table
hash: fix possible ring name overflow
eal: warn if thread name is truncated
eal: avoid format overflow when handling addresses
ethdev: avoid possible overflow in xstat names
efd: avoid overflowing ring name
eal: add check for sysfs path overflow
eal: limit maximum runtime directory and socket paths
lib/eal/common/eal_common_config.c | 6 ++-
lib/eal/common/eal_common_memory.c | 2 +-
lib/eal/common/eal_common_proc.c | 18 ++++-----
lib/eal/common/eal_filesystem.h | 6 ++-
lib/eal/linux/eal.c | 6 ++-
lib/eal/linux/eal_hugepage_info.c | 64 +++++++++++-------------------
lib/efd/rte_efd.c | 20 +++++++++-
lib/ethdev/rte_ethdev.c | 27 +++++++++----
lib/hash/rte_cuckoo_hash.c | 33 +++++++++++----
9 files changed, 110 insertions(+), 72 deletions(-)
--
2.51.0
^ permalink raw reply [flat|nested] 48+ messages in thread* [RFC 1/8] eal: use C library to parse filesystem table 2025-12-02 17:24 [RFC 0/8] first steps in fixing buffer overflow Stephen Hemminger @ 2025-12-02 17:24 ` Stephen Hemminger 2025-12-02 17:24 ` [RFC 2/8] hash: fix possible ring name overflow Stephen Hemminger ` (7 subsequent siblings) 8 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-02 17:24 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson Rather than doing parsing of /proc/mounts with open coded string handling, use the standard C library routines. These exist in BSD and Linux. It also avoids any possible issues with escaped strings etc which the library handles. See getmntent(3) man page. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- lib/eal/linux/eal_hugepage_info.c | 58 ++++++++++--------------------- 1 file changed, 18 insertions(+), 40 deletions(-) diff --git a/lib/eal/linux/eal_hugepage_info.c b/lib/eal/linux/eal_hugepage_info.c index d47a19c56a..7161b1a2fb 100644 --- a/lib/eal/linux/eal_hugepage_info.c +++ b/lib/eal/linux/eal_hugepage_info.c @@ -13,6 +13,7 @@ #include <inttypes.h> #include <unistd.h> #include <errno.h> +#include <mntent.h> #include <sys/mman.h> #include <sys/stat.h> @@ -195,23 +196,13 @@ get_default_hp_size(void) static int get_hugepage_dir(uint64_t hugepage_sz, char *hugedir, int len) { - enum proc_mount_fieldnames { - DEVICE = 0, - MOUNTPT, - FSTYPE, - OPTIONS, - _FIELDNAME_MAX - }; static uint64_t default_size = 0; const char proc_mounts[] = "/proc/mounts"; - const char hugetlbfs_str[] = "hugetlbfs"; - const size_t htlbfs_str_len = sizeof(hugetlbfs_str) - 1; const char pagesize_opt[] = "pagesize="; const size_t pagesize_opt_len = sizeof(pagesize_opt) - 1; - const char split_tok = ' '; - char *splitstr[_FIELDNAME_MAX]; char found[PATH_MAX] = ""; char buf[BUFSIZ]; + struct mntent entry; const struct internal_config *internal_conf = eal_get_internal_configuration(); const size_t hugepage_dir_len = (internal_conf->hugepage_dir != NULL) ? @@ -226,56 +217,43 @@ get_hugepage_dir(uint64_t hugepage_sz, char *hugedir, int len) return -1; } - FILE *fd = fopen(proc_mounts, "r"); - if (fd == NULL) + FILE *mounts = setmntent(proc_mounts, "r"); + if (mounts == NULL) rte_panic("Cannot open %s\n", proc_mounts); if (default_size == 0) default_size = get_default_hp_size(); - while (fgets(buf, sizeof(buf), fd)){ + while (getmntent_r(mounts, &entry, buf, sizeof(buf))) { const char *pagesz_str; - size_t mountpt_len = 0; - - if (rte_strsplit(buf, sizeof(buf), splitstr, _FIELDNAME_MAX, - split_tok) != _FIELDNAME_MAX) { - EAL_LOG(ERR, "Error parsing %s", proc_mounts); - break; /* return NULL */ - } + uint64_t pagesz = default_size; + size_t mountpt_len; - if (strncmp(splitstr[FSTYPE], hugetlbfs_str, htlbfs_str_len) != 0) + if (strcmp(entry.mnt_type, "hugetlbfs") != 0) continue; - pagesz_str = strstr(splitstr[OPTIONS], pagesize_opt); + pagesz_str = strstr(entry.mnt_opts, pagesize_opt); + if (pagesz_str) + pagesz = rte_str_to_size(&pagesz_str[pagesize_opt_len]); - /* if no explicit page size, the default page size is compared */ - if (pagesz_str == NULL) { - if (hugepage_sz != default_size) - continue; - } - /* there is an explicit page size, so check it */ - else { - uint64_t pagesz = rte_str_to_size(&pagesz_str[pagesize_opt_len]); - if (pagesz != hugepage_sz) - continue; - } + if (pagesz != hugepage_sz) + continue; /* * If no --huge-dir option has been given, we're done. */ if (internal_conf->hugepage_dir == NULL) { - strlcpy(found, splitstr[MOUNTPT], len); + strlcpy(found, entry.mnt_dir, len); break; } - mountpt_len = strlen(splitstr[MOUNTPT]); + mountpt_len = strlen(entry.mnt_dir); /* * Ignore any mount that doesn't contain the --huge-dir directory * or where mount point is not a parent path of --huge-dir */ - if (strncmp(internal_conf->hugepage_dir, splitstr[MOUNTPT], - mountpt_len) != 0 || + if (strncmp(internal_conf->hugepage_dir, entry.mnt_dir, mountpt_len) != 0 || (hugepage_dir_len > mountpt_len && internal_conf->hugepage_dir[mountpt_len] != '/')) { continue; @@ -286,10 +264,10 @@ get_hugepage_dir(uint64_t hugepage_sz, char *hugedir, int len) * (so /mnt/1 is preferred over /mnt for matching /mnt/1/2)). */ if (mountpt_len > strlen(found)) - strlcpy(found, splitstr[MOUNTPT], len); + strlcpy(found, entry.mnt_dir, len); } /* end while fgets */ - fclose(fd); + endmntent(mounts); if (found[0] != '\0') { /* If needed, return the requested dir, not the mount point. */ -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC 2/8] hash: fix possible ring name overflow 2025-12-02 17:24 [RFC 0/8] first steps in fixing buffer overflow Stephen Hemminger 2025-12-02 17:24 ` [RFC 1/8] eal: use C library to parse filesystem table Stephen Hemminger @ 2025-12-02 17:24 ` Stephen Hemminger 2025-12-02 17:24 ` [RFC 3/8] eal: warn if thread name is truncated Stephen Hemminger ` (6 subsequent siblings) 8 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-02 17:24 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Yipeng Wang, Sameh Gobriel, Bruce Richardson, Vladimir Medvedkin The maximum possible hash parameter name will cause the generated ring names to overlow in snprintf(). Potentially causing conflicting ring names and trouble. For reference: RTE_MEMPOOL_NAMESIZE = 32 RTE_RING_NAMESIZE = 29 RTE_HASH_NAMESIZE = 32 The hash name is concatenated with a prefix like "HT_RCU_" the hash name string needs to be enforced as having space for the resulting string (ie 22). Since the NAMESIZE's are part of ABI they can't change. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/hash/rte_cuckoo_hash.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/lib/hash/rte_cuckoo_hash.c b/lib/hash/rte_cuckoo_hash.c index 2c92c51624..3a521a1a1e 100644 --- a/lib/hash/rte_cuckoo_hash.c +++ b/lib/hash/rte_cuckoo_hash.c @@ -77,6 +77,11 @@ struct __rte_hash_rcu_dq_entry { uint32_t ext_bkt_idx; }; +#define HASH_QSBR_PREFIX "HT_RCU_" +#define HASH_EXT_PREFIX "HT_EXT_" +#define HASH_RING_PREFIX "HT_" + + RTE_EXPORT_SYMBOL(rte_hash_find_existing) struct rte_hash * rte_hash_find_existing(const char *name) @@ -231,6 +236,20 @@ rte_hash_create(const struct rte_hash_parameters *params) return NULL; } + /* + * The API for hash allows 32 characters but maximimu length + * would overflow ring name which is limited to 29 characters (RTE_RING_NAMESIZE). + * To avoid breaking ABI, enforce limit of 25 characters on + * the hash table name. + */ + if (strnlen(params->name, RTE_HASH_NAMESIZE) + > RTE_RING_NAMESIZE - sizeof(HASH_QSBR_PREFIX)) { + rte_errno = EINVAL; + HASH_LOG(ERR, "%s: hash name too long to fit in qsbr ring name", + __func__); + return NULL; + } + /* Check extra flags field to check extra options. */ if (params->extra_flag & RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT) hw_trans_mem_support = 1; @@ -272,7 +291,7 @@ rte_hash_create(const struct rte_hash_parameters *params) else num_key_slots = params->entries + 1; - snprintf(ring_name, sizeof(ring_name), "HT_%s", params->name); + snprintf(ring_name, sizeof(ring_name), HASH_RING_PREFIX "%s", params->name); /* Create ring (Dummy slot index is not enqueued) */ r = rte_ring_create_elem(ring_name, sizeof(uint32_t), rte_align32pow2(num_key_slots), params->socket_id, 0); @@ -286,8 +305,8 @@ rte_hash_create(const struct rte_hash_parameters *params) /* Create ring for extendable buckets. */ if (ext_table_support) { - snprintf(ext_ring_name, sizeof(ext_ring_name), "HT_EXT_%s", - params->name); + snprintf(ext_ring_name, sizeof(ext_ring_name), + HASH_EXT_PREFIX "%s", params->name); r_ext = rte_ring_create_elem(ext_ring_name, sizeof(uint32_t), rte_align32pow2(num_buckets + 1), params->socket_id, 0); @@ -299,7 +318,7 @@ rte_hash_create(const struct rte_hash_parameters *params) } } - snprintf(hash_name, sizeof(hash_name), "HT_%s", params->name); + snprintf(hash_name, sizeof(hash_name), HASH_RING_PREFIX "%s", params->name); rte_mcfg_tailq_write_lock(); @@ -1582,7 +1601,8 @@ rte_hash_rcu_qsbr_add(struct rte_hash *h, struct rte_hash_rcu_config *cfg) char rcu_dq_name[RTE_RCU_QSBR_DQ_NAMESIZE]; struct rte_hash_rcu_config *hash_rcu_cfg = NULL; - if (h == NULL || cfg == NULL || cfg->v == NULL) { + if (h == NULL || cfg == NULL || cfg->v == NULL || + strlen(h->name) > RTE_RCU_QSBR_DQ_NAMESIZE - sizeof(HASH_QSBR_PREFIX)) { rte_errno = EINVAL; return 1; } @@ -1606,8 +1626,7 @@ rte_hash_rcu_qsbr_add(struct rte_hash *h, struct rte_hash_rcu_config *cfg) /* No other things to do. */ } else if (cfg->mode == RTE_HASH_QSBR_MODE_DQ) { /* Init QSBR defer queue. */ - snprintf(rcu_dq_name, sizeof(rcu_dq_name), - "HASH_RCU_%s", h->name); + snprintf(rcu_dq_name, sizeof(rcu_dq_name), HASH_QSBR_PREFIX "%s", h->name); params.name = rcu_dq_name; params.size = cfg->dq_size; if (params.size == 0) -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC 3/8] eal: warn if thread name is truncated 2025-12-02 17:24 [RFC 0/8] first steps in fixing buffer overflow Stephen Hemminger 2025-12-02 17:24 ` [RFC 1/8] eal: use C library to parse filesystem table Stephen Hemminger 2025-12-02 17:24 ` [RFC 2/8] hash: fix possible ring name overflow Stephen Hemminger @ 2025-12-02 17:24 ` Stephen Hemminger 2025-12-02 17:24 ` [RFC 4/8] eal: avoid format overflow when handling addresses Stephen Hemminger ` (5 subsequent siblings) 8 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-02 17:24 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Thread name is very short 16 characters and therefore the name dpdk-worker-%d will overflow with more than 9999 worker cores. Error should be non-fatal since name only matters for debug. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/linux/eal.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index b12f325ddd..d848de03d8 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -863,8 +863,10 @@ rte_eal_init(int argc, char **argv) rte_panic("Cannot create thread\n"); /* Set thread_name for aid in debugging. */ - snprintf(thread_name, sizeof(thread_name), - "dpdk-worker%d", i); + ret = snprintf(thread_name, sizeof(thread_name), "dpdk-worker%d", i); + if (ret >= RTE_THREAD_NAME_SIZE) + EAL_LOG(INFO, "Worker thread name %s truncated", thread_name); + rte_thread_set_name(lcore_config[i].thread_id, thread_name); ret = rte_thread_set_affinity_by_id(lcore_config[i].thread_id, -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC 4/8] eal: avoid format overflow when handling addresses 2025-12-02 17:24 [RFC 0/8] first steps in fixing buffer overflow Stephen Hemminger ` (2 preceding siblings ...) 2025-12-02 17:24 ` [RFC 3/8] eal: warn if thread name is truncated Stephen Hemminger @ 2025-12-02 17:24 ` Stephen Hemminger 2025-12-02 17:24 ` [RFC 5/8] ethdev: avoid possible overflow in xstat names Stephen Hemminger ` (4 subsequent siblings) 8 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-02 17:24 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Anatoly Burakov The largest possible string in this code 0xFFFFFFFFFFFFFFFF which will overflow with only 15 character buffer. Increase to 20. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c index c62edf5e55..2633857db5 100644 --- a/lib/eal/common/eal_common_memory.c +++ b/lib/eal/common/eal_common_memory.c @@ -1153,7 +1153,7 @@ rte_eal_memory_init(void) #define EAL_MEMSEG_INFO_REQ "/eal/memseg_info" #define EAL_ELEMENT_LIST_REQ "/eal/mem_element_list" #define EAL_ELEMENT_INFO_REQ "/eal/mem_element_info" -#define ADDR_STR 15 +#define ADDR_STR 20 /* 16 bytes 64 bit + 0x */ /* Telemetry callback handler to return heap stats for requested heap id. */ -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC 5/8] ethdev: avoid possible overflow in xstat names 2025-12-02 17:24 [RFC 0/8] first steps in fixing buffer overflow Stephen Hemminger ` (3 preceding siblings ...) 2025-12-02 17:24 ` [RFC 4/8] eal: avoid format overflow when handling addresses Stephen Hemminger @ 2025-12-02 17:24 ` Stephen Hemminger 2025-12-02 17:24 ` [RFC 6/8] efd: avoid overflowing ring name Stephen Hemminger ` (3 subsequent siblings) 8 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-02 17:24 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Thomas Monjalon, Andrew Rybchenko The compiler doesn't know that all the elements in the table of queue stats are short enough to avoid overflowing the snprintf. Add a condition that will not happen to warn if it ever does; maybe some day a new long named queue stat could be added. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/ethdev/rte_ethdev.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c index c6fe0d5165..5bd3fbc0bc 100644 --- a/lib/ethdev/rte_ethdev.c +++ b/lib/ethdev/rte_ethdev.c @@ -3501,10 +3501,16 @@ eth_basic_stats_get_names(struct rte_eth_dev *dev, num_q = RTE_MIN(dev->data->nb_rx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS); for (id_queue = 0; id_queue < num_q; id_queue++) { for (idx = 0; idx < RTE_NB_RXQ_STATS; idx++) { - snprintf(xstats_names[cnt_used_entries].name, - sizeof(xstats_names[0].name), - "rx_q%u_%s", - id_queue, eth_dev_rxq_stats_strings[idx].name); + unsigned int cc; + + cc = snprintf(xstats_names[cnt_used_entries].name, sizeof(xstats_names[0].name), + "rx_q%u_%s", + id_queue, eth_dev_rxq_stats_strings[idx].name); + + /* could only happen if a long string was added to eth_dev_rxq_stats_strings */ + if (cc >= sizeof(xstats_names[0].name)) + RTE_ETHDEV_LOG_LINE(ERR, "truncated rxq stat string '%s'", + eth_dev_rxq_stats_strings[idx].name); cnt_used_entries++; } @@ -3512,10 +3518,15 @@ eth_basic_stats_get_names(struct rte_eth_dev *dev, num_q = RTE_MIN(dev->data->nb_tx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS); for (id_queue = 0; id_queue < num_q; id_queue++) { for (idx = 0; idx < RTE_NB_TXQ_STATS; idx++) { - snprintf(xstats_names[cnt_used_entries].name, - sizeof(xstats_names[0].name), - "tx_q%u_%s", - id_queue, eth_dev_txq_stats_strings[idx].name); + unsigned int cc; + + cc = snprintf(xstats_names[cnt_used_entries].name, sizeof(xstats_names[0].name), + "tx_q%u_%s", + id_queue, eth_dev_txq_stats_strings[idx].name); + /* could only happen if a long string was added to eth_dev_rxq_stats_strings */ + if (cc >= sizeof(xstats_names[0].name)) + RTE_ETHDEV_LOG_LINE(ERR, "truncated txq stat string '%s'", + eth_dev_txq_stats_strings[idx].name); cnt_used_entries++; } } -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC 6/8] efd: avoid overflowing ring name 2025-12-02 17:24 [RFC 0/8] first steps in fixing buffer overflow Stephen Hemminger ` (4 preceding siblings ...) 2025-12-02 17:24 ` [RFC 5/8] ethdev: avoid possible overflow in xstat names Stephen Hemminger @ 2025-12-02 17:24 ` Stephen Hemminger 2025-12-02 17:24 ` [RFC 7/8] eal: add check for sysfs path overflow Stephen Hemminger ` (2 subsequent siblings) 8 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-02 17:24 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Byron Marohn, Yipeng Wang The efd library allowed table name to be longer than would be safe when prefix was added for a ring name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/efd/rte_efd.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/efd/rte_efd.c b/lib/efd/rte_efd.c index ebf1e0655f..61fd6a6646 100644 --- a/lib/efd/rte_efd.c +++ b/lib/efd/rte_efd.c @@ -36,6 +36,9 @@ RTE_LOG_REGISTER_DEFAULT(efd_logtype, INFO); #define EFD_LOG(level, ...) \ RTE_LOG_LINE(level, EFD, "" __VA_ARGS__) +/** Prefix used on ring name for hash */ +#define EFD_HASH_PREFIX "HT_" + #define EFD_KEY(key_idx, table) (table->keys + ((key_idx) * table->key_len)) /** Hash function used to determine chunk_id and bin_id for a group */ #define EFD_HASH(key, table) \ @@ -527,6 +530,15 @@ rte_efd_create(const char *name, uint32_t max_num_rules, uint32_t key_len, return NULL; } + /* + * The name is turned into a ring name which has a limit of + * RTE_RING_NAMESIZE. + */ + if (name == NULL || strnlen(name, RTE_RING_NAMESIZE) >= RTE_RING_NAMESIZE - sizeof(EFD_HASH_PREFIX)) { + EFD_LOG(ERR, "Invalid name '%s'", name); + return NULL; + } + /* * Compute the minimum number of chunks (smallest power of 2) * that can hold all of the rules @@ -698,7 +710,13 @@ rte_efd_create(const char *name, uint32_t max_num_rules, uint32_t key_len, TAILQ_INSERT_TAIL(efd_list, te, next); rte_mcfg_tailq_write_unlock(); - snprintf(ring_name, sizeof(ring_name), "HT_%s", table->name); + int cc = snprintf(ring_name, sizeof(ring_name), EFD_HASH_PREFIX "%s", table->name); + if (cc >= sizeof(ring_name)) { + EFD_LOG(ERR, "ring name '%s%s' overflow", EFD_HASH_PREFIX, table->name); + rte_efd_free(table); + return NULL; + } + /* Create ring (Dummy slot index is not enqueued) */ r = rte_ring_create(ring_name, rte_align32pow2(table->max_num_rules), offline_cpu_socket, 0); -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC 7/8] eal: add check for sysfs path overflow 2025-12-02 17:24 [RFC 0/8] first steps in fixing buffer overflow Stephen Hemminger ` (5 preceding siblings ...) 2025-12-02 17:24 ` [RFC 6/8] efd: avoid overflowing ring name Stephen Hemminger @ 2025-12-02 17:24 ` Stephen Hemminger 2025-12-02 17:24 ` [RFC 8/8] eal: limit maximum runtime directory and socket paths Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger 8 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-02 17:24 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger It shouldn't happen but in theory sysfs socket could overflow. Add a check for it. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/linux/eal_hugepage_info.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/eal/linux/eal_hugepage_info.c b/lib/eal/linux/eal_hugepage_info.c index 7161b1a2fb..fe3351259e 100644 --- a/lib/eal/linux/eal_hugepage_info.c +++ b/lib/eal/linux/eal_hugepage_info.c @@ -150,8 +150,12 @@ get_num_hugepages_on_node(const char *subdir, unsigned int socket, size_t sz) return 0; } - snprintf(path, sizeof(path), "%s/%s/%s", + if (snprintf(path, sizeof(path), "%s/%s/%s", socketpath, subdir, nr_hp_file) >= PATH_MAX) { + EAL_LOG(NOTICE, "Socket path %s/%s/%s is truncated", socketpath, subdir, nr_hp_file); + return 0; + } + if (eal_parse_sysfs_value(path, &num_pages) < 0) return 0; -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC 8/8] eal: limit maximum runtime directory and socket paths 2025-12-02 17:24 [RFC 0/8] first steps in fixing buffer overflow Stephen Hemminger ` (6 preceding siblings ...) 2025-12-02 17:24 ` [RFC 7/8] eal: add check for sysfs path overflow Stephen Hemminger @ 2025-12-02 17:24 ` Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger 8 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-02 17:24 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Anatoly Burakov Linux (and FreeBSD) has a limitation of 108 characters for any unix domain socket path. Therefore DPDK would not work if a really large runtime directory was used. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_config.c | 6 ++++-- lib/eal/common/eal_common_proc.c | 18 +++++++++--------- lib/eal/common/eal_filesystem.h | 6 +++++- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/eal/common/eal_common_config.c b/lib/eal/common/eal_common_config.c index 7fc7611a07..e2e69a75fb 100644 --- a/lib/eal/common/eal_common_config.c +++ b/lib/eal/common/eal_common_config.c @@ -6,6 +6,7 @@ #include <eal_export.h> #include "eal_private.h" +#include "eal_filesystem.h" #include "eal_memcfg.h" /* early configuration structure, when memory config is not mmapped */ @@ -24,7 +25,7 @@ static struct rte_config rte_config = { }; /* platform-specific runtime dir */ -static char runtime_dir[PATH_MAX]; +static char runtime_dir[UNIX_PATH_MAX]; /* internal configuration */ static struct internal_config internal_config; @@ -39,7 +40,8 @@ rte_eal_get_runtime_dir(void) int eal_set_runtime_dir(const char *run_dir) { - if (strlcpy(runtime_dir, run_dir, PATH_MAX) >= PATH_MAX) { + /* runtime directory limited by maximum allowable unix domain socket */ + if (strlcpy(runtime_dir, run_dir, UNIX_PATH_MAX) >= UNIX_PATH_MAX) { EAL_LOG(ERR, "Runtime directory string too long"); return -1; } diff --git a/lib/eal/common/eal_common_proc.c b/lib/eal/common/eal_common_proc.c index 62fd4ba88f..3c4a1850ff 100644 --- a/lib/eal/common/eal_common_proc.c +++ b/lib/eal/common/eal_common_proc.c @@ -36,10 +36,10 @@ static RTE_ATOMIC(int) mp_fd = -1; static rte_thread_t mp_handle_tid; -static char mp_filter[PATH_MAX]; /* Filter for secondary process sockets */ -static char mp_dir_path[PATH_MAX]; /* The directory path for all mp sockets */ +static char mp_filter[UNIX_PATH_MAX]; /* Filter for secondary process sockets */ +static char mp_dir_path[UNIX_PATH_MAX]; /* The directory path for all mp sockets */ static pthread_mutex_t mp_mutex_action = PTHREAD_MUTEX_INITIALIZER; -static char peer_name[PATH_MAX]; +static char peer_name[UNIX_PATH_MAX]; struct action_entry { TAILQ_ENTRY(action_entry) next; @@ -78,7 +78,7 @@ struct pending_request { REQUEST_TYPE_SYNC, REQUEST_TYPE_ASYNC } type; - char dst[PATH_MAX]; + char dst[UNIX_PATH_MAX]; struct rte_mp_msg *request; struct rte_mp_msg *reply; int reply_received; @@ -599,7 +599,7 @@ open_socket_fd(void) static void close_socket_fd(int fd) { - char path[PATH_MAX]; + char path[UNIX_PATH_MAX]; close(fd); create_socket_path(peer_name, path, sizeof(path)); @@ -609,7 +609,7 @@ close_socket_fd(int fd) int rte_mp_channel_init(void) { - char path[PATH_MAX]; + char path[UNIX_PATH_MAX]; int dir_fd; const struct internal_config *internal_conf = eal_get_internal_configuration(); @@ -779,7 +779,7 @@ mp_send(struct rte_mp_msg *msg, const char *peer, int type) } while ((ent = readdir(mp_dir))) { - char path[PATH_MAX]; + char path[UNIX_PATH_MAX]; if (fnmatch(mp_filter, ent->d_name, 0) != 0) continue; @@ -1055,7 +1055,7 @@ rte_mp_request_sync(struct rte_mp_msg *req, struct rte_mp_reply *reply, pthread_mutex_lock(&pending_requests.lock); while ((ent = readdir(mp_dir))) { - char path[PATH_MAX]; + char path[UNIX_PATH_MAX]; if (fnmatch(mp_filter, ent->d_name, 0) != 0) continue; @@ -1200,7 +1200,7 @@ rte_mp_request_async(struct rte_mp_msg *req, const struct timespec *ts, } while ((ent = readdir(mp_dir))) { - char path[PATH_MAX]; + char path[UNIX_PATH_MAX]; if (fnmatch(mp_filter, ent->d_name, 0) != 0) continue; diff --git a/lib/eal/common/eal_filesystem.h b/lib/eal/common/eal_filesystem.h index 5d21f07c20..5371d9f1d6 100644 --- a/lib/eal/common/eal_filesystem.h +++ b/lib/eal/common/eal_filesystem.h @@ -45,10 +45,14 @@ eal_runtime_config_path(void) /** Path of primary/secondary communication unix socket file. */ #define MP_SOCKET_FNAME "mp_socket" + +/** Maximum length of unix domain socket path as defined in sys/un.h */ +#define UNIX_PATH_MAX 108 + static inline const char * eal_mp_socket_path(void) { - static char buffer[PATH_MAX]; /* static so auto-zeroed */ + static char buffer[UNIX_PATH_MAX]; /* static so auto-zeroed */ snprintf(buffer, sizeof(buffer), "%s/%s", rte_eal_get_runtime_dir(), MP_SOCKET_FNAME); -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC v2 00/14] lib: check for string overflow 2025-12-02 17:24 [RFC 0/8] first steps in fixing buffer overflow Stephen Hemminger ` (7 preceding siblings ...) 2025-12-02 17:24 ` [RFC 8/8] eal: limit maximum runtime directory and socket paths Stephen Hemminger @ 2025-12-05 2:28 ` Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 01/14] eal: use C library to parse filesystem table Stephen Hemminger ` (14 more replies) 8 siblings, 15 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 2:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger First draft of changes to fix format overflow issues in EAL and related libraries. This does introduce more restrictions on file prefix and some parameters because of more checking for overflow. Stephen Hemminger (14): eal: use C library to parse filesystem table test: avoid long hash names lpm: restrict name size hash: avoid possible ring name overflow graph: avoid overflowing comment buffer eal: warn if thread name is truncated eal: avoid format overflow when handling addresses ethdev: avoid possible overflow in xstat names vhost: check for overflow in xstat name efd: avoid overflowing ring name eal: add check for sysfs path overflow eal: limit maximum runtime directory and socket paths eal: check for hugefile path overflow lib: enable format overflow warnings app/test/test_hash.c | 29 +++++++---- lib/eal/common/eal_common_config.c | 6 ++- lib/eal/common/eal_common_memory.c | 2 +- lib/eal/common/eal_common_proc.c | 83 +++++++++++++++++++----------- lib/eal/common/eal_filesystem.h | 16 ++++-- lib/eal/linux/eal.c | 6 ++- lib/eal/linux/eal_hugepage_info.c | 64 +++++++++-------------- lib/eal/linux/eal_memalloc.c | 11 +++- lib/eal/linux/eal_memory.c | 9 +++- lib/efd/rte_efd.c | 15 +++++- lib/ethdev/rte_ethdev.c | 28 +++++++--- lib/graph/graph_pcap.c | 9 ++-- lib/hash/rte_cuckoo_hash.c | 21 +++++--- lib/hash/rte_hash.h | 6 ++- lib/lpm/rte_lpm.h | 2 +- lib/meson.build | 4 -- lib/vhost/vhost.c | 14 +++-- 17 files changed, 202 insertions(+), 123 deletions(-) -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC v2 01/14] eal: use C library to parse filesystem table 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger @ 2025-12-05 2:28 ` Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 02/14] test: avoid long hash names Stephen Hemminger ` (13 subsequent siblings) 14 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 2:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson Rather than doing parsing of /proc/mounts with open coded string handling, use the standard C library routines. These exist in BSD and Linux. It also avoids any possible issues with escaped strings etc which the library handles. See getmntent(3) man page. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- lib/eal/linux/eal_hugepage_info.c | 58 ++++++++++--------------------- 1 file changed, 18 insertions(+), 40 deletions(-) diff --git a/lib/eal/linux/eal_hugepage_info.c b/lib/eal/linux/eal_hugepage_info.c index d47a19c56a..7161b1a2fb 100644 --- a/lib/eal/linux/eal_hugepage_info.c +++ b/lib/eal/linux/eal_hugepage_info.c @@ -13,6 +13,7 @@ #include <inttypes.h> #include <unistd.h> #include <errno.h> +#include <mntent.h> #include <sys/mman.h> #include <sys/stat.h> @@ -195,23 +196,13 @@ get_default_hp_size(void) static int get_hugepage_dir(uint64_t hugepage_sz, char *hugedir, int len) { - enum proc_mount_fieldnames { - DEVICE = 0, - MOUNTPT, - FSTYPE, - OPTIONS, - _FIELDNAME_MAX - }; static uint64_t default_size = 0; const char proc_mounts[] = "/proc/mounts"; - const char hugetlbfs_str[] = "hugetlbfs"; - const size_t htlbfs_str_len = sizeof(hugetlbfs_str) - 1; const char pagesize_opt[] = "pagesize="; const size_t pagesize_opt_len = sizeof(pagesize_opt) - 1; - const char split_tok = ' '; - char *splitstr[_FIELDNAME_MAX]; char found[PATH_MAX] = ""; char buf[BUFSIZ]; + struct mntent entry; const struct internal_config *internal_conf = eal_get_internal_configuration(); const size_t hugepage_dir_len = (internal_conf->hugepage_dir != NULL) ? @@ -226,56 +217,43 @@ get_hugepage_dir(uint64_t hugepage_sz, char *hugedir, int len) return -1; } - FILE *fd = fopen(proc_mounts, "r"); - if (fd == NULL) + FILE *mounts = setmntent(proc_mounts, "r"); + if (mounts == NULL) rte_panic("Cannot open %s\n", proc_mounts); if (default_size == 0) default_size = get_default_hp_size(); - while (fgets(buf, sizeof(buf), fd)){ + while (getmntent_r(mounts, &entry, buf, sizeof(buf))) { const char *pagesz_str; - size_t mountpt_len = 0; - - if (rte_strsplit(buf, sizeof(buf), splitstr, _FIELDNAME_MAX, - split_tok) != _FIELDNAME_MAX) { - EAL_LOG(ERR, "Error parsing %s", proc_mounts); - break; /* return NULL */ - } + uint64_t pagesz = default_size; + size_t mountpt_len; - if (strncmp(splitstr[FSTYPE], hugetlbfs_str, htlbfs_str_len) != 0) + if (strcmp(entry.mnt_type, "hugetlbfs") != 0) continue; - pagesz_str = strstr(splitstr[OPTIONS], pagesize_opt); + pagesz_str = strstr(entry.mnt_opts, pagesize_opt); + if (pagesz_str) + pagesz = rte_str_to_size(&pagesz_str[pagesize_opt_len]); - /* if no explicit page size, the default page size is compared */ - if (pagesz_str == NULL) { - if (hugepage_sz != default_size) - continue; - } - /* there is an explicit page size, so check it */ - else { - uint64_t pagesz = rte_str_to_size(&pagesz_str[pagesize_opt_len]); - if (pagesz != hugepage_sz) - continue; - } + if (pagesz != hugepage_sz) + continue; /* * If no --huge-dir option has been given, we're done. */ if (internal_conf->hugepage_dir == NULL) { - strlcpy(found, splitstr[MOUNTPT], len); + strlcpy(found, entry.mnt_dir, len); break; } - mountpt_len = strlen(splitstr[MOUNTPT]); + mountpt_len = strlen(entry.mnt_dir); /* * Ignore any mount that doesn't contain the --huge-dir directory * or where mount point is not a parent path of --huge-dir */ - if (strncmp(internal_conf->hugepage_dir, splitstr[MOUNTPT], - mountpt_len) != 0 || + if (strncmp(internal_conf->hugepage_dir, entry.mnt_dir, mountpt_len) != 0 || (hugepage_dir_len > mountpt_len && internal_conf->hugepage_dir[mountpt_len] != '/')) { continue; @@ -286,10 +264,10 @@ get_hugepage_dir(uint64_t hugepage_sz, char *hugedir, int len) * (so /mnt/1 is preferred over /mnt for matching /mnt/1/2)). */ if (mountpt_len > strlen(found)) - strlcpy(found, splitstr[MOUNTPT], len); + strlcpy(found, entry.mnt_dir, len); } /* end while fgets */ - fclose(fd); + endmntent(mounts); if (found[0] != '\0') { /* If needed, return the requested dir, not the mount point. */ -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC v2 02/14] test: avoid long hash names 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 01/14] eal: use C library to parse filesystem table Stephen Hemminger @ 2025-12-05 2:28 ` Stephen Hemminger 2025-12-05 8:29 ` Bruce Richardson 2025-12-05 2:28 ` [RFC v2 03/14] lpm: restrict name size Stephen Hemminger ` (12 subsequent siblings) 14 siblings, 1 reply; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 2:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, stable The test was using hash table names which were too long and would break if the hash library was checking the parameters. Fixes: af75078fece3 ("first public release") Fixes: 9c7d8eed1a45 ("test/hash: add RCU tests") Fixes: 567bb951716f ("hash: reclaim RCU defer queue") Cc: stable@dpdk.org Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_hash.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/app/test/test_hash.c b/app/test/test_hash.c index 5791fd7f4c..8cecc28d11 100644 --- a/app/test/test_hash.c +++ b/app/test/test_hash.c @@ -1399,8 +1399,16 @@ static int test_hash_creation_with_bad_parameters(void) return -1; } - memcpy(¶ms, &ut_params, sizeof(params)); - params.name = "creation_with_bad_parameters_0"; + params = ut_params; + params.name = "really_long_name_of_22"; + handle = rte_hash_create(¶ms); + if (handle != NULL) { + rte_hash_free(handle); + printf("Impossible creating hash successfully with excessively long name\n"); + return -1; + } + + params.name = "with_bad_parameters_0"; params.entries = RTE_HASH_ENTRIES_MAX + 1; handle = rte_hash_create(¶ms); if (handle != NULL) { @@ -1410,7 +1418,7 @@ static int test_hash_creation_with_bad_parameters(void) } memcpy(¶ms, &ut_params, sizeof(params)); - params.name = "creation_with_bad_parameters_2"; + params.name = "with_bad_parameters_2"; params.entries = BUCKET_ENTRIES - 1; handle = rte_hash_create(¶ms); if (handle != NULL) { @@ -1420,7 +1428,7 @@ static int test_hash_creation_with_bad_parameters(void) } memcpy(¶ms, &ut_params, sizeof(params)); - params.name = "creation_with_bad_parameters_3"; + params.name = "with_bad_parameters_3"; params.key_len = 0; handle = rte_hash_create(¶ms); if (handle != NULL) { @@ -1430,7 +1438,7 @@ static int test_hash_creation_with_bad_parameters(void) } memcpy(¶ms, &ut_params, sizeof(params)); - params.name = "creation_with_bad_parameters_4"; + params.name = "with_bad_parameters_4"; params.socket_id = RTE_MAX_NUMA_NODES + 1; handle = rte_hash_create(¶ms); if (handle != NULL) { @@ -1510,7 +1518,8 @@ static int test_average_table_utilization(uint32_t ext_table) printf("Measuring performance, please wait"); fflush(stdout); ut_params.entries = 1 << 16; - ut_params.name = "test_average_utilization"; + /* the maximum length of name is 21 characters */ + ut_params.name = "test_avge_utilization"; ut_params.hash_func = rte_jhash; if (ext_table) ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE; @@ -1898,7 +1907,7 @@ test_hash_rcu_qsbr_add(void) printf("\n# Running RCU QSBR add tests\n"); memcpy(¶ms, &ut_params, sizeof(params)); - params.name = "test_hash_rcu_qsbr_add"; + params.name = "test_hash_qsbr_add"; params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF | RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD; g_handle = rte_hash_create(¶ms); @@ -1976,7 +1985,7 @@ test_hash_rcu_qsbr_dq_mode(uint8_t ext_bkt) hash_extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE; struct rte_hash_parameters params_pseudo_hash = { - .name = "test_hash_rcu_qsbr_dq_mode", + .name = "test_hash_qsbr_mode", .entries = total_entries, .key_len = sizeof(struct flow_key), .hash_func = pseudo_hash, @@ -2146,7 +2155,7 @@ test_hash_rcu_qsbr_sync_mode(uint8_t ext_bkt) hash_extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE; struct rte_hash_parameters params_pseudo_hash = { - .name = "test_hash_rcu_qsbr_sync_mode", + .name = "test_hash_qsbr_sync", .entries = total_entries, .key_len = sizeof(struct flow_key), .hash_func = pseudo_hash, @@ -2250,7 +2259,7 @@ test_hash_rcu_qsbr_dq_reclaim(void) uint32_t reclaim_keys[8] = {10, 11, 12, 13, 14, 15, 16, 17}; struct rte_hash_rcu_config rcu_cfg = {0}; struct rte_hash_parameters hash_params = { - .name = "test_hash_rcu_qsbr_dq_reclaim", + .name = "test_qsbr_reclaim", .entries = total_entries, .key_len = sizeof(uint32_t), .hash_func = NULL, -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [RFC v2 02/14] test: avoid long hash names 2025-12-05 2:28 ` [RFC v2 02/14] test: avoid long hash names Stephen Hemminger @ 2025-12-05 8:29 ` Bruce Richardson 2025-12-05 17:00 ` Stephen Hemminger 0 siblings, 1 reply; 48+ messages in thread From: Bruce Richardson @ 2025-12-05 8:29 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev, stable On Thu, Dec 04, 2025 at 06:28:11PM -0800, Stephen Hemminger wrote: > The test was using hash table names which were too long and > would break if the hash library was checking the parameters. > > Fixes: af75078fece3 ("first public release") > Fixes: 9c7d8eed1a45 ("test/hash: add RCU tests") > Fixes: 567bb951716f ("hash: reclaim RCU defer queue") > Cc: stable@dpdk.org > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- > app/test/test_hash.c | 29 +++++++++++++++++++---------- > 1 file changed, 19 insertions(+), 10 deletions(-) > > diff --git a/app/test/test_hash.c b/app/test/test_hash.c > index 5791fd7f4c..8cecc28d11 100644 > --- a/app/test/test_hash.c > +++ b/app/test/test_hash.c > @@ -1399,8 +1399,16 @@ static int test_hash_creation_with_bad_parameters(void) > return -1; > } > > - memcpy(¶ms, &ut_params, sizeof(params)); > - params.name = "creation_with_bad_parameters_0"; > + params = ut_params; > + params.name = "really_long_name_of_22"; > + handle = rte_hash_create(¶ms); > + if (handle != NULL) { > + rte_hash_free(handle); > + printf("Impossible creating hash successfully with excessively long name\n"); > + return -1; > + } > + I'm not sure about this behaviour, for something like the hash name. I'd tend more towards having the hash library just truncate the name rather than returning an error if it was too long. Also, I worry that this could break end-applications which were relying on previous behaviour of ignoring long names. What do you/others think? /Bruce ^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [RFC v2 02/14] test: avoid long hash names 2025-12-05 8:29 ` Bruce Richardson @ 2025-12-05 17:00 ` Stephen Hemminger 2025-12-05 18:19 ` Bruce Richardson 0 siblings, 1 reply; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 17:00 UTC (permalink / raw) To: Bruce Richardson; +Cc: dev, stable On Fri, 5 Dec 2025 08:29:39 +0000 Bruce Richardson <bruce.richardson@intel.com> wrote: > On Thu, Dec 04, 2025 at 06:28:11PM -0800, Stephen Hemminger wrote: > > The test was using hash table names which were too long and > > would break if the hash library was checking the parameters. > > > > Fixes: af75078fece3 ("first public release") > > Fixes: 9c7d8eed1a45 ("test/hash: add RCU tests") > > Fixes: 567bb951716f ("hash: reclaim RCU defer queue") > > Cc: stable@dpdk.org > > > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > > --- > > app/test/test_hash.c | 29 +++++++++++++++++++---------- > > 1 file changed, 19 insertions(+), 10 deletions(-) > > > > diff --git a/app/test/test_hash.c b/app/test/test_hash.c > > index 5791fd7f4c..8cecc28d11 100644 > > --- a/app/test/test_hash.c > > +++ b/app/test/test_hash.c > > @@ -1399,8 +1399,16 @@ static int test_hash_creation_with_bad_parameters(void) > > return -1; > > } > > > > - memcpy(¶ms, &ut_params, sizeof(params)); > > - params.name = "creation_with_bad_parameters_0"; > > + params = ut_params; > > + params.name = "really_long_name_of_22"; > > + handle = rte_hash_create(¶ms); > > + if (handle != NULL) { > > + rte_hash_free(handle); > > + printf("Impossible creating hash successfully with excessively long name\n"); > > + return -1; > > + } > > + > > I'm not sure about this behaviour, for something like the hash name. I'd > tend more towards having the hash library just truncate the name rather > than returning an error if it was too long. > > Also, I worry that this could break end-applications which were relying on > previous behaviour of ignoring long names. > > What do you/others think? Truncating the name could create issues where two hashes end up sharing a ring underneath. ^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [RFC v2 02/14] test: avoid long hash names 2025-12-05 17:00 ` Stephen Hemminger @ 2025-12-05 18:19 ` Bruce Richardson 0 siblings, 0 replies; 48+ messages in thread From: Bruce Richardson @ 2025-12-05 18:19 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev, stable On Fri, Dec 05, 2025 at 09:00:03AM -0800, Stephen Hemminger wrote: > On Fri, 5 Dec 2025 08:29:39 +0000 > Bruce Richardson <bruce.richardson@intel.com> wrote: > > > On Thu, Dec 04, 2025 at 06:28:11PM -0800, Stephen Hemminger wrote: > > > The test was using hash table names which were too long and > > > would break if the hash library was checking the parameters. > > > > > > Fixes: af75078fece3 ("first public release") > > > Fixes: 9c7d8eed1a45 ("test/hash: add RCU tests") > > > Fixes: 567bb951716f ("hash: reclaim RCU defer queue") > > > Cc: stable@dpdk.org > > > > > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > > > --- > > > app/test/test_hash.c | 29 +++++++++++++++++++---------- > > > 1 file changed, 19 insertions(+), 10 deletions(-) > > > > > > diff --git a/app/test/test_hash.c b/app/test/test_hash.c > > > index 5791fd7f4c..8cecc28d11 100644 > > > --- a/app/test/test_hash.c > > > +++ b/app/test/test_hash.c > > > @@ -1399,8 +1399,16 @@ static int test_hash_creation_with_bad_parameters(void) > > > return -1; > > > } > > > > > > - memcpy(¶ms, &ut_params, sizeof(params)); > > > - params.name = "creation_with_bad_parameters_0"; > > > + params = ut_params; > > > + params.name = "really_long_name_of_22"; > > > + handle = rte_hash_create(¶ms); > > > + if (handle != NULL) { > > > + rte_hash_free(handle); > > > + printf("Impossible creating hash successfully with excessively long name\n"); > > > + return -1; > > > + } > > > + > > > > I'm not sure about this behaviour, for something like the hash name. I'd > > tend more towards having the hash library just truncate the name rather > > than returning an error if it was too long. > > > > Also, I worry that this could break end-applications which were relying on > > previous behaviour of ignoring long names. > > > > What do you/others think? > > Truncating the name could create issues where two hashes end up sharing a ring > underneath. > Yes, I realise that. However, we have been silently truncating for years without reported issues, therefore I think it is safer to go from "silently truncating" to "noisily truncating", rather than jumping straight to "failing the API". ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC v2 03/14] lpm: restrict name size 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 01/14] eal: use C library to parse filesystem table Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 02/14] test: avoid long hash names Stephen Hemminger @ 2025-12-05 2:28 ` Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 04/14] hash: avoid possible ring name overflow Stephen Hemminger ` (11 subsequent siblings) 14 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 2:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Since LPM uses ring internally with a prefix, limit the maximum allowed LPM name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/lpm/rte_lpm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lpm/rte_lpm.h b/lib/lpm/rte_lpm.h index edfe77b458..21a93b7e44 100644 --- a/lib/lpm/rte_lpm.h +++ b/lib/lpm/rte_lpm.h @@ -26,7 +26,7 @@ extern "C" { #endif /** Max number of characters in LPM name. */ -#define RTE_LPM_NAMESIZE 32 +#define RTE_LPM_NAMESIZE (RTE_RING_NAMESIZE - sizeof("LPM_RCU_") + 1) /** Maximum depth value possible for IPv4 LPM. */ #define RTE_LPM_MAX_DEPTH 32 -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC v2 04/14] hash: avoid possible ring name overflow 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger ` (2 preceding siblings ...) 2025-12-05 2:28 ` [RFC v2 03/14] lpm: restrict name size Stephen Hemminger @ 2025-12-05 2:28 ` Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 05/14] graph: avoid overflowing comment buffer Stephen Hemminger ` (10 subsequent siblings) 14 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 2:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger The maximum possible hash parameter name will cause the generated ring names to overflow in snprintf(). Potentially causing conflicting ring names and duplicate rings. For reference: RTE_MEMPOOL_NAMESIZE = 32 RTE_RING_NAMESIZE = 29 RTE_HASH_NAMESIZE = 32 This version changes RTE_HASH_NAMESIZE since not hardcoded into any ABI. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/hash/rte_cuckoo_hash.c | 21 +++++++++++++++------ lib/hash/rte_hash.h | 6 ++++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/hash/rte_cuckoo_hash.c b/lib/hash/rte_cuckoo_hash.c index 2c92c51624..8c5d4c417c 100644 --- a/lib/hash/rte_cuckoo_hash.c +++ b/lib/hash/rte_cuckoo_hash.c @@ -77,6 +77,10 @@ struct __rte_hash_rcu_dq_entry { uint32_t ext_bkt_idx; }; +#define HASH_QSBR_PREFIX "HT_RCU_" +#define HASH_EXT_PREFIX "HT_EXT_" +#define HASH_RING_PREFIX "HT_" + RTE_EXPORT_SYMBOL(rte_hash_find_existing) struct rte_hash * rte_hash_find_existing(const char *name) @@ -222,6 +226,12 @@ rte_hash_create(const struct rte_hash_parameters *params) return NULL; } + if (strnlen(params->name, RTE_HASH_NAMESIZE) >= RTE_HASH_NAMESIZE) { + rte_errno = ENAMETOOLONG; + HASH_LOG(ERR, "%s(): name '%s' too long", __func__, params->name); + return NULL; + } + /* Validate correct usage of extra options */ if ((params->extra_flag & RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY) && (params->extra_flag & RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF)) { @@ -272,7 +282,7 @@ rte_hash_create(const struct rte_hash_parameters *params) else num_key_slots = params->entries + 1; - snprintf(ring_name, sizeof(ring_name), "HT_%s", params->name); + snprintf(ring_name, sizeof(ring_name), HASH_RING_PREFIX "%s", params->name); /* Create ring (Dummy slot index is not enqueued) */ r = rte_ring_create_elem(ring_name, sizeof(uint32_t), rte_align32pow2(num_key_slots), params->socket_id, 0); @@ -286,8 +296,8 @@ rte_hash_create(const struct rte_hash_parameters *params) /* Create ring for extendable buckets. */ if (ext_table_support) { - snprintf(ext_ring_name, sizeof(ext_ring_name), "HT_EXT_%s", - params->name); + snprintf(ext_ring_name, sizeof(ext_ring_name), + HASH_EXT_PREFIX "%s", params->name); r_ext = rte_ring_create_elem(ext_ring_name, sizeof(uint32_t), rte_align32pow2(num_buckets + 1), params->socket_id, 0); @@ -299,7 +309,7 @@ rte_hash_create(const struct rte_hash_parameters *params) } } - snprintf(hash_name, sizeof(hash_name), "HT_%s", params->name); + snprintf(hash_name, sizeof(hash_name), HASH_RING_PREFIX "%s", params->name); rte_mcfg_tailq_write_lock(); @@ -1606,8 +1616,7 @@ rte_hash_rcu_qsbr_add(struct rte_hash *h, struct rte_hash_rcu_config *cfg) /* No other things to do. */ } else if (cfg->mode == RTE_HASH_QSBR_MODE_DQ) { /* Init QSBR defer queue. */ - snprintf(rcu_dq_name, sizeof(rcu_dq_name), - "HASH_RCU_%s", h->name); + snprintf(rcu_dq_name, sizeof(rcu_dq_name), HASH_QSBR_PREFIX "%s", h->name); params.name = rcu_dq_name; params.size = cfg->dq_size; if (params.size == 0) diff --git a/lib/hash/rte_hash.h b/lib/hash/rte_hash.h index f692e0868d..7292610064 100644 --- a/lib/hash/rte_hash.h +++ b/lib/hash/rte_hash.h @@ -24,8 +24,10 @@ extern "C" { /** Maximum size of hash table that can be created. */ #define RTE_HASH_ENTRIES_MAX (1 << 30) -/** Maximum number of characters in hash name.*/ -#define RTE_HASH_NAMESIZE 32 +/** Maximum number of characters in hash name. + * Limited by ring name (used internally) with prefix. + */ +#define RTE_HASH_NAMESIZE (RTE_RING_NAMESIZE - sizeof("HT_EXT_") + 1) /** Maximum number of keys that can be searched for using rte_hash_lookup_bulk. */ #define RTE_HASH_LOOKUP_BULK_MAX 64 -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC v2 05/14] graph: avoid overflowing comment buffer 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger ` (3 preceding siblings ...) 2025-12-05 2:28 ` [RFC v2 04/14] hash: avoid possible ring name overflow Stephen Hemminger @ 2025-12-05 2:28 ` Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 06/14] eal: warn if thread name is truncated Stephen Hemminger ` (9 subsequent siblings) 14 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 2:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger The library builds a pcapng comment to put on each packet but the buffer is not big enough for the largest possible graph node name, etc. Change to use asprintf() to allow any string length. Note, if asprintf() fails it is better to still log the packet without comment so no data is lost. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/graph/graph_pcap.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/graph/graph_pcap.c b/lib/graph/graph_pcap.c index 08dcda0d28..602be79ced 100644 --- a/lib/graph/graph_pcap.c +++ b/lib/graph/graph_pcap.c @@ -194,7 +194,7 @@ graph_pcap_dispatch(struct rte_graph *graph, uint16_t nb_objs) { struct rte_mbuf *mbuf_clones[RTE_GRAPH_BURST_SIZE]; - char buffer[GRAPH_PCAP_BUF_SZ]; + char *comment = NULL; uint64_t i, num_packets; struct rte_mbuf *mbuf; ssize_t len; @@ -207,19 +207,22 @@ graph_pcap_dispatch(struct rte_graph *graph, if (num_packets > nb_objs) num_packets = nb_objs; - snprintf(buffer, GRAPH_PCAP_BUF_SZ, "%s: %s", graph->name, node->name); + /* put a comment on all these packets */ + if (asprintf(&comment, "%s: %s", graph->name, node->name) < 0) + graph_err("asprintf for comment failed."); for (i = 0; i < num_packets; i++) { struct rte_mbuf *mc; mbuf = (struct rte_mbuf *)objs[i]; mc = rte_pcapng_copy(mbuf->port, 0, mbuf, pkt_mp, mbuf->pkt_len, - 0, buffer); + 0, comment); if (mc == NULL) break; mbuf_clones[i] = mc; } + free(comment); /* write it to capture file */ len = rte_pcapng_write_packets(pcapng_fd, mbuf_clones, i); -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC v2 06/14] eal: warn if thread name is truncated 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger ` (4 preceding siblings ...) 2025-12-05 2:28 ` [RFC v2 05/14] graph: avoid overflowing comment buffer Stephen Hemminger @ 2025-12-05 2:28 ` Stephen Hemminger 2025-12-05 8:32 ` Bruce Richardson 2025-12-05 2:28 ` [RFC v2 07/14] eal: avoid format overflow when handling addresses Stephen Hemminger ` (8 subsequent siblings) 14 siblings, 1 reply; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 2:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Thread name is very short 16 characters and therefore the name dpdk-worker-%d will overflow with more than 9999 worker cores. Error should be non-fatal since name only matters for debug. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/linux/eal.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index b12f325ddd..d848de03d8 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -863,8 +863,10 @@ rte_eal_init(int argc, char **argv) rte_panic("Cannot create thread\n"); /* Set thread_name for aid in debugging. */ - snprintf(thread_name, sizeof(thread_name), - "dpdk-worker%d", i); + ret = snprintf(thread_name, sizeof(thread_name), "dpdk-worker%d", i); + if (ret >= RTE_THREAD_NAME_SIZE) + EAL_LOG(INFO, "Worker thread name %s truncated", thread_name); + rte_thread_set_name(lcore_config[i].thread_id, thread_name); ret = rte_thread_set_affinity_by_id(lcore_config[i].thread_id, -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [RFC v2 06/14] eal: warn if thread name is truncated 2025-12-05 2:28 ` [RFC v2 06/14] eal: warn if thread name is truncated Stephen Hemminger @ 2025-12-05 8:32 ` Bruce Richardson 0 siblings, 0 replies; 48+ messages in thread From: Bruce Richardson @ 2025-12-05 8:32 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev On Thu, Dec 04, 2025 at 06:28:15PM -0800, Stephen Hemminger wrote: > Thread name is very short 16 characters and therefore the name > dpdk-worker-%d will overflow with more than 9999 worker cores. > Error should be non-fatal since name only matters for debug. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- Can't see this issue being hit any time soon, but no harm. Acked-by: Bruce Richardson <bruce.richardson@intel.com> > lib/eal/linux/eal.c | 6 ++++-- > 1 file changed, 4 insertions(+), 2 deletions(-) > > diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c > index b12f325ddd..d848de03d8 100644 > --- a/lib/eal/linux/eal.c > +++ b/lib/eal/linux/eal.c > @@ -863,8 +863,10 @@ rte_eal_init(int argc, char **argv) > rte_panic("Cannot create thread\n"); > > /* Set thread_name for aid in debugging. */ > - snprintf(thread_name, sizeof(thread_name), > - "dpdk-worker%d", i); > + ret = snprintf(thread_name, sizeof(thread_name), "dpdk-worker%d", i); > + if (ret >= RTE_THREAD_NAME_SIZE) > + EAL_LOG(INFO, "Worker thread name %s truncated", thread_name); > + > rte_thread_set_name(lcore_config[i].thread_id, thread_name); > > ret = rte_thread_set_affinity_by_id(lcore_config[i].thread_id, > -- > 2.51.0 > ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC v2 07/14] eal: avoid format overflow when handling addresses 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger ` (5 preceding siblings ...) 2025-12-05 2:28 ` [RFC v2 06/14] eal: warn if thread name is truncated Stephen Hemminger @ 2025-12-05 2:28 ` Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 08/14] ethdev: avoid possible overflow in xstat names Stephen Hemminger ` (7 subsequent siblings) 14 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 2:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger The largest possible string in this code 0xFFFFFFFFFFFFFFFF which will overflow with only 15 character buffer. Increase to 20. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c index c62edf5e55..2633857db5 100644 --- a/lib/eal/common/eal_common_memory.c +++ b/lib/eal/common/eal_common_memory.c @@ -1153,7 +1153,7 @@ rte_eal_memory_init(void) #define EAL_MEMSEG_INFO_REQ "/eal/memseg_info" #define EAL_ELEMENT_LIST_REQ "/eal/mem_element_list" #define EAL_ELEMENT_INFO_REQ "/eal/mem_element_info" -#define ADDR_STR 15 +#define ADDR_STR 20 /* 16 bytes 64 bit + 0x */ /* Telemetry callback handler to return heap stats for requested heap id. */ -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC v2 08/14] ethdev: avoid possible overflow in xstat names 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger ` (6 preceding siblings ...) 2025-12-05 2:28 ` [RFC v2 07/14] eal: avoid format overflow when handling addresses Stephen Hemminger @ 2025-12-05 2:28 ` Stephen Hemminger 2025-12-05 8:34 ` Bruce Richardson 2025-12-05 2:28 ` [RFC v2 09/14] vhost: check for overflow in xstat name Stephen Hemminger ` (6 subsequent siblings) 14 siblings, 1 reply; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 2:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger The compiler doesn't know that all the elements in the table of queue stats are short enough to avoid overflowing the snprintf. Add a condition that will not happen to warn if it ever does; maybe some day a new long named queue stat could be added. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/ethdev/rte_ethdev.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c index c6fe0d5165..20a6ce3450 100644 --- a/lib/ethdev/rte_ethdev.c +++ b/lib/ethdev/rte_ethdev.c @@ -3501,10 +3501,17 @@ eth_basic_stats_get_names(struct rte_eth_dev *dev, num_q = RTE_MIN(dev->data->nb_rx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS); for (id_queue = 0; id_queue < num_q; id_queue++) { for (idx = 0; idx < RTE_NB_RXQ_STATS; idx++) { - snprintf(xstats_names[cnt_used_entries].name, - sizeof(xstats_names[0].name), - "rx_q%u_%s", - id_queue, eth_dev_rxq_stats_strings[idx].name); + unsigned int cc; + + cc = snprintf(xstats_names[cnt_used_entries].name, + sizeof(xstats_names[0].name), + "rx_q%u_%s", + id_queue, eth_dev_rxq_stats_strings[idx].name); + + /* could only happen if a long string was added */ + if (cc >= sizeof(xstats_names[0].name)) + RTE_ETHDEV_LOG_LINE(ERR, "truncated rxq stat string '%s'", + eth_dev_rxq_stats_strings[idx].name); cnt_used_entries++; } @@ -3512,10 +3519,15 @@ eth_basic_stats_get_names(struct rte_eth_dev *dev, num_q = RTE_MIN(dev->data->nb_tx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS); for (id_queue = 0; id_queue < num_q; id_queue++) { for (idx = 0; idx < RTE_NB_TXQ_STATS; idx++) { - snprintf(xstats_names[cnt_used_entries].name, - sizeof(xstats_names[0].name), - "tx_q%u_%s", - id_queue, eth_dev_txq_stats_strings[idx].name); + unsigned int cc; + + cc = snprintf(xstats_names[cnt_used_entries].name, + sizeof(xstats_names[0].name), + "tx_q%u_%s", + id_queue, eth_dev_txq_stats_strings[idx].name); + if (cc >= sizeof(xstats_names[0].name)) + RTE_ETHDEV_LOG_LINE(ERR, "truncated txq stat string '%s'", + eth_dev_txq_stats_strings[idx].name); cnt_used_entries++; } } -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [RFC v2 08/14] ethdev: avoid possible overflow in xstat names 2025-12-05 2:28 ` [RFC v2 08/14] ethdev: avoid possible overflow in xstat names Stephen Hemminger @ 2025-12-05 8:34 ` Bruce Richardson 0 siblings, 0 replies; 48+ messages in thread From: Bruce Richardson @ 2025-12-05 8:34 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev On Thu, Dec 04, 2025 at 06:28:17PM -0800, Stephen Hemminger wrote: > The compiler doesn't know that all the elements in the table > of queue stats are short enough to avoid overflowing the snprintf. > Add a condition that will not happen to warn if it ever does; > maybe some day a new long named queue stat could be added. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- > lib/ethdev/rte_ethdev.c | 28 ++++++++++++++++++++-------- > 1 file changed, 20 insertions(+), 8 deletions(-) Acked-by: Bruce Richardson <bruce.richardson@intel.com> > > diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c > index c6fe0d5165..20a6ce3450 100644 > --- a/lib/ethdev/rte_ethdev.c > +++ b/lib/ethdev/rte_ethdev.c > @@ -3501,10 +3501,17 @@ eth_basic_stats_get_names(struct rte_eth_dev *dev, > num_q = RTE_MIN(dev->data->nb_rx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS); > for (id_queue = 0; id_queue < num_q; id_queue++) { > for (idx = 0; idx < RTE_NB_RXQ_STATS; idx++) { > - snprintf(xstats_names[cnt_used_entries].name, > - sizeof(xstats_names[0].name), > - "rx_q%u_%s", > - id_queue, eth_dev_rxq_stats_strings[idx].name); > + unsigned int cc; > + > + cc = snprintf(xstats_names[cnt_used_entries].name, > + sizeof(xstats_names[0].name), > + "rx_q%u_%s", > + id_queue, eth_dev_rxq_stats_strings[idx].name); > + > + /* could only happen if a long string was added */ > + if (cc >= sizeof(xstats_names[0].name)) > + RTE_ETHDEV_LOG_LINE(ERR, "truncated rxq stat string '%s'", > + eth_dev_rxq_stats_strings[idx].name); > cnt_used_entries++; > } > > @@ -3512,10 +3519,15 @@ eth_basic_stats_get_names(struct rte_eth_dev *dev, > num_q = RTE_MIN(dev->data->nb_tx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS); > for (id_queue = 0; id_queue < num_q; id_queue++) { > for (idx = 0; idx < RTE_NB_TXQ_STATS; idx++) { > - snprintf(xstats_names[cnt_used_entries].name, > - sizeof(xstats_names[0].name), > - "tx_q%u_%s", > - id_queue, eth_dev_txq_stats_strings[idx].name); > + unsigned int cc; > + > + cc = snprintf(xstats_names[cnt_used_entries].name, > + sizeof(xstats_names[0].name), > + "tx_q%u_%s", > + id_queue, eth_dev_txq_stats_strings[idx].name); > + if (cc >= sizeof(xstats_names[0].name)) > + RTE_ETHDEV_LOG_LINE(ERR, "truncated txq stat string '%s'", > + eth_dev_txq_stats_strings[idx].name); > cnt_used_entries++; > } > } > -- > 2.51.0 > ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC v2 09/14] vhost: check for overflow in xstat name 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger ` (7 preceding siblings ...) 2025-12-05 2:28 ` [RFC v2 08/14] ethdev: avoid possible overflow in xstat names Stephen Hemminger @ 2025-12-05 2:28 ` Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 10/14] efd: avoid overflowing ring name Stephen Hemminger ` (5 subsequent siblings) 14 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 2:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger The snprintf to format an xstat name could overflow if called with a long rte_vhost_stat_name. Check if that happens and warn. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/vhost/vhost.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/vhost/vhost.c b/lib/vhost/vhost.c index 416f082dca..540f4e0635 100644 --- a/lib/vhost/vhost.c +++ b/lib/vhost/vhost.c @@ -2200,6 +2200,7 @@ rte_vhost_vring_stats_get_names(int vid, uint16_t queue_id, { struct virtio_net *dev = get_device(vid); unsigned int i; + int ret; if (dev == NULL) return -1; @@ -2213,10 +2214,15 @@ rte_vhost_vring_stats_get_names(int vid, uint16_t queue_id, if (name == NULL || size < VHOST_NB_VQ_STATS) return VHOST_NB_VQ_STATS; - for (i = 0; i < VHOST_NB_VQ_STATS; i++) - snprintf(name[i].name, sizeof(name[i].name), "%s_q%u_%s", - (queue_id & 1) ? "rx" : "tx", - queue_id / 2, vhost_vq_stat_strings[i].name); + for (i = 0; i < VHOST_NB_VQ_STATS; i++) { + ret = snprintf(name[i].name, sizeof(name[i].name), "%s_q%u_%s", + (queue_id & 1) ? "rx" : "tx", + queue_id / 2, vhost_vq_stat_strings[i].name); + if (ret >= (int)sizeof(name[0].name)) + VHOST_CONFIG_LOG("device", NOTICE, "truncated xstat '%s_q%u_%s'", + (queue_id & 1) ? "rx" : "tx", + queue_id / 2, vhost_vq_stat_strings[i].name); + } return VHOST_NB_VQ_STATS; } -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC v2 10/14] efd: avoid overflowing ring name 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger ` (8 preceding siblings ...) 2025-12-05 2:28 ` [RFC v2 09/14] vhost: check for overflow in xstat name Stephen Hemminger @ 2025-12-05 2:28 ` Stephen Hemminger 2025-12-05 8:37 ` Bruce Richardson 2025-12-05 2:28 ` [RFC v2 11/14] eal: add check for sysfs path overflow Stephen Hemminger ` (4 subsequent siblings) 14 siblings, 1 reply; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 2:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger The efd library allowed table name to be longer than would be safe when prefix was added for a ring name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/efd/rte_efd.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/efd/rte_efd.c b/lib/efd/rte_efd.c index ebf1e0655f..b4ea8fdf33 100644 --- a/lib/efd/rte_efd.c +++ b/lib/efd/rte_efd.c @@ -36,6 +36,9 @@ RTE_LOG_REGISTER_DEFAULT(efd_logtype, INFO); #define EFD_LOG(level, ...) \ RTE_LOG_LINE(level, EFD, "" __VA_ARGS__) +/** Prefix used on ring name for hash */ +#define EFD_HASH_PREFIX "HT_" + #define EFD_KEY(key_idx, table) (table->keys + ((key_idx) * table->key_len)) /** Hash function used to determine chunk_id and bin_id for a group */ #define EFD_HASH(key, table) \ @@ -527,6 +530,17 @@ rte_efd_create(const char *name, uint32_t max_num_rules, uint32_t key_len, return NULL; } + if (name == NULL) { + EFD_LOG(ERR, "Invalid name '%s'", name); + return NULL; + } + + if (snprintf(ring_name, sizeof(ring_name), + EFD_HASH_PREFIX "%s", name) >= (int)sizeof(ring_name)) { + EFD_LOG(ERR, "ring name '%s%s' overflow", EFD_HASH_PREFIX, table->name); + return NULL; + } + /* * Compute the minimum number of chunks (smallest power of 2) * that can hold all of the rules @@ -698,7 +712,6 @@ rte_efd_create(const char *name, uint32_t max_num_rules, uint32_t key_len, TAILQ_INSERT_TAIL(efd_list, te, next); rte_mcfg_tailq_write_unlock(); - snprintf(ring_name, sizeof(ring_name), "HT_%s", table->name); /* Create ring (Dummy slot index is not enqueued) */ r = rte_ring_create(ring_name, rte_align32pow2(table->max_num_rules), offline_cpu_socket, 0); -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [RFC v2 10/14] efd: avoid overflowing ring name 2025-12-05 2:28 ` [RFC v2 10/14] efd: avoid overflowing ring name Stephen Hemminger @ 2025-12-05 8:37 ` Bruce Richardson 0 siblings, 0 replies; 48+ messages in thread From: Bruce Richardson @ 2025-12-05 8:37 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev On Thu, Dec 04, 2025 at 06:28:19PM -0800, Stephen Hemminger wrote: > The efd library allowed table name to be longer than would be > safe when prefix was added for a ring name. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- > lib/efd/rte_efd.c | 15 ++++++++++++++- > 1 file changed, 14 insertions(+), 1 deletion(-) > Again, not convinced that truncating is a problem here, if we document that only N characters of the name are preserved. We can warn and continue rather than returning error. /Bruce > diff --git a/lib/efd/rte_efd.c b/lib/efd/rte_efd.c > index ebf1e0655f..b4ea8fdf33 100644 > --- a/lib/efd/rte_efd.c > +++ b/lib/efd/rte_efd.c > @@ -36,6 +36,9 @@ RTE_LOG_REGISTER_DEFAULT(efd_logtype, INFO); > #define EFD_LOG(level, ...) \ > RTE_LOG_LINE(level, EFD, "" __VA_ARGS__) > > +/** Prefix used on ring name for hash */ > +#define EFD_HASH_PREFIX "HT_" > + > #define EFD_KEY(key_idx, table) (table->keys + ((key_idx) * table->key_len)) > /** Hash function used to determine chunk_id and bin_id for a group */ > #define EFD_HASH(key, table) \ > @@ -527,6 +530,17 @@ rte_efd_create(const char *name, uint32_t max_num_rules, uint32_t key_len, > return NULL; > } > > + if (name == NULL) { > + EFD_LOG(ERR, "Invalid name '%s'", name); > + return NULL; > + } > + > + if (snprintf(ring_name, sizeof(ring_name), > + EFD_HASH_PREFIX "%s", name) >= (int)sizeof(ring_name)) { > + EFD_LOG(ERR, "ring name '%s%s' overflow", EFD_HASH_PREFIX, table->name); > + return NULL; > + } > + > /* > * Compute the minimum number of chunks (smallest power of 2) > * that can hold all of the rules > @@ -698,7 +712,6 @@ rte_efd_create(const char *name, uint32_t max_num_rules, uint32_t key_len, > TAILQ_INSERT_TAIL(efd_list, te, next); > rte_mcfg_tailq_write_unlock(); > > - snprintf(ring_name, sizeof(ring_name), "HT_%s", table->name); > /* Create ring (Dummy slot index is not enqueued) */ > r = rte_ring_create(ring_name, rte_align32pow2(table->max_num_rules), > offline_cpu_socket, 0); > -- > 2.51.0 > ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC v2 11/14] eal: add check for sysfs path overflow 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger ` (9 preceding siblings ...) 2025-12-05 2:28 ` [RFC v2 10/14] efd: avoid overflowing ring name Stephen Hemminger @ 2025-12-05 2:28 ` Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 12/14] eal: limit maximum runtime directory and socket paths Stephen Hemminger ` (3 subsequent siblings) 14 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 2:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Shouldn't happen but in theory sysfs socket could overflow. Add a check for it. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/linux/eal_hugepage_info.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/eal/linux/eal_hugepage_info.c b/lib/eal/linux/eal_hugepage_info.c index 7161b1a2fb..fe3351259e 100644 --- a/lib/eal/linux/eal_hugepage_info.c +++ b/lib/eal/linux/eal_hugepage_info.c @@ -150,8 +150,12 @@ get_num_hugepages_on_node(const char *subdir, unsigned int socket, size_t sz) return 0; } - snprintf(path, sizeof(path), "%s/%s/%s", + if (snprintf(path, sizeof(path), "%s/%s/%s", socketpath, subdir, nr_hp_file) >= PATH_MAX) { + EAL_LOG(NOTICE, "Socket path %s/%s/%s is truncated", socketpath, subdir, nr_hp_file); + return 0; + } + if (eal_parse_sysfs_value(path, &num_pages) < 0) return 0; -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC v2 12/14] eal: limit maximum runtime directory and socket paths 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger ` (10 preceding siblings ...) 2025-12-05 2:28 ` [RFC v2 11/14] eal: add check for sysfs path overflow Stephen Hemminger @ 2025-12-05 2:28 ` Stephen Hemminger 2025-12-05 8:46 ` Bruce Richardson 2025-12-05 2:28 ` [RFC v2 13/14] eal: check for hugefile path overflow Stephen Hemminger ` (2 subsequent siblings) 14 siblings, 1 reply; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 2:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Linux (and FreeBSD) has a limitation of 108 characters for any unix domain socket path. Therefore DPDK would not work if a really large runtime directory was used. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_config.c | 6 ++- lib/eal/common/eal_common_proc.c | 83 +++++++++++++++++++----------- lib/eal/common/eal_filesystem.h | 6 ++- 3 files changed, 63 insertions(+), 32 deletions(-) diff --git a/lib/eal/common/eal_common_config.c b/lib/eal/common/eal_common_config.c index 7fc7611a07..e2e69a75fb 100644 --- a/lib/eal/common/eal_common_config.c +++ b/lib/eal/common/eal_common_config.c @@ -6,6 +6,7 @@ #include <eal_export.h> #include "eal_private.h" +#include "eal_filesystem.h" #include "eal_memcfg.h" /* early configuration structure, when memory config is not mmapped */ @@ -24,7 +25,7 @@ static struct rte_config rte_config = { }; /* platform-specific runtime dir */ -static char runtime_dir[PATH_MAX]; +static char runtime_dir[UNIX_PATH_MAX]; /* internal configuration */ static struct internal_config internal_config; @@ -39,7 +40,8 @@ rte_eal_get_runtime_dir(void) int eal_set_runtime_dir(const char *run_dir) { - if (strlcpy(runtime_dir, run_dir, PATH_MAX) >= PATH_MAX) { + /* runtime directory limited by maximum allowable unix domain socket */ + if (strlcpy(runtime_dir, run_dir, UNIX_PATH_MAX) >= UNIX_PATH_MAX) { EAL_LOG(ERR, "Runtime directory string too long"); return -1; } diff --git a/lib/eal/common/eal_common_proc.c b/lib/eal/common/eal_common_proc.c index 62fd4ba88f..dbf749c5b8 100644 --- a/lib/eal/common/eal_common_proc.c +++ b/lib/eal/common/eal_common_proc.c @@ -36,10 +36,10 @@ static RTE_ATOMIC(int) mp_fd = -1; static rte_thread_t mp_handle_tid; -static char mp_filter[PATH_MAX]; /* Filter for secondary process sockets */ -static char mp_dir_path[PATH_MAX]; /* The directory path for all mp sockets */ +static char mp_filter[UNIX_PATH_MAX]; /* Filter for secondary process sockets */ +static char mp_dir_path[UNIX_PATH_MAX]; /* The directory path for all mp sockets */ static pthread_mutex_t mp_mutex_action = PTHREAD_MUTEX_INITIALIZER; -static char peer_name[PATH_MAX]; +static char peer_name[UNIX_PATH_MAX]; struct action_entry { TAILQ_ENTRY(action_entry) next; @@ -78,7 +78,7 @@ struct pending_request { REQUEST_TYPE_SYNC, REQUEST_TYPE_ASYNC } type; - char dst[PATH_MAX]; + char dst[UNIX_PATH_MAX]; struct rte_mp_msg *request; struct rte_mp_msg *reply; int reply_received; @@ -132,15 +132,19 @@ find_pending_request(const char *dst, const char *act_name) return r; } -static void -create_socket_path(const char *name, char *buf, int len) +static int +create_socket_path(const char *name, char *buf, size_t len) { const char *prefix = eal_mp_socket_path(); - if (strlen(name) > 0) - snprintf(buf, len, "%s_%s", prefix, name); - else - strlcpy(buf, prefix, len); + if (strlen(name) > 0) { + if (snprintf(buf, len, "%s_%s", prefix, name) >= (int)len) + return -1; + } else { + if (strlcpy(buf, prefix, len) >= len) + return -1; + } + return 0; } RTE_EXPORT_SYMBOL(rte_eal_primary_proc_alive) @@ -572,6 +576,11 @@ open_socket_fd(void) snprintf(peer_name, sizeof(peer_name), "%d_%"PRIx64, getpid(), rte_rdtsc()); + if (create_socket_path(peer_name, un.sun_path, sizeof(un.sun_path)) < 0) { + EAL_LOG(ERR, "peer '%s' socket path too long", peer_name); + return -1; + } + mp_fd = socket(AF_UNIX, SOCK_DGRAM, 0); if (mp_fd < 0) { EAL_LOG(ERR, "failed to create unix socket"); @@ -581,8 +590,6 @@ open_socket_fd(void) memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; - create_socket_path(peer_name, un.sun_path, sizeof(un.sun_path)); - unlink(un.sun_path); /* May still exist since last run */ if (bind(mp_fd, (struct sockaddr *)&un, sizeof(un)) < 0) { @@ -599,17 +606,20 @@ open_socket_fd(void) static void close_socket_fd(int fd) { - char path[PATH_MAX]; + char path[UNIX_PATH_MAX]; close(fd); - create_socket_path(peer_name, path, sizeof(path)); - unlink(path); + + if (create_socket_path(peer_name, path, sizeof(path)) < 0) + EAL_LOG(ERR, "file prefix path for peerr '%s' too long", peer_name); + else + unlink(path); } int rte_mp_channel_init(void) { - char path[PATH_MAX]; + char path[UNIX_PATH_MAX]; int dir_fd; const struct internal_config *internal_conf = eal_get_internal_configuration(); @@ -624,7 +634,12 @@ rte_mp_channel_init(void) } /* create filter path */ - create_socket_path("*", path, sizeof(path)); + if (create_socket_path("*", path, sizeof(path)) < 0) { + EAL_LOG(ERR, "file prefix path too long"); + rte_errno = ENAMETOOLONG; + return -1; + } + rte_basename(path, mp_filter, sizeof(mp_filter)); strlcpy(mp_dir_path, dirname(path), sizeof(mp_dir_path)); @@ -779,14 +794,17 @@ mp_send(struct rte_mp_msg *msg, const char *peer, int type) } while ((ent = readdir(mp_dir))) { - char path[PATH_MAX]; + char path[UNIX_PATH_MAX]; if (fnmatch(mp_filter, ent->d_name, 0) != 0) continue; - snprintf(path, sizeof(path), "%s/%s", mp_dir_path, - ent->d_name); - if (send_msg(path, msg, type) < 0) + if (snprintf(path, sizeof(path), "%s/%s", + mp_dir_path, ent->d_name) >= (int)sizeof(path)) { + EAL_LOG(ERR, "Unix domain path %s/%s too long", + mp_dir_path, ent->d_name); + ret = -1; + } else if (send_msg(path, msg, type) < 0) ret = -1; } /* unlock the dir */ @@ -1055,13 +1073,18 @@ rte_mp_request_sync(struct rte_mp_msg *req, struct rte_mp_reply *reply, pthread_mutex_lock(&pending_requests.lock); while ((ent = readdir(mp_dir))) { - char path[PATH_MAX]; + char path[UNIX_PATH_MAX]; if (fnmatch(mp_filter, ent->d_name, 0) != 0) continue; - snprintf(path, sizeof(path), "%s/%s", mp_dir_path, - ent->d_name); + if (snprintf(path, sizeof(path), "%s/%s", + mp_dir_path, ent->d_name) >= (int)sizeof(path)) { + EAL_LOG(ERR, "Unix domain socket path '%s/%s' too long", + mp_dir_path, ent->d_name); + rte_errno = ENAMETOOLONG; + goto unlock_end; + } /* unlocks the mutex while waiting for response, * locks on receive @@ -1200,15 +1223,17 @@ rte_mp_request_async(struct rte_mp_msg *req, const struct timespec *ts, } while ((ent = readdir(mp_dir))) { - char path[PATH_MAX]; + char path[UNIX_PATH_MAX]; if (fnmatch(mp_filter, ent->d_name, 0) != 0) continue; - snprintf(path, sizeof(path), "%s/%s", mp_dir_path, - ent->d_name); - - if (mp_request_async(path, copy, param, ts)) + if (snprintf(path, sizeof(path), "%s/%s", + mp_dir_path, ent->d_name) >= (int)sizeof(path)) { + EAL_LOG(ERR, "Unix domain path %s/%s too long", + mp_dir_path, ent->d_name); + ret = -1; + } else if (mp_request_async(path, copy, param, ts)) ret = -1; } /* if we didn't send anything, put dummy request on the queue */ diff --git a/lib/eal/common/eal_filesystem.h b/lib/eal/common/eal_filesystem.h index 5d21f07c20..5371d9f1d6 100644 --- a/lib/eal/common/eal_filesystem.h +++ b/lib/eal/common/eal_filesystem.h @@ -45,10 +45,14 @@ eal_runtime_config_path(void) /** Path of primary/secondary communication unix socket file. */ #define MP_SOCKET_FNAME "mp_socket" + +/** Maximum length of unix domain socket path as defined in sys/un.h */ +#define UNIX_PATH_MAX 108 + static inline const char * eal_mp_socket_path(void) { - static char buffer[PATH_MAX]; /* static so auto-zeroed */ + static char buffer[UNIX_PATH_MAX]; /* static so auto-zeroed */ snprintf(buffer, sizeof(buffer), "%s/%s", rte_eal_get_runtime_dir(), MP_SOCKET_FNAME); -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [RFC v2 12/14] eal: limit maximum runtime directory and socket paths 2025-12-05 2:28 ` [RFC v2 12/14] eal: limit maximum runtime directory and socket paths Stephen Hemminger @ 2025-12-05 8:46 ` Bruce Richardson 0 siblings, 0 replies; 48+ messages in thread From: Bruce Richardson @ 2025-12-05 8:46 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev On Thu, Dec 04, 2025 at 06:28:21PM -0800, Stephen Hemminger wrote: > Linux (and FreeBSD) has a limitation of 108 characters for > any unix domain socket path. Therefore DPDK would not work > if a really large runtime directory was used. > FreeBSD actually limits it to 104 [1]. Should reduce the define by that extra amount. /Bruce [1] https://man.freebsd.org/cgi/man.cgi?query=unix&sektion=4 > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- > lib/eal/common/eal_common_config.c | 6 ++- > lib/eal/common/eal_common_proc.c | 83 +++++++++++++++++++----------- > lib/eal/common/eal_filesystem.h | 6 ++- > 3 files changed, 63 insertions(+), 32 deletions(-) > ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC v2 13/14] eal: check for hugefile path overflow 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger ` (11 preceding siblings ...) 2025-12-05 2:28 ` [RFC v2 12/14] eal: limit maximum runtime directory and socket paths Stephen Hemminger @ 2025-12-05 2:28 ` Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 14/14] lib: enable format overflow warnings Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger 14 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 2:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger When constructing huge filename path, check for possible overflow of PATH_MAX. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_filesystem.h | 10 ++++++---- lib/eal/linux/eal_memalloc.c | 11 +++++++++-- lib/eal/linux/eal_memory.c | 9 +++++++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/lib/eal/common/eal_filesystem.h b/lib/eal/common/eal_filesystem.h index 5371d9f1d6..006d2ff3e5 100644 --- a/lib/eal/common/eal_filesystem.h +++ b/lib/eal/common/eal_filesystem.h @@ -93,12 +93,14 @@ eal_hugepage_data_path(void) /** String format for hugepage map files. */ #define HUGEFILE_FMT "%s/%smap_%d" -static inline const char * +static inline __rte_warn_unused_result const char * eal_get_hugefile_path(char *buffer, size_t buflen, const char *hugedir, int f_id) { - snprintf(buffer, buflen, HUGEFILE_FMT, hugedir, - eal_get_hugefile_prefix(), f_id); - return buffer; + if (snprintf(buffer, buflen, HUGEFILE_FMT, hugedir, + eal_get_hugefile_prefix(), f_id) >= (int)buflen) + return NULL; + else + return buffer; } /** define the default filename prefix for the %s values above */ diff --git a/lib/eal/linux/eal_memalloc.c b/lib/eal/linux/eal_memalloc.c index 1e60e21620..d9e8ea76b9 100644 --- a/lib/eal/linux/eal_memalloc.c +++ b/lib/eal/linux/eal_memalloc.c @@ -260,6 +260,7 @@ get_seg_fd(char *path, int buflen, struct hugepage_info *hi, { int fd; int *out_fd; + const char *huge_path; struct stat st; int ret; const struct internal_config *internal_conf = @@ -276,12 +277,18 @@ get_seg_fd(char *path, int buflen, struct hugepage_info *hi, if (internal_conf->single_file_segments) { out_fd = &fd_list[list_idx].memseg_list_fd; - eal_get_hugefile_path(path, buflen, hi->hugedir, list_idx); + huge_path = eal_get_hugefile_path(path, buflen, hi->hugedir, list_idx); } else { out_fd = &fd_list[list_idx].fds[seg_idx]; - eal_get_hugefile_path(path, buflen, hi->hugedir, + huge_path = eal_get_hugefile_path(path, buflen, hi->hugedir, list_idx * RTE_MAX_MEMSEG_PER_LIST + seg_idx); } + if (huge_path == NULL) { + EAL_LOG(DEBUG, "%s(): hugefile path truncated: '%s'", + __func__, path); + return -1; + } + fd = *out_fd; if (fd >= 0) return fd; diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c index 8e1763e890..2a0a441398 100644 --- a/lib/eal/linux/eal_memory.c +++ b/lib/eal/linux/eal_memory.c @@ -337,8 +337,13 @@ map_all_hugepages(struct hugepage_file *hugepg_tbl, struct hugepage_info *hpi, hf->file_id = i; hf->size = hugepage_sz; - eal_get_hugefile_path(hf->filepath, sizeof(hf->filepath), - hpi->hugedir, hf->file_id); + if (eal_get_hugefile_path(hf->filepath, sizeof(hf->filepath), + hpi->hugedir, hf->file_id) == NULL) { + EAL_LOG(DEBUG, "%s(): huge file path '%s' truncated", + __func__, hf->filepath); + goto out; + } + hf->filepath[sizeof(hf->filepath) - 1] = '\0'; /* try to create hugepage file */ -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [RFC v2 14/14] lib: enable format overflow warnings 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger ` (12 preceding siblings ...) 2025-12-05 2:28 ` [RFC v2 13/14] eal: check for hugefile path overflow Stephen Hemminger @ 2025-12-05 2:28 ` Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger 14 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 2:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Enable compiler checking of format overflow Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/meson.build | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/meson.build b/lib/meson.build index c8f4270868..8f5cfd28a5 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -113,10 +113,6 @@ default_cflags = machine_args default_cflags += ['-DALLOW_EXPERIMENTAL_API'] default_cflags += ['-DALLOW_INTERNAL_API'] -if cc.has_argument('-Wno-format-truncation') - default_cflags += '-Wno-format-truncation' -endif - foreach l:libraries build = true reason = '<unknown reason>' # set if build == false to explain why -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3 00/16] lib: find and fix possible string overflows 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger ` (13 preceding siblings ...) 2025-12-05 2:28 ` [RFC v2 14/14] lib: enable format overflow warnings Stephen Hemminger @ 2025-12-05 20:11 ` Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 01/16] eal: use C library to parse filesystem table Stephen Hemminger ` (15 more replies) 14 siblings, 16 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 20:11 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Change all the libraries to find and fix cases where a string could overflow when formatting or using strclpy. This does provide early indication of possible problems where the file prefix is too long to fit in unix domain socket path, and where a hash table is being requested that has a name too long. v3 - allow longer hash names but warn if ring names get truncated - pickup some other places like latencystats and tailq - add release note - fix build on FreeBSD Stephen Hemminger (16): eal: use C library to parse filesystem table lpm: restrict name size hash: add checks for hash name length graph: avoid overflowing comment buffer latencystats: add check for string overflow efd: handle possible name truncation eal: warn if thread name is truncated eal: avoid format overflow when handling addresses eal: add check for sysfs path overflow eal: limit maximum runtime directory and socket paths eal: check for hugefile path overflow eal: check tailq length eal: handle long shared library path ethdev: avoid possible overflow in xstat names vhost: check for overflow in xstat name lib: enable format overflow warnings app/test/test_hash.c | 21 +++++++ doc/guides/rel_notes/release_26_03.rst | 3 + lib/eal/common/eal_common_config.c | 6 +- lib/eal/common/eal_common_memory.c | 2 +- lib/eal/common/eal_common_options.c | 17 ++++-- lib/eal/common/eal_common_proc.c | 83 +++++++++++++++++--------- lib/eal/common/eal_common_tailqs.c | 5 ++ lib/eal/common/eal_filesystem.h | 17 ++++-- lib/eal/linux/eal.c | 6 +- lib/eal/linux/eal_hugepage_info.c | 64 +++++++------------- lib/eal/linux/eal_memalloc.c | 11 +++- lib/eal/linux/eal_memory.c | 9 ++- lib/efd/rte_efd.c | 7 ++- lib/ethdev/rte_ethdev.c | 35 +++++++---- lib/graph/graph_pcap.c | 9 ++- lib/hash/rte_cuckoo_hash.c | 41 +++++++++---- lib/hash/rte_fbk_hash.c | 13 +++- lib/latencystats/rte_latencystats.c | 9 ++- lib/lpm/rte_lpm.h | 2 +- lib/meson.build | 4 -- lib/vhost/vhost.c | 14 +++-- 21 files changed, 248 insertions(+), 130 deletions(-) -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3 01/16] eal: use C library to parse filesystem table 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger @ 2025-12-05 20:11 ` Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 02/16] lpm: restrict name size Stephen Hemminger ` (14 subsequent siblings) 15 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 20:11 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson Rather than doing parsing of /proc/mounts with open coded string handling, use the standard C library routines. These exist in BSD and Linux. It also avoids any possible issues with escaped strings etc which the library handles. See getmntent(3) man page. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- lib/eal/linux/eal_hugepage_info.c | 58 ++++++++++--------------------- 1 file changed, 18 insertions(+), 40 deletions(-) diff --git a/lib/eal/linux/eal_hugepage_info.c b/lib/eal/linux/eal_hugepage_info.c index d47a19c56a..7161b1a2fb 100644 --- a/lib/eal/linux/eal_hugepage_info.c +++ b/lib/eal/linux/eal_hugepage_info.c @@ -13,6 +13,7 @@ #include <inttypes.h> #include <unistd.h> #include <errno.h> +#include <mntent.h> #include <sys/mman.h> #include <sys/stat.h> @@ -195,23 +196,13 @@ get_default_hp_size(void) static int get_hugepage_dir(uint64_t hugepage_sz, char *hugedir, int len) { - enum proc_mount_fieldnames { - DEVICE = 0, - MOUNTPT, - FSTYPE, - OPTIONS, - _FIELDNAME_MAX - }; static uint64_t default_size = 0; const char proc_mounts[] = "/proc/mounts"; - const char hugetlbfs_str[] = "hugetlbfs"; - const size_t htlbfs_str_len = sizeof(hugetlbfs_str) - 1; const char pagesize_opt[] = "pagesize="; const size_t pagesize_opt_len = sizeof(pagesize_opt) - 1; - const char split_tok = ' '; - char *splitstr[_FIELDNAME_MAX]; char found[PATH_MAX] = ""; char buf[BUFSIZ]; + struct mntent entry; const struct internal_config *internal_conf = eal_get_internal_configuration(); const size_t hugepage_dir_len = (internal_conf->hugepage_dir != NULL) ? @@ -226,56 +217,43 @@ get_hugepage_dir(uint64_t hugepage_sz, char *hugedir, int len) return -1; } - FILE *fd = fopen(proc_mounts, "r"); - if (fd == NULL) + FILE *mounts = setmntent(proc_mounts, "r"); + if (mounts == NULL) rte_panic("Cannot open %s\n", proc_mounts); if (default_size == 0) default_size = get_default_hp_size(); - while (fgets(buf, sizeof(buf), fd)){ + while (getmntent_r(mounts, &entry, buf, sizeof(buf))) { const char *pagesz_str; - size_t mountpt_len = 0; - - if (rte_strsplit(buf, sizeof(buf), splitstr, _FIELDNAME_MAX, - split_tok) != _FIELDNAME_MAX) { - EAL_LOG(ERR, "Error parsing %s", proc_mounts); - break; /* return NULL */ - } + uint64_t pagesz = default_size; + size_t mountpt_len; - if (strncmp(splitstr[FSTYPE], hugetlbfs_str, htlbfs_str_len) != 0) + if (strcmp(entry.mnt_type, "hugetlbfs") != 0) continue; - pagesz_str = strstr(splitstr[OPTIONS], pagesize_opt); + pagesz_str = strstr(entry.mnt_opts, pagesize_opt); + if (pagesz_str) + pagesz = rte_str_to_size(&pagesz_str[pagesize_opt_len]); - /* if no explicit page size, the default page size is compared */ - if (pagesz_str == NULL) { - if (hugepage_sz != default_size) - continue; - } - /* there is an explicit page size, so check it */ - else { - uint64_t pagesz = rte_str_to_size(&pagesz_str[pagesize_opt_len]); - if (pagesz != hugepage_sz) - continue; - } + if (pagesz != hugepage_sz) + continue; /* * If no --huge-dir option has been given, we're done. */ if (internal_conf->hugepage_dir == NULL) { - strlcpy(found, splitstr[MOUNTPT], len); + strlcpy(found, entry.mnt_dir, len); break; } - mountpt_len = strlen(splitstr[MOUNTPT]); + mountpt_len = strlen(entry.mnt_dir); /* * Ignore any mount that doesn't contain the --huge-dir directory * or where mount point is not a parent path of --huge-dir */ - if (strncmp(internal_conf->hugepage_dir, splitstr[MOUNTPT], - mountpt_len) != 0 || + if (strncmp(internal_conf->hugepage_dir, entry.mnt_dir, mountpt_len) != 0 || (hugepage_dir_len > mountpt_len && internal_conf->hugepage_dir[mountpt_len] != '/')) { continue; @@ -286,10 +264,10 @@ get_hugepage_dir(uint64_t hugepage_sz, char *hugedir, int len) * (so /mnt/1 is preferred over /mnt for matching /mnt/1/2)). */ if (mountpt_len > strlen(found)) - strlcpy(found, splitstr[MOUNTPT], len); + strlcpy(found, entry.mnt_dir, len); } /* end while fgets */ - fclose(fd); + endmntent(mounts); if (found[0] != '\0') { /* If needed, return the requested dir, not the mount point. */ -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3 02/16] lpm: restrict name size 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 01/16] eal: use C library to parse filesystem table Stephen Hemminger @ 2025-12-05 20:11 ` Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 03/16] hash: add checks for hash name length Stephen Hemminger ` (13 subsequent siblings) 15 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 20:11 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson, Vladimir Medvedkin Since LPM uses ring internally with a prefix, limit the maximum allowed LPM name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/lpm/rte_lpm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lpm/rte_lpm.h b/lib/lpm/rte_lpm.h index edfe77b458..21a93b7e44 100644 --- a/lib/lpm/rte_lpm.h +++ b/lib/lpm/rte_lpm.h @@ -26,7 +26,7 @@ extern "C" { #endif /** Max number of characters in LPM name. */ -#define RTE_LPM_NAMESIZE 32 +#define RTE_LPM_NAMESIZE (RTE_RING_NAMESIZE - sizeof("LPM_RCU_") + 1) /** Maximum depth value possible for IPv4 LPM. */ #define RTE_LPM_MAX_DEPTH 32 -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3 03/16] hash: add checks for hash name length 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 01/16] eal: use C library to parse filesystem table Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 02/16] lpm: restrict name size Stephen Hemminger @ 2025-12-05 20:11 ` Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 04/16] graph: avoid overflowing comment buffer Stephen Hemminger ` (12 subsequent siblings) 15 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 20:11 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Yipeng Wang, Sameh Gobriel, Bruce Richardson, Vladimir Medvedkin Add a missing check to the API that the name is within the current defined maximum name size. This name is then used internally to create ring names, those names could get truncated; if a name is truncated add message to log. If ring creation fails it might be because of name conflict, so change the log message to decode error value. Add additional tests as well. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_hash.c | 21 +++++++++++++ doc/guides/rel_notes/release_26_03.rst | 3 ++ lib/hash/rte_cuckoo_hash.c | 41 ++++++++++++++++++-------- lib/hash/rte_fbk_hash.c | 13 ++++++-- 4 files changed, 64 insertions(+), 14 deletions(-) diff --git a/app/test/test_hash.c b/app/test/test_hash.c index 5791fd7f4c..0b608a3d74 100644 --- a/app/test/test_hash.c +++ b/app/test/test_hash.c @@ -1120,6 +1120,14 @@ fbk_hash_unit_test(void) .socket_id = RTE_MAX_NUMA_NODES + 1, /* invalid socket */ }; + /* try and create hash with an excessively long name */ + struct rte_fbk_hash_params invalid_params_long_name = { + .name = "four_byte_key_hash_name_length_32", + .entries = 4, + .entries_per_bucket = 2, + .socket_id = 0, + }; + /* try to create two hashes with identical names * in this case, trying to create a second one will not * fail but will simply return pointer to the existing @@ -1201,6 +1209,9 @@ fbk_hash_unit_test(void) handle = rte_fbk_hash_create(&invalid_params_7); RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); + handle = rte_fbk_hash_create(&invalid_params_long_name); + RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); + if (rte_eal_has_hugepages()) { handle = rte_fbk_hash_create(&invalid_params_8); RETURN_IF_ERROR_FBK(handle != NULL, @@ -1439,6 +1450,16 @@ static int test_hash_creation_with_bad_parameters(void) return -1; } + memcpy(¶ms, &ut_params, sizeof(params)); + params.name = "hash_creation_with_too_long_name"; + params.socket_id = RTE_MAX_NUMA_NODES + 1; + handle = rte_hash_create(¶ms); + if (handle != NULL) { + rte_hash_free(handle); + printf("Impossible creating hash successfully with long name\n"); + return -1; + } + /* test with same name should fail */ memcpy(¶ms, &ut_params, sizeof(params)); params.name = "same_name"; diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst index 15dabee7a1..a12bd41e86 100644 --- a/doc/guides/rel_notes/release_26_03.rst +++ b/doc/guides/rel_notes/release_26_03.rst @@ -84,6 +84,9 @@ API Changes Also, make sure to start the actual text at the margin. ======================================================= +* hash: Added name length validation to hash creation. + The hash name in hash parameters is now checked against RTE_HASH_NAMESIZE. + ABI Changes ----------- diff --git a/lib/hash/rte_cuckoo_hash.c b/lib/hash/rte_cuckoo_hash.c index 2c92c51624..f9c4a0e302 100644 --- a/lib/hash/rte_cuckoo_hash.c +++ b/lib/hash/rte_cuckoo_hash.c @@ -170,7 +170,6 @@ rte_hash_create(const struct rte_hash_parameters *params) void *buckets = NULL; void *buckets_ext = NULL; char ring_name[RTE_RING_NAMESIZE]; - char ext_ring_name[RTE_RING_NAMESIZE]; unsigned num_key_slots; unsigned int hw_trans_mem_support = 0, use_local_cache = 0; unsigned int ext_table_support = 0; @@ -222,6 +221,13 @@ rte_hash_create(const struct rte_hash_parameters *params) return NULL; } + if (strlen(params->name) >= RTE_HASH_NAMESIZE) { + rte_errno = ENAMETOOLONG; + HASH_LOG(ERR, "%s() name '%s' exceeds maximum length %d", + __func__, params->name, RTE_HASH_NAMESIZE); + return NULL; + } + /* Validate correct usage of extra options */ if ((params->extra_flag & RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY) && (params->extra_flag & RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF)) { @@ -272,12 +278,16 @@ rte_hash_create(const struct rte_hash_parameters *params) else num_key_slots = params->entries + 1; - snprintf(ring_name, sizeof(ring_name), "HT_%s", params->name); + /* Ring name may get truncated, conflict detected on ring creation */ + if (snprintf(ring_name, sizeof(ring_name), "HT_%s", params->name) + >= (int)sizeof(ring_name)) + HASH_LOG(NOTICE, "ring name truncated to '%s'", ring_name); + /* Create ring (Dummy slot index is not enqueued) */ r = rte_ring_create_elem(ring_name, sizeof(uint32_t), rte_align32pow2(num_key_slots), params->socket_id, 0); if (r == NULL) { - HASH_LOG(ERR, "memory allocation failed"); + HASH_LOG(ERR, "ring creation failed: %s", rte_strerror(rte_errno)); goto err; } @@ -286,20 +296,25 @@ rte_hash_create(const struct rte_hash_parameters *params) /* Create ring for extendable buckets. */ if (ext_table_support) { - snprintf(ext_ring_name, sizeof(ext_ring_name), "HT_EXT_%s", - params->name); + char ext_ring_name[RTE_RING_NAMESIZE]; + + if (snprintf(ext_ring_name, sizeof(ext_ring_name), + "HT_EXT_%s", params->name) >= (int)sizeof(ext_ring_name)) + HASH_LOG(NOTICE, "external ring name truncated to '%s'", ext_ring_name); + r_ext = rte_ring_create_elem(ext_ring_name, sizeof(uint32_t), rte_align32pow2(num_buckets + 1), params->socket_id, 0); - if (r_ext == NULL) { - HASH_LOG(ERR, "ext buckets memory allocation " - "failed"); + HASH_LOG(ERR, "ext buckets ring create failed: %s", + rte_strerror(rte_errno)); goto err; } } - snprintf(hash_name, sizeof(hash_name), "HT_%s", params->name); + if (snprintf(hash_name, sizeof(hash_name), "HT_%s", params->name) + >= (int)sizeof(hash_name)) + HASH_LOG(NOTICE, "%s() hash name truncated to '%s'", __func__, hash_name); rte_mcfg_tailq_write_lock(); @@ -1606,8 +1621,9 @@ rte_hash_rcu_qsbr_add(struct rte_hash *h, struct rte_hash_rcu_config *cfg) /* No other things to do. */ } else if (cfg->mode == RTE_HASH_QSBR_MODE_DQ) { /* Init QSBR defer queue. */ - snprintf(rcu_dq_name, sizeof(rcu_dq_name), - "HASH_RCU_%s", h->name); + if (snprintf(rcu_dq_name, sizeof(rcu_dq_name), + "HASH_RCU_%s", h->name) >= (int)sizeof(rcu_dq_name)) + HASH_LOG(NOTICE, "HASH defer queue name truncated to: %s", rcu_dq_name); params.name = rcu_dq_name; params.size = cfg->dq_size; if (params.size == 0) @@ -1623,7 +1639,8 @@ rte_hash_rcu_qsbr_add(struct rte_hash *h, struct rte_hash_rcu_config *cfg) h->dq = rte_rcu_qsbr_dq_create(¶ms); if (h->dq == NULL) { rte_free(hash_rcu_cfg); - HASH_LOG(ERR, "HASH defer queue creation failed"); + HASH_LOG(ERR, "HASH defer queue creation failed: %s", + rte_strerror(rte_errno)); return 1; } } else { diff --git a/lib/hash/rte_fbk_hash.c b/lib/hash/rte_fbk_hash.c index 38b15a14d1..f60fad3caa 100644 --- a/lib/hash/rte_fbk_hash.c +++ b/lib/hash/rte_fbk_hash.c @@ -83,7 +83,7 @@ rte_fbk_hash_create(const struct rte_fbk_hash_params *params) { struct rte_fbk_hash_table *ht = NULL; struct rte_tailq_entry *te; - char hash_name[RTE_FBK_HASH_NAMESIZE]; + char *hash_name = NULL; const uint32_t mem_size = sizeof(*ht) + (sizeof(ht->t[0]) * params->entries); uint32_t i; @@ -96,6 +96,7 @@ rte_fbk_hash_create(const struct rte_fbk_hash_params *params) /* Error checking of parameters. */ if ((!rte_is_power_of_2(params->entries)) || (!rte_is_power_of_2(params->entries_per_bucket)) || + (params->name == NULL) || (params->entries == 0) || (params->entries_per_bucket == 0) || (params->entries_per_bucket > params->entries) || @@ -105,7 +106,14 @@ rte_fbk_hash_create(const struct rte_fbk_hash_params *params) return NULL; } - snprintf(hash_name, sizeof(hash_name), "FBK_%s", params->name); + if (strlen(params->name) >= RTE_FBK_HASH_NAMESIZE) { + rte_errno = ENAMETOOLONG; + return NULL; + } + + /* don't care if hash_name is NULL */ + int unused __rte_unused; + unused = asprintf(&hash_name, "FBK_%s", params->name); rte_mcfg_tailq_write_lock(); @@ -170,6 +178,7 @@ rte_fbk_hash_create(const struct rte_fbk_hash_params *params) exit: rte_mcfg_tailq_write_unlock(); + free(hash_name); return ht; } -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3 04/16] graph: avoid overflowing comment buffer 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger ` (2 preceding siblings ...) 2025-12-05 20:11 ` [PATCH v3 03/16] hash: add checks for hash name length Stephen Hemminger @ 2025-12-05 20:11 ` Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 05/16] latencystats: add check for string overflow Stephen Hemminger ` (11 subsequent siblings) 15 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 20:11 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Jerin Jacob, Kiran Kumar K, Nithin Dabilpuram, Zhirun Yan The library builds a pcapng comment to put on each packet but the buffer is not big enough for the largest possible graph node name, etc. Change to use asprintf() to allow any string length. Note, if asprintf() fails it is better to still log the packet without comment so no data is lost. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/graph/graph_pcap.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/graph/graph_pcap.c b/lib/graph/graph_pcap.c index 08dcda0d28..602be79ced 100644 --- a/lib/graph/graph_pcap.c +++ b/lib/graph/graph_pcap.c @@ -194,7 +194,7 @@ graph_pcap_dispatch(struct rte_graph *graph, uint16_t nb_objs) { struct rte_mbuf *mbuf_clones[RTE_GRAPH_BURST_SIZE]; - char buffer[GRAPH_PCAP_BUF_SZ]; + char *comment = NULL; uint64_t i, num_packets; struct rte_mbuf *mbuf; ssize_t len; @@ -207,19 +207,22 @@ graph_pcap_dispatch(struct rte_graph *graph, if (num_packets > nb_objs) num_packets = nb_objs; - snprintf(buffer, GRAPH_PCAP_BUF_SZ, "%s: %s", graph->name, node->name); + /* put a comment on all these packets */ + if (asprintf(&comment, "%s: %s", graph->name, node->name) < 0) + graph_err("asprintf for comment failed."); for (i = 0; i < num_packets; i++) { struct rte_mbuf *mc; mbuf = (struct rte_mbuf *)objs[i]; mc = rte_pcapng_copy(mbuf->port, 0, mbuf, pkt_mp, mbuf->pkt_len, - 0, buffer); + 0, comment); if (mc == NULL) break; mbuf_clones[i] = mc; } + free(comment); /* write it to capture file */ len = rte_pcapng_write_packets(pcapng_fd, mbuf_clones, i); -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3 05/16] latencystats: add check for string overflow 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger ` (3 preceding siblings ...) 2025-12-05 20:11 ` [PATCH v3 04/16] graph: avoid overflowing comment buffer Stephen Hemminger @ 2025-12-05 20:11 ` Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 06/16] efd: handle possible name truncation Stephen Hemminger ` (10 subsequent siblings) 15 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 20:11 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Reshma Pattan The copy of latency stat names could get truncated if in the future a new value is added. Add warning if that happens. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/latencystats/rte_latencystats.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/latencystats/rte_latencystats.c b/lib/latencystats/rte_latencystats.c index f61d5a273f..0861d00c6b 100644 --- a/lib/latencystats/rte_latencystats.c +++ b/lib/latencystats/rte_latencystats.c @@ -405,9 +405,12 @@ rte_latencystats_get_names(struct rte_metric_name *names, uint16_t size) if (names == NULL || size < NUM_LATENCY_STATS) return NUM_LATENCY_STATS; - for (i = 0; i < NUM_LATENCY_STATS; i++) - strlcpy(names[i].name, lat_stats_strings[i].name, - sizeof(names[i].name)); + for (i = 0; i < NUM_LATENCY_STATS; i++) { + if (strlcpy(names[i].name, lat_stats_strings[i].name, sizeof(names[0].name)) + >= sizeof(names[0].name)) + LATENCY_STATS_LOG(NOTICE, "Latency metric '%s' too long", + lat_stats_strings[i].name); + } return NUM_LATENCY_STATS; } -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3 06/16] efd: handle possible name truncation 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger ` (4 preceding siblings ...) 2025-12-05 20:11 ` [PATCH v3 05/16] latencystats: add check for string overflow Stephen Hemminger @ 2025-12-05 20:11 ` Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 07/16] eal: warn if thread name is truncated Stephen Hemminger ` (9 subsequent siblings) 15 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 20:11 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Byron Marohn, Yipeng Wang If the conversion of efd name to ring name gets truncated, then log it. And if the ring name than causes collision, make sure that log message includes error reason. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/efd/rte_efd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/efd/rte_efd.c b/lib/efd/rte_efd.c index ebf1e0655f..ed2c509938 100644 --- a/lib/efd/rte_efd.c +++ b/lib/efd/rte_efd.c @@ -698,12 +698,15 @@ rte_efd_create(const char *name, uint32_t max_num_rules, uint32_t key_len, TAILQ_INSERT_TAIL(efd_list, te, next); rte_mcfg_tailq_write_unlock(); - snprintf(ring_name, sizeof(ring_name), "HT_%s", table->name); + if (snprintf(ring_name, sizeof(ring_name), "HT_%s", table->name) + >= (int)sizeof(ring_name)) + EFD_LOG(NOTICE, "EFD ring name truncated to '%s'", ring_name); + /* Create ring (Dummy slot index is not enqueued) */ r = rte_ring_create(ring_name, rte_align32pow2(table->max_num_rules), offline_cpu_socket, 0); if (r == NULL) { - EFD_LOG(ERR, "memory allocation failed"); + EFD_LOG(ERR, "ring creation failed: %s", rte_strerror(rte_errno)); rte_efd_free(table); return NULL; } -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3 07/16] eal: warn if thread name is truncated 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger ` (5 preceding siblings ...) 2025-12-05 20:11 ` [PATCH v3 06/16] efd: handle possible name truncation Stephen Hemminger @ 2025-12-05 20:11 ` Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 08/16] eal: avoid format overflow when handling addresses Stephen Hemminger ` (8 subsequent siblings) 15 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 20:11 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson Thread name is very short 16 characters and therefore the name dpdk-worker-%d will overflow with more than 9999 worker cores. Error should be non-fatal since name only matters for debug. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- lib/eal/linux/eal.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index b12f325ddd..d848de03d8 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -863,8 +863,10 @@ rte_eal_init(int argc, char **argv) rte_panic("Cannot create thread\n"); /* Set thread_name for aid in debugging. */ - snprintf(thread_name, sizeof(thread_name), - "dpdk-worker%d", i); + ret = snprintf(thread_name, sizeof(thread_name), "dpdk-worker%d", i); + if (ret >= RTE_THREAD_NAME_SIZE) + EAL_LOG(INFO, "Worker thread name %s truncated", thread_name); + rte_thread_set_name(lcore_config[i].thread_id, thread_name); ret = rte_thread_set_affinity_by_id(lcore_config[i].thread_id, -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3 08/16] eal: avoid format overflow when handling addresses 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger ` (6 preceding siblings ...) 2025-12-05 20:11 ` [PATCH v3 07/16] eal: warn if thread name is truncated Stephen Hemminger @ 2025-12-05 20:11 ` Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 09/16] eal: add check for sysfs path overflow Stephen Hemminger ` (7 subsequent siblings) 15 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 20:11 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Anatoly Burakov The largest possible string in this code 0xFFFFFFFFFFFFFFFF which will overflow with only 15 character buffer. Increase to 20. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c index c62edf5e55..2633857db5 100644 --- a/lib/eal/common/eal_common_memory.c +++ b/lib/eal/common/eal_common_memory.c @@ -1153,7 +1153,7 @@ rte_eal_memory_init(void) #define EAL_MEMSEG_INFO_REQ "/eal/memseg_info" #define EAL_ELEMENT_LIST_REQ "/eal/mem_element_list" #define EAL_ELEMENT_INFO_REQ "/eal/mem_element_info" -#define ADDR_STR 15 +#define ADDR_STR 20 /* 16 bytes 64 bit + 0x */ /* Telemetry callback handler to return heap stats for requested heap id. */ -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3 09/16] eal: add check for sysfs path overflow 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger ` (7 preceding siblings ...) 2025-12-05 20:11 ` [PATCH v3 08/16] eal: avoid format overflow when handling addresses Stephen Hemminger @ 2025-12-05 20:11 ` Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 10/16] eal: limit maximum runtime directory and socket paths Stephen Hemminger ` (6 subsequent siblings) 15 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 20:11 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Shouldn't happen but in theory sysfs socket could overflow. Add a check for it. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/linux/eal_hugepage_info.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/eal/linux/eal_hugepage_info.c b/lib/eal/linux/eal_hugepage_info.c index 7161b1a2fb..fe3351259e 100644 --- a/lib/eal/linux/eal_hugepage_info.c +++ b/lib/eal/linux/eal_hugepage_info.c @@ -150,8 +150,12 @@ get_num_hugepages_on_node(const char *subdir, unsigned int socket, size_t sz) return 0; } - snprintf(path, sizeof(path), "%s/%s/%s", + if (snprintf(path, sizeof(path), "%s/%s/%s", socketpath, subdir, nr_hp_file) >= PATH_MAX) { + EAL_LOG(NOTICE, "Socket path %s/%s/%s is truncated", socketpath, subdir, nr_hp_file); + return 0; + } + if (eal_parse_sysfs_value(path, &num_pages) < 0) return 0; -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3 10/16] eal: limit maximum runtime directory and socket paths 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger ` (8 preceding siblings ...) 2025-12-05 20:11 ` [PATCH v3 09/16] eal: add check for sysfs path overflow Stephen Hemminger @ 2025-12-05 20:11 ` Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 11/16] eal: check for hugefile path overflow Stephen Hemminger ` (5 subsequent siblings) 15 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 20:11 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Anatoly Burakov Linux (and FreeBSD) has a limitation of 108 characters for any unix domain socket path. Therefore DPDK would not work if a really large runtime directory was used. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_config.c | 6 ++- lib/eal/common/eal_common_proc.c | 83 +++++++++++++++++++----------- lib/eal/common/eal_filesystem.h | 7 ++- 3 files changed, 64 insertions(+), 32 deletions(-) diff --git a/lib/eal/common/eal_common_config.c b/lib/eal/common/eal_common_config.c index 7fc7611a07..e2e69a75fb 100644 --- a/lib/eal/common/eal_common_config.c +++ b/lib/eal/common/eal_common_config.c @@ -6,6 +6,7 @@ #include <eal_export.h> #include "eal_private.h" +#include "eal_filesystem.h" #include "eal_memcfg.h" /* early configuration structure, when memory config is not mmapped */ @@ -24,7 +25,7 @@ static struct rte_config rte_config = { }; /* platform-specific runtime dir */ -static char runtime_dir[PATH_MAX]; +static char runtime_dir[UNIX_PATH_MAX]; /* internal configuration */ static struct internal_config internal_config; @@ -39,7 +40,8 @@ rte_eal_get_runtime_dir(void) int eal_set_runtime_dir(const char *run_dir) { - if (strlcpy(runtime_dir, run_dir, PATH_MAX) >= PATH_MAX) { + /* runtime directory limited by maximum allowable unix domain socket */ + if (strlcpy(runtime_dir, run_dir, UNIX_PATH_MAX) >= UNIX_PATH_MAX) { EAL_LOG(ERR, "Runtime directory string too long"); return -1; } diff --git a/lib/eal/common/eal_common_proc.c b/lib/eal/common/eal_common_proc.c index 62fd4ba88f..dbf749c5b8 100644 --- a/lib/eal/common/eal_common_proc.c +++ b/lib/eal/common/eal_common_proc.c @@ -36,10 +36,10 @@ static RTE_ATOMIC(int) mp_fd = -1; static rte_thread_t mp_handle_tid; -static char mp_filter[PATH_MAX]; /* Filter for secondary process sockets */ -static char mp_dir_path[PATH_MAX]; /* The directory path for all mp sockets */ +static char mp_filter[UNIX_PATH_MAX]; /* Filter for secondary process sockets */ +static char mp_dir_path[UNIX_PATH_MAX]; /* The directory path for all mp sockets */ static pthread_mutex_t mp_mutex_action = PTHREAD_MUTEX_INITIALIZER; -static char peer_name[PATH_MAX]; +static char peer_name[UNIX_PATH_MAX]; struct action_entry { TAILQ_ENTRY(action_entry) next; @@ -78,7 +78,7 @@ struct pending_request { REQUEST_TYPE_SYNC, REQUEST_TYPE_ASYNC } type; - char dst[PATH_MAX]; + char dst[UNIX_PATH_MAX]; struct rte_mp_msg *request; struct rte_mp_msg *reply; int reply_received; @@ -132,15 +132,19 @@ find_pending_request(const char *dst, const char *act_name) return r; } -static void -create_socket_path(const char *name, char *buf, int len) +static int +create_socket_path(const char *name, char *buf, size_t len) { const char *prefix = eal_mp_socket_path(); - if (strlen(name) > 0) - snprintf(buf, len, "%s_%s", prefix, name); - else - strlcpy(buf, prefix, len); + if (strlen(name) > 0) { + if (snprintf(buf, len, "%s_%s", prefix, name) >= (int)len) + return -1; + } else { + if (strlcpy(buf, prefix, len) >= len) + return -1; + } + return 0; } RTE_EXPORT_SYMBOL(rte_eal_primary_proc_alive) @@ -572,6 +576,11 @@ open_socket_fd(void) snprintf(peer_name, sizeof(peer_name), "%d_%"PRIx64, getpid(), rte_rdtsc()); + if (create_socket_path(peer_name, un.sun_path, sizeof(un.sun_path)) < 0) { + EAL_LOG(ERR, "peer '%s' socket path too long", peer_name); + return -1; + } + mp_fd = socket(AF_UNIX, SOCK_DGRAM, 0); if (mp_fd < 0) { EAL_LOG(ERR, "failed to create unix socket"); @@ -581,8 +590,6 @@ open_socket_fd(void) memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; - create_socket_path(peer_name, un.sun_path, sizeof(un.sun_path)); - unlink(un.sun_path); /* May still exist since last run */ if (bind(mp_fd, (struct sockaddr *)&un, sizeof(un)) < 0) { @@ -599,17 +606,20 @@ open_socket_fd(void) static void close_socket_fd(int fd) { - char path[PATH_MAX]; + char path[UNIX_PATH_MAX]; close(fd); - create_socket_path(peer_name, path, sizeof(path)); - unlink(path); + + if (create_socket_path(peer_name, path, sizeof(path)) < 0) + EAL_LOG(ERR, "file prefix path for peerr '%s' too long", peer_name); + else + unlink(path); } int rte_mp_channel_init(void) { - char path[PATH_MAX]; + char path[UNIX_PATH_MAX]; int dir_fd; const struct internal_config *internal_conf = eal_get_internal_configuration(); @@ -624,7 +634,12 @@ rte_mp_channel_init(void) } /* create filter path */ - create_socket_path("*", path, sizeof(path)); + if (create_socket_path("*", path, sizeof(path)) < 0) { + EAL_LOG(ERR, "file prefix path too long"); + rte_errno = ENAMETOOLONG; + return -1; + } + rte_basename(path, mp_filter, sizeof(mp_filter)); strlcpy(mp_dir_path, dirname(path), sizeof(mp_dir_path)); @@ -779,14 +794,17 @@ mp_send(struct rte_mp_msg *msg, const char *peer, int type) } while ((ent = readdir(mp_dir))) { - char path[PATH_MAX]; + char path[UNIX_PATH_MAX]; if (fnmatch(mp_filter, ent->d_name, 0) != 0) continue; - snprintf(path, sizeof(path), "%s/%s", mp_dir_path, - ent->d_name); - if (send_msg(path, msg, type) < 0) + if (snprintf(path, sizeof(path), "%s/%s", + mp_dir_path, ent->d_name) >= (int)sizeof(path)) { + EAL_LOG(ERR, "Unix domain path %s/%s too long", + mp_dir_path, ent->d_name); + ret = -1; + } else if (send_msg(path, msg, type) < 0) ret = -1; } /* unlock the dir */ @@ -1055,13 +1073,18 @@ rte_mp_request_sync(struct rte_mp_msg *req, struct rte_mp_reply *reply, pthread_mutex_lock(&pending_requests.lock); while ((ent = readdir(mp_dir))) { - char path[PATH_MAX]; + char path[UNIX_PATH_MAX]; if (fnmatch(mp_filter, ent->d_name, 0) != 0) continue; - snprintf(path, sizeof(path), "%s/%s", mp_dir_path, - ent->d_name); + if (snprintf(path, sizeof(path), "%s/%s", + mp_dir_path, ent->d_name) >= (int)sizeof(path)) { + EAL_LOG(ERR, "Unix domain socket path '%s/%s' too long", + mp_dir_path, ent->d_name); + rte_errno = ENAMETOOLONG; + goto unlock_end; + } /* unlocks the mutex while waiting for response, * locks on receive @@ -1200,15 +1223,17 @@ rte_mp_request_async(struct rte_mp_msg *req, const struct timespec *ts, } while ((ent = readdir(mp_dir))) { - char path[PATH_MAX]; + char path[UNIX_PATH_MAX]; if (fnmatch(mp_filter, ent->d_name, 0) != 0) continue; - snprintf(path, sizeof(path), "%s/%s", mp_dir_path, - ent->d_name); - - if (mp_request_async(path, copy, param, ts)) + if (snprintf(path, sizeof(path), "%s/%s", + mp_dir_path, ent->d_name) >= (int)sizeof(path)) { + EAL_LOG(ERR, "Unix domain path %s/%s too long", + mp_dir_path, ent->d_name); + ret = -1; + } else if (mp_request_async(path, copy, param, ts)) ret = -1; } /* if we didn't send anything, put dummy request on the queue */ diff --git a/lib/eal/common/eal_filesystem.h b/lib/eal/common/eal_filesystem.h index 5d21f07c20..ce52babb7f 100644 --- a/lib/eal/common/eal_filesystem.h +++ b/lib/eal/common/eal_filesystem.h @@ -17,6 +17,7 @@ #include <limits.h> #include <unistd.h> #include <stdlib.h> +#include <sys/un.h> #include <rte_string_fns.h> #include "eal_internal_cfg.h" @@ -45,10 +46,14 @@ eal_runtime_config_path(void) /** Path of primary/secondary communication unix socket file. */ #define MP_SOCKET_FNAME "mp_socket" + +/** Maximum length of unix domain socket path. */ +#define UNIX_PATH_MAX (sizeof(((struct sockaddr_un *)0)->sun_path)) + static inline const char * eal_mp_socket_path(void) { - static char buffer[PATH_MAX]; /* static so auto-zeroed */ + static char buffer[UNIX_PATH_MAX]; /* static so auto-zeroed */ snprintf(buffer, sizeof(buffer), "%s/%s", rte_eal_get_runtime_dir(), MP_SOCKET_FNAME); -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3 11/16] eal: check for hugefile path overflow 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger ` (9 preceding siblings ...) 2025-12-05 20:11 ` [PATCH v3 10/16] eal: limit maximum runtime directory and socket paths Stephen Hemminger @ 2025-12-05 20:11 ` Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 12/16] eal: check tailq length Stephen Hemminger ` (4 subsequent siblings) 15 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 20:11 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Anatoly Burakov When constructing huge filename path, check for possible overflow of PATH_MAX. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_filesystem.h | 10 ++++++---- lib/eal/linux/eal_memalloc.c | 11 +++++++++-- lib/eal/linux/eal_memory.c | 9 +++++++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/lib/eal/common/eal_filesystem.h b/lib/eal/common/eal_filesystem.h index ce52babb7f..4cc5b22a16 100644 --- a/lib/eal/common/eal_filesystem.h +++ b/lib/eal/common/eal_filesystem.h @@ -94,12 +94,14 @@ eal_hugepage_data_path(void) /** String format for hugepage map files. */ #define HUGEFILE_FMT "%s/%smap_%d" -static inline const char * +static inline __rte_warn_unused_result const char * eal_get_hugefile_path(char *buffer, size_t buflen, const char *hugedir, int f_id) { - snprintf(buffer, buflen, HUGEFILE_FMT, hugedir, - eal_get_hugefile_prefix(), f_id); - return buffer; + if (snprintf(buffer, buflen, HUGEFILE_FMT, hugedir, + eal_get_hugefile_prefix(), f_id) >= (int)buflen) + return NULL; + else + return buffer; } /** define the default filename prefix for the %s values above */ diff --git a/lib/eal/linux/eal_memalloc.c b/lib/eal/linux/eal_memalloc.c index 1e60e21620..d9e8ea76b9 100644 --- a/lib/eal/linux/eal_memalloc.c +++ b/lib/eal/linux/eal_memalloc.c @@ -260,6 +260,7 @@ get_seg_fd(char *path, int buflen, struct hugepage_info *hi, { int fd; int *out_fd; + const char *huge_path; struct stat st; int ret; const struct internal_config *internal_conf = @@ -276,12 +277,18 @@ get_seg_fd(char *path, int buflen, struct hugepage_info *hi, if (internal_conf->single_file_segments) { out_fd = &fd_list[list_idx].memseg_list_fd; - eal_get_hugefile_path(path, buflen, hi->hugedir, list_idx); + huge_path = eal_get_hugefile_path(path, buflen, hi->hugedir, list_idx); } else { out_fd = &fd_list[list_idx].fds[seg_idx]; - eal_get_hugefile_path(path, buflen, hi->hugedir, + huge_path = eal_get_hugefile_path(path, buflen, hi->hugedir, list_idx * RTE_MAX_MEMSEG_PER_LIST + seg_idx); } + if (huge_path == NULL) { + EAL_LOG(DEBUG, "%s(): hugefile path truncated: '%s'", + __func__, path); + return -1; + } + fd = *out_fd; if (fd >= 0) return fd; diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c index 8e1763e890..2a0a441398 100644 --- a/lib/eal/linux/eal_memory.c +++ b/lib/eal/linux/eal_memory.c @@ -337,8 +337,13 @@ map_all_hugepages(struct hugepage_file *hugepg_tbl, struct hugepage_info *hpi, hf->file_id = i; hf->size = hugepage_sz; - eal_get_hugefile_path(hf->filepath, sizeof(hf->filepath), - hpi->hugedir, hf->file_id); + if (eal_get_hugefile_path(hf->filepath, sizeof(hf->filepath), + hpi->hugedir, hf->file_id) == NULL) { + EAL_LOG(DEBUG, "%s(): huge file path '%s' truncated", + __func__, hf->filepath); + goto out; + } + hf->filepath[sizeof(hf->filepath) - 1] = '\0'; /* try to create hugepage file */ -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3 12/16] eal: check tailq length 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger ` (10 preceding siblings ...) 2025-12-05 20:11 ` [PATCH v3 11/16] eal: check for hugefile path overflow Stephen Hemminger @ 2025-12-05 20:11 ` Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 13/16] eal: handle long shared library path Stephen Hemminger ` (3 subsequent siblings) 15 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 20:11 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger The tailq name should not be allowed to exceed limits. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_tailqs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/eal/common/eal_common_tailqs.c b/lib/eal/common/eal_common_tailqs.c index 47080d75ac..7502836c6d 100644 --- a/lib/eal/common/eal_common_tailqs.c +++ b/lib/eal/common/eal_common_tailqs.c @@ -67,6 +67,11 @@ rte_eal_tailq_create(const char *name) { struct rte_tailq_head *head = NULL; + if (strlen(name) >= sizeof(head->name)) { + EAL_LOG(ERR, "tailq name '%s' is too long", name); + return NULL; + } + if (!rte_eal_tailq_lookup(name) && (rte_tailqs_count + 1 < RTE_MAX_TAILQ)) { struct rte_mem_config *mcfg; -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3 13/16] eal: handle long shared library path 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger ` (11 preceding siblings ...) 2025-12-05 20:11 ` [PATCH v3 12/16] eal: check tailq length Stephen Hemminger @ 2025-12-05 20:11 ` Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 14/16] ethdev: avoid possible overflow in xstat names Stephen Hemminger ` (2 subsequent siblings) 15 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 20:11 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Instead of a fixed size shared library path that could in theory get truncated when concatenating, use a dynamically allocated buffer via asprintf. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index b1fb670ea0..6aa078e135 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -570,7 +570,6 @@ static int eal_plugindir_init(const char *path) { struct dirent *dent = NULL; - char sopath[PATH_MAX]; DIR *d = NULL; if (path == NULL || *path == '\0') @@ -584,19 +583,29 @@ eal_plugindir_init(const char *path) } while ((dent = readdir(d)) != NULL) { + char *sopath = NULL; struct stat sb; if (!ends_with(dent->d_name, ".so") && !ends_with(dent->d_name, ".so."ABI_VERSION)) continue; - snprintf(sopath, sizeof(sopath), "%s/%s", path, dent->d_name); + if (asprintf(&sopath, "%s/%s", path, dent->d_name) < 0) { + EAL_LOG(ERR, "failed to create full path %s/%s", + path, dent->d_name); + continue; + } /* if a regular file, add to list to load */ - if (!(stat(sopath, &sb) == 0 && S_ISREG(sb.st_mode))) + if (!(stat(sopath, &sb) == 0 && S_ISREG(sb.st_mode))) { + free(sopath); continue; + } - if (eal_plugin_add(sopath) == -1) + if (eal_plugin_add(sopath) == -1) { + free(sopath); break; + } + free(sopath); } closedir(d); -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3 14/16] ethdev: avoid possible overflow in xstat names 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger ` (12 preceding siblings ...) 2025-12-05 20:11 ` [PATCH v3 13/16] eal: handle long shared library path Stephen Hemminger @ 2025-12-05 20:11 ` Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 15/16] vhost: check for overflow in xstat name Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 16/16] lib: enable format overflow warnings Stephen Hemminger 15 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 20:11 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Thomas Monjalon, Andrew Rybchenko The compiler doesn't know that all the elements in the table of queue stats are short enough to avoid overflowing the snprintf. Add a condition to warn if it ever does; maybe some day a new long named queue stat could be added. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- lib/ethdev/rte_ethdev.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c index c6fe0d5165..05de3335e5 100644 --- a/lib/ethdev/rte_ethdev.c +++ b/lib/ethdev/rte_ethdev.c @@ -3489,9 +3489,10 @@ eth_basic_stats_get_names(struct rte_eth_dev *dev, uint16_t num_q; for (idx = 0; idx < RTE_NB_STATS; idx++) { - strlcpy(xstats_names[cnt_used_entries].name, - eth_dev_stats_strings[idx].name, - sizeof(xstats_names[0].name)); + if (strlcpy(xstats_names[cnt_used_entries].name, eth_dev_stats_strings[idx].name, + sizeof(xstats_names[0].name)) >= sizeof(xstats_names[0].name)) + RTE_ETHDEV_LOG_LINE(ERR, "statistic name '%s' will be truncated", + xstats_names[cnt_used_entries].name); cnt_used_entries++; } @@ -3501,10 +3502,17 @@ eth_basic_stats_get_names(struct rte_eth_dev *dev, num_q = RTE_MIN(dev->data->nb_rx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS); for (id_queue = 0; id_queue < num_q; id_queue++) { for (idx = 0; idx < RTE_NB_RXQ_STATS; idx++) { - snprintf(xstats_names[cnt_used_entries].name, - sizeof(xstats_names[0].name), - "rx_q%u_%s", - id_queue, eth_dev_rxq_stats_strings[idx].name); + unsigned int cc; + + cc = snprintf(xstats_names[cnt_used_entries].name, + sizeof(xstats_names[0].name), + "rx_q%u_%s", + id_queue, eth_dev_rxq_stats_strings[idx].name); + + /* could only happen if a long string was added */ + if (cc >= sizeof(xstats_names[0].name)) + RTE_ETHDEV_LOG_LINE(ERR, "truncated rxq stat string '%s'", + eth_dev_rxq_stats_strings[idx].name); cnt_used_entries++; } @@ -3512,10 +3520,15 @@ eth_basic_stats_get_names(struct rte_eth_dev *dev, num_q = RTE_MIN(dev->data->nb_tx_queues, RTE_ETHDEV_QUEUE_STAT_CNTRS); for (id_queue = 0; id_queue < num_q; id_queue++) { for (idx = 0; idx < RTE_NB_TXQ_STATS; idx++) { - snprintf(xstats_names[cnt_used_entries].name, - sizeof(xstats_names[0].name), - "tx_q%u_%s", - id_queue, eth_dev_txq_stats_strings[idx].name); + unsigned int cc; + + cc = snprintf(xstats_names[cnt_used_entries].name, + sizeof(xstats_names[0].name), + "tx_q%u_%s", + id_queue, eth_dev_txq_stats_strings[idx].name); + if (cc >= sizeof(xstats_names[0].name)) + RTE_ETHDEV_LOG_LINE(ERR, "truncated txq stat string '%s'", + eth_dev_txq_stats_strings[idx].name); cnt_used_entries++; } } -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3 15/16] vhost: check for overflow in xstat name 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger ` (13 preceding siblings ...) 2025-12-05 20:11 ` [PATCH v3 14/16] ethdev: avoid possible overflow in xstat names Stephen Hemminger @ 2025-12-05 20:11 ` Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 16/16] lib: enable format overflow warnings Stephen Hemminger 15 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 20:11 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Maxime Coquelin, Chenbo Xia The snprintf to format an xstat name could overflow if called with a long rte_vhost_stat_name. Check if that happens and warn. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/vhost/vhost.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/vhost/vhost.c b/lib/vhost/vhost.c index 416f082dca..540f4e0635 100644 --- a/lib/vhost/vhost.c +++ b/lib/vhost/vhost.c @@ -2200,6 +2200,7 @@ rte_vhost_vring_stats_get_names(int vid, uint16_t queue_id, { struct virtio_net *dev = get_device(vid); unsigned int i; + int ret; if (dev == NULL) return -1; @@ -2213,10 +2214,15 @@ rte_vhost_vring_stats_get_names(int vid, uint16_t queue_id, if (name == NULL || size < VHOST_NB_VQ_STATS) return VHOST_NB_VQ_STATS; - for (i = 0; i < VHOST_NB_VQ_STATS; i++) - snprintf(name[i].name, sizeof(name[i].name), "%s_q%u_%s", - (queue_id & 1) ? "rx" : "tx", - queue_id / 2, vhost_vq_stat_strings[i].name); + for (i = 0; i < VHOST_NB_VQ_STATS; i++) { + ret = snprintf(name[i].name, sizeof(name[i].name), "%s_q%u_%s", + (queue_id & 1) ? "rx" : "tx", + queue_id / 2, vhost_vq_stat_strings[i].name); + if (ret >= (int)sizeof(name[0].name)) + VHOST_CONFIG_LOG("device", NOTICE, "truncated xstat '%s_q%u_%s'", + (queue_id & 1) ? "rx" : "tx", + queue_id / 2, vhost_vq_stat_strings[i].name); + } return VHOST_NB_VQ_STATS; } -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v3 16/16] lib: enable format overflow warnings 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger ` (14 preceding siblings ...) 2025-12-05 20:11 ` [PATCH v3 15/16] vhost: check for overflow in xstat name Stephen Hemminger @ 2025-12-05 20:11 ` Stephen Hemminger 15 siblings, 0 replies; 48+ messages in thread From: Stephen Hemminger @ 2025-12-05 20:11 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Enable compiler checking of format overflow Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/meson.build | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/meson.build b/lib/meson.build index c8f4270868..8f5cfd28a5 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -113,10 +113,6 @@ default_cflags = machine_args default_cflags += ['-DALLOW_EXPERIMENTAL_API'] default_cflags += ['-DALLOW_INTERNAL_API'] -if cc.has_argument('-Wno-format-truncation') - default_cflags += '-Wno-format-truncation' -endif - foreach l:libraries build = true reason = '<unknown reason>' # set if build == false to explain why -- 2.51.0 ^ permalink raw reply [flat|nested] 48+ messages in thread
end of thread, other threads:[~2025-12-05 20:17 UTC | newest] Thread overview: 48+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2025-12-02 17:24 [RFC 0/8] first steps in fixing buffer overflow Stephen Hemminger 2025-12-02 17:24 ` [RFC 1/8] eal: use C library to parse filesystem table Stephen Hemminger 2025-12-02 17:24 ` [RFC 2/8] hash: fix possible ring name overflow Stephen Hemminger 2025-12-02 17:24 ` [RFC 3/8] eal: warn if thread name is truncated Stephen Hemminger 2025-12-02 17:24 ` [RFC 4/8] eal: avoid format overflow when handling addresses Stephen Hemminger 2025-12-02 17:24 ` [RFC 5/8] ethdev: avoid possible overflow in xstat names Stephen Hemminger 2025-12-02 17:24 ` [RFC 6/8] efd: avoid overflowing ring name Stephen Hemminger 2025-12-02 17:24 ` [RFC 7/8] eal: add check for sysfs path overflow Stephen Hemminger 2025-12-02 17:24 ` [RFC 8/8] eal: limit maximum runtime directory and socket paths Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 00/14] lib: check for string overflow Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 01/14] eal: use C library to parse filesystem table Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 02/14] test: avoid long hash names Stephen Hemminger 2025-12-05 8:29 ` Bruce Richardson 2025-12-05 17:00 ` Stephen Hemminger 2025-12-05 18:19 ` Bruce Richardson 2025-12-05 2:28 ` [RFC v2 03/14] lpm: restrict name size Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 04/14] hash: avoid possible ring name overflow Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 05/14] graph: avoid overflowing comment buffer Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 06/14] eal: warn if thread name is truncated Stephen Hemminger 2025-12-05 8:32 ` Bruce Richardson 2025-12-05 2:28 ` [RFC v2 07/14] eal: avoid format overflow when handling addresses Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 08/14] ethdev: avoid possible overflow in xstat names Stephen Hemminger 2025-12-05 8:34 ` Bruce Richardson 2025-12-05 2:28 ` [RFC v2 09/14] vhost: check for overflow in xstat name Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 10/14] efd: avoid overflowing ring name Stephen Hemminger 2025-12-05 8:37 ` Bruce Richardson 2025-12-05 2:28 ` [RFC v2 11/14] eal: add check for sysfs path overflow Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 12/14] eal: limit maximum runtime directory and socket paths Stephen Hemminger 2025-12-05 8:46 ` Bruce Richardson 2025-12-05 2:28 ` [RFC v2 13/14] eal: check for hugefile path overflow Stephen Hemminger 2025-12-05 2:28 ` [RFC v2 14/14] lib: enable format overflow warnings Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 00/16] lib: find and fix possible string overflows Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 01/16] eal: use C library to parse filesystem table Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 02/16] lpm: restrict name size Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 03/16] hash: add checks for hash name length Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 04/16] graph: avoid overflowing comment buffer Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 05/16] latencystats: add check for string overflow Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 06/16] efd: handle possible name truncation Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 07/16] eal: warn if thread name is truncated Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 08/16] eal: avoid format overflow when handling addresses Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 09/16] eal: add check for sysfs path overflow Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 10/16] eal: limit maximum runtime directory and socket paths Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 11/16] eal: check for hugefile path overflow Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 12/16] eal: check tailq length Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 13/16] eal: handle long shared library path Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 14/16] ethdev: avoid possible overflow in xstat names Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 15/16] vhost: check for overflow in xstat name Stephen Hemminger 2025-12-05 20:11 ` [PATCH v3 16/16] lib: enable format overflow warnings Stephen Hemminger
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).