You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by bc...@apache.org on 2026/04/13 20:49:22 UTC

(trafficserver) branch master updated: Fix ASAN-detected plugin bugs across five components (#13013)

This is an automated email from the ASF dual-hosted git repository.

bcall pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 123b6686ea Fix ASAN-detected plugin bugs across five components (#13013)
123b6686ea is described below

commit 123b6686ea16e46dc4bbe07477853004f6f9448d
Author: Bryan Call <bc...@apache.org>
AuthorDate: Mon Apr 13 13:49:15 2026 -0700

    Fix ASAN-detected plugin bugs across five components (#13013)
    
    * Fix heap-buffer-overflow in stats_over_http -- use %.*s
      with string_view length instead of %s.
    * Fix delete type mismatch in ja4_fingerprint -- delete as
      JA4_data* and cast consistently in handle_read_request_hdr.
    * Fix use-after-free in txn_box Config destructor -- reorder
      _arena before _roots so arena outlives directive memory.
    * Fix memory leak in slice plugin -- free urlstr before
      early return on invalid content length.
    * Fix use-after-free in async_engine test plugin -- save
      writefd before OPENSSL_free releases backing memory.
---
 plugins/experimental/ja4_fingerprint/plugin.cc               | 8 ++++----
 plugins/experimental/txn_box/plugin/include/txn_box/Config.h | 8 +++++---
 plugins/slice/server.cc                                      | 1 +
 plugins/stats_over_http/stats_over_http.cc                   | 3 ++-
 tests/tools/plugins/async_engine.c                           | 7 ++++---
 5 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/plugins/experimental/ja4_fingerprint/plugin.cc b/plugins/experimental/ja4_fingerprint/plugin.cc
index 216171280f..fc3768997a 100644
--- a/plugins/experimental/ja4_fingerprint/plugin.cc
+++ b/plugins/experimental/ja4_fingerprint/plugin.cc
@@ -358,9 +358,9 @@ handle_read_request_hdr(TSCont cont, TSEvent event, void *edata)
     return TS_SUCCESS;
   }
 
-  std::string *fingerprint{static_cast<std::string *>(TSUserArgGet(vconn, *get_user_arg_index()))};
-  if (fingerprint) {
-    append_JA4_headers(cont, txnp, fingerprint);
+  JA4_data *data{static_cast<JA4_data *>(TSUserArgGet(vconn, *get_user_arg_index()))};
+  if (data) {
+    append_JA4_headers(cont, txnp, &data->fingerprint);
   } else {
     Dbg(dbg_ctl, "No JA4 fingerprint attached to vconn!");
   }
@@ -444,7 +444,7 @@ handle_vconn_close(TSCont /* cont ATS_UNUSED */, TSEvent event, void *edata)
     return TS_SUCCESS;
   }
   TSVConn const ssl_vc{static_cast<TSVConn>(edata)};
-  delete static_cast<std::string *>(TSUserArgGet(ssl_vc, *get_user_arg_index()));
+  delete static_cast<JA4_data *>(TSUserArgGet(ssl_vc, *get_user_arg_index()));
   TSUserArgSet(ssl_vc, *get_user_arg_index(), nullptr);
   TSVConnReenable(ssl_vc);
   return TS_SUCCESS;
diff --git a/plugins/experimental/txn_box/plugin/include/txn_box/Config.h b/plugins/experimental/txn_box/plugin/include/txn_box/Config.h
index 277fd09e18..6461b4c5b5 100644
--- a/plugins/experimental/txn_box/plugin/include/txn_box/Config.h
+++ b/plugins/experimental/txn_box/plugin/include/txn_box/Config.h
@@ -559,6 +559,11 @@ protected:
   /// Set of named configuration storage objects.
   std::unordered_map<swoc::TextView, swoc::MemSpan<void>, std::hash<std::string_view>> _named_objects;
 
+  /// For localizing data at a configuration level, primarily strings.
+  /// Declared before _roots so it is destroyed after _roots, since directives
+  /// in _roots reference memory allocated from this arena.
+  swoc::MemArena _arena;
+
   /// Top level directives for each hook. Always invoked.
   std::array<std::vector<Directive::Handle>, std::tuple_size<Hook>::value> _roots;
 
@@ -566,9 +571,6 @@ protected:
   /// directive load, if needed. This includes the top level directives.
   std::array<size_t, std::tuple_size<Hook>::value> _directive_count{0};
 
-  /// For localizing data at a configuration level, primarily strings.
-  swoc::MemArena _arena;
-
   /// Additional clean up to perform when @a this is destroyed.
   swoc::IntrusiveDList<Finalizer::Linkage> _finalizers;
 
diff --git a/plugins/slice/server.cc b/plugins/slice/server.cc
index 7ed2841e32..cc0afd9c5d 100644
--- a/plugins/slice/server.cc
+++ b/plugins/slice/server.cc
@@ -97,6 +97,7 @@ update_object_size(TSHttpTxn txnp, int64_t size, Config &config)
   if (urlstr != nullptr) {
     if (size <= 0) {
       DEBUG_LOG("Ignoring invalid content length for %.*s: %" PRId64, urllen, urlstr, size);
+      TSfree(urlstr);
       return;
     }
 
diff --git a/plugins/stats_over_http/stats_over_http.cc b/plugins/stats_over_http/stats_over_http.cc
index b02b17c44e..e927cc6849 100644
--- a/plugins/stats_over_http/stats_over_http.cc
+++ b/plugins/stats_over_http/stats_over_http.cc
@@ -777,7 +777,8 @@ stats_origin(TSCont contp, TSEvent /* event ATS_UNUSED */, void *edata)
   icontp   = TSContCreate(stats_dostuff, TSMutexCreate());
 
   if (path_had_explicit_format) {
-    Dbg(dbg_ctl, "Path had explicit format, ignoring any Accept header: %s", request_path_suffix.data());
+    Dbg(dbg_ctl, "Path had explicit format, ignoring any Accept header: %.*s", static_cast<int>(request_path_suffix.size()),
+        request_path_suffix.data());
     my_state->output_format = format_per_path;
   } else {
     // Check for an Accept header to determine response type.
diff --git a/tests/tools/plugins/async_engine.c b/tests/tools/plugins/async_engine.c
index 8032293449..4624f20dd1 100644
--- a/tests/tools/plugins/async_engine.c
+++ b/tests/tools/plugins/async_engine.c
@@ -173,11 +173,12 @@ async_destroy(ENGINE *e ATS_UNUSED)
 static void
 wait_cleanup(ASYNC_WAIT_CTX *ctx ATS_UNUSED, const void *key ATS_UNUSED, OSSL_ASYNC_FD readfd, void *pvwritefd)
 {
-  OSSL_ASYNC_FD *pwritefd = (OSSL_ASYNC_FD *)pvwritefd;
+  OSSL_ASYNC_FD *pwritefd  = (OSSL_ASYNC_FD *)pvwritefd;
+  OSSL_ASYNC_FD  writefd_v = *pwritefd;
   close(readfd);
-  close(*((OSSL_ASYNC_FD *)pwritefd));
+  close(writefd_v);
   OPENSSL_free(pwritefd);
-  fprintf(stderr, "Cleanup %d and %d\n", readfd, *pwritefd);
+  fprintf(stderr, "Cleanup %d and %d\n", readfd, writefd_v);
 }
 
 #define DUMMY_CHAR 'X'