public inbox for systemtap@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 1/3] bpf: check metadata allocations
       [not found] <20260803145742.11066-1-m.dmitrichenko222@gmail.com>
@ 2026-08-03 14:57 ` m.dmitrichenko222
  2026-08-03 14:57 ` [PATCH 2/3] stapbpf: check map key allocations m.dmitrichenko222
  2026-08-03 14:57 ` [PATCH 3/3] stapbpf: check runtime allocations m.dmitrichenko222
  2 siblings, 0 replies; 3+ messages in thread
From: m.dmitrichenko222 @ 2026-08-03 14:57 UTC (permalink / raw)
  To: systemtap; +Cc: Mikhail Dmitrichenko

From: Mikhail Dmitrichenko <m.dmitrichenko222@gmail.com>

The BPF translator dereferences buffers returned by malloc and
calloc without checking whether the allocations succeeded. Under
memory pressure this results in a NULL pointer dereference instead of
a controlled translation error.

Check all three allocations before serializing the script name,
aggregate metadata, and foreach metadata.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Signed-off-by: Mikhail Dmitrichenko <m.dmitrichenko222@gmail.com>
---
 bpf-translate.cxx | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/bpf-translate.cxx b/bpf-translate.cxx
index cd1eeaf03..3eab41a95 100644
--- a/bpf-translate.cxx
+++ b/bpf-translate.cxx
@@ -4542,6 +4542,8 @@ output_stapbpf_script_name(BPF_Output &eo, const std::string script_name)
   Elf_Data *data = so->data;
   size_t script_name_len = strlen(script_name.c_str());
   data->d_buf = (void *)malloc(script_name_len + 1);
+  if (!data->d_buf)
+    throw SEMANTIC_ERROR(_("out of memory allocating BPF script name"));
   char *script_name_buf = (char *)data->d_buf;
   script_name.copy(script_name_buf, script_name_len);
   script_name_buf[script_name_len] = '\0';
@@ -4702,6 +4704,8 @@ output_interned_aggregates(BPF_Output &eo, globals& glob)
   unsigned n_aggregates =
     glob.scalar_stats.empty() ? glob.aggregates.size() : glob.aggregates.size() + 1;
   data->d_buf = (void *)calloc(n_aggregates, interned_aggregate_len);
+  if (!data->d_buf)
+    throw SEMANTIC_ERROR(_("out of memory allocating BPF aggregate metadata"));
   data->d_size = interned_aggregate_len * n_aggregates;
   size_t ofs = 0; // XXX after glob.scalar_stats
   if (!glob.scalar_stats.empty())
@@ -4737,6 +4741,8 @@ output_foreach_loop_info(BPF_Output &eo, globals& glob)
     sizeof(uint64_t) * globals::n_foreach_info_fields;
   unsigned n_foreach_loops = glob.foreach_loop_info.size();
   data->d_buf = (void *)calloc(n_foreach_loops, interned_foreach_info_len);
+  if (!data->d_buf)
+    throw SEMANTIC_ERROR(_("out of memory allocating BPF foreach metadata"));
   data->d_size = interned_foreach_info_len * n_foreach_loops;
   size_t ofs = 0;
   uint64_t *ix = (uint64_t *)data->d_buf;
-- 
2.25.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 2/3] stapbpf: check map key allocations
       [not found] <20260803145742.11066-1-m.dmitrichenko222@gmail.com>
  2026-08-03 14:57 ` [PATCH 1/3] bpf: check metadata allocations m.dmitrichenko222
@ 2026-08-03 14:57 ` m.dmitrichenko222
  2026-08-03 14:57 ` [PATCH 3/3] stapbpf: check runtime allocations m.dmitrichenko222
  2 siblings, 0 replies; 3+ messages in thread
From: m.dmitrichenko222 @ 2026-08-03 14:57 UTC (permalink / raw)
  To: systemtap; +Cc: Mikhail Dmitrichenko

From: Mikhail Dmitrichenko <m.dmitrichenko222@gmail.com>

The BPF interpreter copies map keys into buffers returned by malloc
without checking for allocation failure. A NULL return is consequently
passed to memcpy.

Abort with a diagnostic when a map key buffer cannot be allocated,
matching the existing handling for map value and printf argument
allocations.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Signed-off-by: Mikhail Dmitrichenko <m.dmitrichenko222@gmail.com>
---
 stapbpf/bpfinterp.cxx | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/stapbpf/bpfinterp.cxx b/stapbpf/bpfinterp.cxx
