From e79be7fd2240347f534c1016d4856fe383aaa479 Mon Sep 17 00:00:00 2001

From: guowentao <guowentao@xfusion.com>

Date: Mon, 2 Feb 2026 11:41:21 +0800

Subject: [PATCH] Fix security hole checking unpacked kernel headers (#3033)



Make sure to check that the unpacked kheaders tar

is owned by root to prevent bpftrace from loading

compromised linux headers.



Signed-off-by: guowentao <guowentao@xfusion.com>

Reference:https://github.com/bpftrace/bpftrace/commit/4be4b7191acb8218240e6b7178c30fa8c9b59998

---

 src/utils.cpp   | 22 +++++++++++++++++++---

 src/utils.h     |  1 +

 tests/utils.cpp | 21 +++++++++++++++++++++

 3 files changed, 41 insertions(+), 3 deletions(-)



diff --git a/src/utils.cpp b/src/utils.cpp

index 8b070eb..ef4cc90 100644

--- a/src/utils.cpp

+++ b/src/utils.cpp

@@ -109,6 +109,8 @@ const struct vmlinux_location vmlinux_locs[] = {

   { nullptr, false },

 };

 

+constexpr std::string_view PROC_KHEADERS_PATH = "/sys/kernel/kheaders.tar.xz";

+

 static bool pid_in_different_mountns(int pid);

 static std::vector<std::string>

 resolve_binary_path(const std::string &cmd, const char *env_paths, int pid);

@@ -700,6 +702,20 @@ bool is_dir(const std::string& path)

   return std_filesystem::is_directory(buf, ec);

 }

 

+bool file_exists_and_ownedby_root(const char *f)

+{

+  struct stat st;

+  if (stat(f, &st) == 0) {

+    if (st.st_uid != 0) {

+      LOG(ERROR) << "header file ownership expected to be root: "

+                 << std::string(f);

+      return false;

+    }

+    return true;

+  }

+  return false;

+}

+

 namespace {

   struct KernelHeaderTmpDir {

     KernelHeaderTmpDir(const std::string& prefix) : path{prefix + "XXXXXX"}

@@ -736,14 +752,14 @@ namespace {

 #else

     std_filesystem::path path_prefix{ "/tmp" };

 #endif

-    std_filesystem::path path_kheaders{ "/sys/kernel/kheaders.tar.xz" };

+    std_filesystem::path path_kheaders{ PROC_KHEADERS_PATH };

     if (const char* tmpdir = ::getenv("TMPDIR")) {

       path_prefix = tmpdir;

     }

     path_prefix /= "kheaders-";

     std_filesystem::path shared_path{ path_prefix.string() + utsname.release };

 

-    if (std_filesystem::exists(shared_path, ec))

+    if (file_exists_and_ownedby_root(shared_path.c_str()))

     {

       // already unpacked

       return shared_path.string();

@@ -767,7 +783,7 @@ namespace {

 

     KernelHeaderTmpDir tmpdir{path_prefix};

 

-    FILE* tar = ::popen(("tar xf /sys/kernel/kheaders.tar.xz -C " + tmpdir.path).c_str(), "w");

+    FILE* tar = ::popen(("tar xf " + std::string(PROC_KHEADERS_PATH) + " -C " + tmpdir.path).c_str(), "w");

     if (!tar) {

       return "";

     }

diff --git a/src/utils.h b/src/utils.h

index 7c08961..b804749 100644

--- a/src/utils.h

+++ b/src/utils.h

@@ -185,6 +185,7 @@ std::vector<std::string> get_wildcard_tokens(const std::string &input,

 std::vector<int> get_online_cpus();

 std::vector<int> get_possible_cpus();

 bool is_dir(const std::string &path);

+bool file_exists_and_ownedby_root(const char *f);

 std::tuple<std::string, std::string> get_kernel_dirs(

     const struct utsname &utsname,

     bool unpack_kheaders = true);

diff --git a/tests/utils.cpp b/tests/utils.cpp

index 88d4800..da097e7 100644

--- a/tests/utils.cpp

+++ b/tests/utils.cpp

@@ -363,6 +363,27 @@ TEST(utils, get_pids_for_program)

   ASSERT_EQ(pids.size(), 0);

 }

 

+TEST(utils, file_exists_and_ownedby_root)

+{

+  std::string tmpdir = "/tmp/bpftrace-test-utils-XXXXXX";

+  std::string file1 = "/ownedby-user";

+  std::string file2 = "/no-exists";

+  if (::mkdtemp(tmpdir.data()) == nullptr) {

+    throw std::runtime_error("creating temporary path for tests failed");

+  }

+

+  int fd;

+  fd = open((tmpdir + file1).c_str(), O_CREAT, S_IRUSR);

+  close(fd);

+  ASSERT_GE(fd, 0);

+

+  EXPECT_FALSE(file_exists_and_ownedby_root((tmpdir + file1).c_str()));

+  EXPECT_FALSE(file_exists_and_ownedby_root((tmpdir + file2).c_str()));

+  EXPECT_TRUE(file_exists_and_ownedby_root("/proc/1/maps"));

+

+  EXPECT_GT(std_filesystem::remove_all(tmpdir), 0);

+}

+

 } // namespace utils

 } // namespace test

 } // namespace bpftrace

-- 

2.43.0