[PATCH v2 4/5] lib/pmu: fix out-of-bound access
rkudurumalla
rkudurumalla at marvell.com
Tue May 5 07:30:22 CEST 2026
From: Rakesh Kudurumalla <rkudurumalla at marvell.com>
Make sure that out-of-bound access does not happen by saving one byte in
buffer for NUL terminator.
Fixes: a8926a65ad1d ("pmu: support Arm")
Fixes: 960c43184c4d ("pmu: introduce library for reading PMU events")
Cc: tduszynski at marvell.com
Signed-off-by: Tomasz Duszynski <tduszynski at marvell.com>
Signed-off-by: Rakesh Kudurumalla <rkudurumalla at marvell.com>
---
lib/pmu/pmu.c | 54 +++++++++++++++++++++++++++++++++++++++++++--
lib/pmu/pmu_arm64.c | 3 ++-
lib/pmu/rte_pmu.h | 12 +++++++++-
3 files changed, 65 insertions(+), 4 deletions(-)
diff --git a/lib/pmu/pmu.c b/lib/pmu/pmu.c
index c14ffa5a2a..3f57d72a53 100644
--- a/lib/pmu/pmu.c
+++ b/lib/pmu/pmu.c
@@ -126,7 +126,7 @@ get_event_config(const char *name, uint64_t config[3])
if (fp == NULL)
return -errno;
- ret = fread(buf, 1, sizeof(buf), fp);
+ ret = fread(buf, 1, sizeof(buf) - 1, fp);
if (ret == 0) {
fclose(fp);
@@ -419,6 +419,45 @@ rte_pmu_add_event(const char *name)
return event->index;
}
+static int
+check_perf_permissions(void)
+{
+ const char *paranoid_path = "/proc/sys/kernel/perf_event_paranoid";
+ int level, ret;
+ FILE *fp;
+
+ /* Check if user is root */
+ if (getuid() == 0)
+ return 0; /* Root has access */
+
+ fp = fopen(paranoid_path, "r");
+ if (!fp)
+ return -ENOENT; /* File doesn't exist */
+
+ ret = fscanf(fp, "%d", &level);
+ fclose(fp);
+
+ if (ret != 1)
+ return -EINVAL;
+
+ /* On vanilla Linux the default perf_event_paranoid level is 2, which allows non-privileged
+ * processes to access performance counters.
+ *
+ * Debian / Ubuntu and their derivatives apply patches that introduce
+ * additional paranoia levels:
+ *
+ * - Debian adds level 3, which restricts access to perf_event_open() for
+ * monitoring other processes, but still allows unprivileged self-monitoring.
+ * See: https://lore.kernel.org/all/1469630746-32279-1-git-send-email-jeffv@google.com/
+ * - Ubuntu adds level 4 (which is also the default), completely disabling perf_event_open()
+ * for unprivileged usersâeffectively disabling self-monitoring.
+ */
+ if (level >= 4)
+ return -EACCES; /* Insufficient privileges */
+
+ return 0; /* Allowed */
+}
+
static int
add_events(const char *pattern)
{
@@ -492,10 +531,21 @@ rte_pmu_init(void)
if (rte_pmu.initialized && ++rte_pmu.initialized)
return 0;
+ /* Check permissions first */
+ ret = check_perf_permissions();
+ if (ret == -EACCES) {
+ PMU_LOG(ERR, "Insufficient privileges for PMU access (check perf_event_paranoid)");
+ return -EACCES;
+ }
+ if (ret == -ENOENT) {
+ PMU_LOG(ERR, "Cannot access perf_event_paranoid file");
+ return -ENODEV;
+ }
+
ret = scan_pmus();
if (ret) {
PMU_LOG(ERR, "Failed to scan for event sources");
- goto out;
+ return -ENODEV; /* No PMU hardware found */
}
ret = pmu_arch_init();
diff --git a/lib/pmu/pmu_arm64.c b/lib/pmu/pmu_arm64.c
index 2c40b5f702..f3a817b42f 100644
--- a/lib/pmu/pmu_arm64.c
+++ b/lib/pmu/pmu_arm64.c
@@ -24,12 +24,13 @@ read_attr_int(const char *path, int *val)
if (fd == -1)
return -errno;
- ret = read(fd, buf, sizeof(buf));
+ ret = read(fd, buf, sizeof(buf) - 1);
if (ret == -1) {
close(fd);
return -errno;
}
+ buf[ret] = '\0';
*val = strtol(buf, NULL, 10);
close(fd);
diff --git a/lib/pmu/rte_pmu.h b/lib/pmu/rte_pmu.h
index 9970282c76..0c2a5d9298 100644
--- a/lib/pmu/rte_pmu.h
+++ b/lib/pmu/rte_pmu.h
@@ -150,10 +150,20 @@ __rte_pmu_enable_group(struct rte_pmu_event_group *group);
*
* Initialize PMU library.
*
+ * This function initializes the Performance Monitoring Unit (PMU) library
+ * by checking permissions, scanning for available PMU hardware, and setting up
+ * necessary architecture-specific internals.
+ *
* It's safe to call it multiple times.
*
* @return
- * 0 in case of success, negative value otherwise.
+ * 0 on success.
+ * -ENODEV if PMU hardware is not available or kernel lacks PMU support.
+ * -EACCES if insufficient privileges to access PMU.
+ * User should check /proc/sys/kernel/perf_event_paranoid settings.
+ * -ENOMEM if memory allocation failed.
+ * -EINVAL if invalid configuration detected.
+ * Other negative errno values on other failures.
*/
__rte_experimental
int
--
2.25.1
More information about the dev
mailing list