index 1be199f77..be8d1fdda 100644
--- a/stapbpf/bpfinterp.cxx
+++ b/stapbpf/bpfinterp.cxx
@@ -148,6 +148,7 @@ foreach_state_add(const foreach_info &fi, foreach_state &s,
 
   // copy and save key
   uint64_t *kp2 = (uint64_t *)malloc(fi.keysize);
+  if (!kp2) stapbpf_abort("map key allocation failed");
   memcpy(kp2, kp, fi.keysize);
   s.keys.push_back(kp2);
 
@@ -228,6 +229,7 @@ convert_key(const foreach_info &fi,
   // handle string composite keys being passed as pointers
   // allocate correctly sized buffer and store it in map_values:
   uint64_t *lookup_tmp = (uint64_t*)malloc(fi.keysize);
+  if (!lookup_tmp) stapbpf_abort("map key allocation failed");
   memcpy(lookup_tmp, kp, fi.keysize);
   map_values.push_back(lookup_tmp);
   *next_kp = reinterpret_cast<uint64_t>(map_values.back());
@@ -405,6 +407,7 @@ map_get_next_key(int fd_idx, int64_t key, int64_t next_key,
         {
           // allocate correctly sized buffer and store it in map_values:
           uint64_t *lookup_tmp = (uint64_t*)malloc(fi.keysize);
+          if (!lookup_tmp) stapbpf_abort("map key allocation failed");
           memcpy(lookup_tmp, _n, fi.keysize);
           map_values.push_back(lookup_tmp);
           *(uint64_t *)next_key =
-- 
2.25.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 3/3] stapbpf: check runtime allocations
       [not found] <20260803145742.11066-1-m.dmitrichenko222@gmail.com>
  2026-08-03 14:57 ` [PATCH 1/3] bpf: check metadata allocations m.dmitrichenko222
  2026-08-03 14:57 ` [PATCH 2/3] stapbpf: check map key allocations m.dmitrichenko222
@ 2026-08-03 14:57 ` m.dmitrichenko222
  2 siblings, 0 replies; 3+ messages in thread
From: m.dmitrichenko222 @ 2026-08-03 14:57 UTC (permalink / raw)
  To: systemtap; +Cc: Mikhail Dmitrichenko

From: Mikhail Dmitrichenko <m.dmitrichenko222@gmail.com>

stapbpf assumes that allocations for module names and the perf event
poll array always succeed. A failed allocation is followed by a write
through the NULL pointer.

Report the allocation failure and terminate through fatal() instead.
Keep a zero-length poll array valid because malloc(0) is permitted to
return NULL.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Signed-off-by: Mikhail Dmitrichenko <m.dmitrichenko222@gmail.com>
---
 stapbpf/stapbpf.cxx | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/stapbpf/stapbpf.cxx b/stapbpf/stapbpf.cxx
index ed6d67da4..2eea57598 100644
--- a/stapbpf/stapbpf.cxx
+++ b/stapbpf/stapbpf.cxx
@@ -1600,6 +1600,8 @@ load_bpf_file(const char *module)
 
   /* Extract basename: */
   char *buf = (char *)malloc(BPF_MAXSTRINGLEN * sizeof(char));
+  if (!buf)
+    fatal("Out of memory allocating module basename\n");
   // NB: If module doesn't contain a single '/', then the behaviour
   // of rfind (-1) and substr (-1 + 1) will default to module_str.
   string module_basename_str
@@ -1610,6 +1612,8 @@ load_bpf_file(const char *module)
 
   /* Extract name: */
   buf = (char*) malloc(BPF_MAXSTRINGLEN * sizeof(char));
+  if (!buf)
+    fatal("Out of memory allocating module name\n");
   string suffix = ".bo";
   string module_name_str
     = module_basename_str.substr(0, module_basename_str.rfind(suffix)); // name
@@ -2034,6 +2038,8 @@ perf_event_loop(pthread_t main_thread)
     fatal("Too many active CPUs for pollfd allocation\n");
   struct pollfd *pmu_fds
     = (struct pollfd *)malloc(n_active_cpus * sizeof(struct pollfd));
+  if (n_active_cpus && !pmu_fds)
+    fatal("Out of memory allocating pollfd array\n");
   vector<unsigned> cpuids;
 
   assert(ncpus == perf_fds.size());
-- 
2.25.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-08-03 14:58 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20260803145742.11066-1-m.dmitrichenko222@gmail.com>
2026-08-03 14:57 ` [PATCH 1/3] bpf: check metadata allocations m.dmitrichenko222
2026-08-03 14:57 ` [PATCH 2/3] stapbpf: check map key allocations m.dmitrichenko222
2026-08-03 14:57 ` [PATCH 3/3] stapbpf: check runtime allocations m.dmitrichenko222

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 read-only IMAP folder(s) and NNTP newsgroup(s).