]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
FreeBSD syscall: improve kenv wrapper and add a test for it master
authorPaul Floyd <pjfloyd@wanadoo.fr>
Sat, 12 Jul 2025 14:21:29 +0000 (16:21 +0200)
committerPaul Floyd <pjfloyd@wanadoo.fr>
Sat, 12 Jul 2025 14:22:21 +0000 (16:22 +0200)
.gitignore
coregrind/m_syswrap/syswrap-freebsd.c
include/vki/vki-freebsd.h
memcheck/tests/freebsd/Makefile.am
memcheck/tests/freebsd/kenv.cpp [new file with mode: 0644]
memcheck/tests/freebsd/kenv.stderr.exp [new file with mode: 0644]
memcheck/tests/freebsd/kenv.vgtest [new file with mode: 0644]
memcheck/tests/freebsd/scalar.stderr.exp
memcheck/tests/freebsd/scalar.stderr.exp-x86

index e4ddf5dc65ef08217ee5055accfa2088e4386c02..19c2a9300def59f1c9746b389aa5cec46d5e83cf 100644 (file)
 /memcheck/tests/freebsd/getrlimitusage
 /memcheck/tests/freebsd/inlinfo
 /memcheck/tests/freebsd/inlinfo_nested.so
+/memcheck/tests/freebsd/kenv
 /memcheck/tests/freebsd/kqueue
 /memcheck/tests/freebsd/kqueuex
 /memcheck/tests/freebsd/linkat
index e6e71c78d9aa0c0e0a994d3abfd11b3b5c20fbd1..4ce860976c1fd3852993a461db5415737d3906ee 100644 (file)
@@ -3697,19 +3697,39 @@ PRE(sys_nmount)
 PRE(sys_kenv)
 {
    PRINT("sys_kenv ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG2,ARG3,ARG4);
-   PRE_REG_READ4(int, "kenv",
-                 int, action, const char *, name, char *, value, int, len);
    switch (ARG1) {
    case VKI_KENV_GET:
+      // read from arg1, write to arg2
+      PRE_REG_READ4(int, "kenv",
+                    int, action, const char *, name, char *, value, int, len);
+      PRE_MEM_RASCIIZ("kenv(name)", ARG2);
+      PRE_MEM_WRITE("kenv(value)", ARG3, ARG4);
+      break;
    case VKI_KENV_SET:
+      PRE_REG_READ3(int, "kenv",
+                   int, action, const char *, name, char *, value);
+      PRE_MEM_RASCIIZ("kenv(name)", ARG2);
+      PRE_MEM_RASCIIZ("kenv(value)", ARG3);
+      break;
    case VKI_KENV_UNSET:
+      PRE_REG_READ2(int, "kenv", int, action, const char *, name);
       PRE_MEM_RASCIIZ("kenv(name)", ARG2);
-   /* FALLTHROUGH */
+      break;
    case VKI_KENV_DUMP:
+   case VKI_KENV_DUMP_LOADER:
+   case VKI_KENV_DUMP_STATIC:
+      PRRSN;
+      PRA1("kenv",int,action);
+      // ARG2 name is ignored
+      PRA3("kenv",char*,value);
+      PRA4("kenv",int,len);
+      if (ARG3) {
+         PRE_MEM_WRITE("kenv(value)", ARG3, ARG4);
+      }
       break;
    default:
       if (VG_(clo_verbosity) >= 1) {
-         VG_(umsg)("Warning: unimplemented kenv action: %" FMT_REGWORD "d\n",
+         VG_(umsg)("Warning: bad or unimplemented kenv action: %" FMT_REGWORD "d\n",
             ARG1);
       }
       break;
@@ -3724,7 +3744,7 @@ POST(sys_kenv)
          POST_MEM_WRITE(ARG3, ARG4);
          break;
       case VKI_KENV_DUMP:
-         if (ARG3 != (Addr)NULL) {
+         if (ARG3) {
             POST_MEM_WRITE(ARG3, ARG4);
          }
          break;
index 6be56c27ad4982ab895da00c3b150faa5664eadb..63ffbe7e5ee0a4463dd15ee87ca5c40390b0dfe5 100644 (file)
@@ -2228,10 +2228,12 @@ struct vki_kinfo_file {
 //----------------------------------------------------------------------
 // From sys/kenv.h
 //----------------------------------------------------------------------
-#define VKI_KENV_GET    0
-#define VKI_KENV_SET    1
-#define VKI_KENV_UNSET     2
-#define VKI_KENV_DUMP      3
+#define VKI_KENV_GET         0
+#define VKI_KENV_SET         1
+#define VKI_KENV_UNSET       2
+#define VKI_KENV_DUMP        3
+#define VKI_KENV_DUMP_LOADER 4
+#define VKI_KENV_DUMP_STATIC 5
 
 //----------------------------------------------------------------------
 // From sys/sysctl.h (and related)
index 091d056785c11587aeb8c3e8f5e5bb45994ecacf..db1e2aca564645dd717ae28a19a9eca02d486aa0 100644 (file)
@@ -70,6 +70,8 @@ EXTRA_DIST = \
        getfsstat.supp \
                getfsstat.stderr.exp-x86 \
        getrlimitusage.vgtest getrlimitusage.stderr.exp \
+       kenv.vgtest \
+       kenv.stderr.exp \
        kqueue.vgtest \
        kqueue.stderr.exp \
        kqueue.stdout.exp \
@@ -156,6 +158,7 @@ check_PROGRAMS = \
        fexecve \
        file_locking_wait6 \
        get_set_context get_set_login getfh \
+       kenv \
        kqueue linkat memalign misc \
        openpty \
        pdfork_pdkill getfsstat inlinfo inlinfo_nested.so \
@@ -236,6 +239,7 @@ extattr_CFLAGS                      = ${AM_CFLAGS} @FLAG_W_NO_UNUSED_BUT_SET_VARIABLE@ @FLAG_W_NO_U
 get_set_login_CFLAGS           = ${AM_CFLAGS} @FLAG_W_NO_USE_AFTER_FREE@
 getfh_CFLAGS                   = ${AM_CFLAGS} @FLAG_W_NO_USE_AFTER_FREE@
 getfsstat_CFLAGS               = ${AM_CFLAGS} @FLAG_W_NO_UNINITIALIZED@ @FLAG_W_NO_USE_AFTER_FREE@
+kenv_SOURCES                   = kenv.cpp
 linkat_CFLAGS                  = ${AM_CFLAGS} @FLAG_W_NO_MAYBE_UNINITIALIZED@ @FLAG_W_NO_UNINITIALIZED@ @FLAG_W_NO_USE_AFTER_FREE@
 memalign_CFLAGS                        = ${AM_CFLAGS} @FLAG_W_NO_NON_POWER_OF_TWO_ALIGNMENT@
 misc_CFLAGS                    = ${AM_CFLAGS} @FLAG_W_NO_USE_AFTER_FREE@
diff --git a/memcheck/tests/freebsd/kenv.cpp b/memcheck/tests/freebsd/kenv.cpp
new file mode 100644 (file)
index 0000000..5f02937
--- /dev/null
@@ -0,0 +1,130 @@
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <exception>
+#include <cerrno>
+#include <kenv.h>
+#include <unistd.h>
+
+static long x0;
+
+int main(int argc, char** argv)
+{
+   long *px{static_cast<long*>(malloc(2*sizeof(long)))};
+   x0 = px[0];
+   try
+   {
+      const size_t bufSize{1024};
+      auto buf{std::make_unique<char[]>(bufSize)};
+      std::string name{"bootfile"};
+      int res{kenv(KENV_GET, name.c_str(), buf.get(), bufSize)};
+
+      if (res == -1)
+      {
+         throw std::runtime_error("kenv get non-root");
+      }
+
+      if (argc > 1)
+      {
+         std::cout << buf << '\n';
+      }
+
+      res = kenv(42*42, name.c_str(), buf.get(), bufSize);
+      if (res == 0)
+      {
+         throw std::runtime_error("kenv get bogus action succeeded");
+      }
+      if (errno != EINVAL)
+      {
+         std::stringstream ss;
+         ss << "kenv get bogus action wrong errno, expected " << EINVAL << " got " << errno;
+         throw std::runtime_error(ss.str());
+      }
+
+      res = kenv(KENV_GET, "zyxxy", buf.get(), bufSize);
+      if (res == 0)
+      {
+         throw std::runtime_error("kenv get bogus name succeeded");
+      }
+      if (errno != ENOENT)
+      {
+         std::stringstream ss;
+         ss << "kenv get bogus name wrong errno, expected " << ENOENT << " got " << errno;
+         throw std::runtime_error(ss.str());
+      }
+
+      res = kenv(KENV_DUMP, "this does not matter", nullptr, -1);
+      if (res == -1)
+      {
+         throw std::runtime_error("kenv dump to get size non-root");
+      }
+      if (argc > 1)
+      {
+         std::cout << "dump size " << res << '\n';
+      }
+      auto dump_buf{std::make_unique<char[]>(res)};
+      char* uninitCharStar;
+      res = kenv(KENV_DUMP, uninitCharStar, dump_buf.get(), res);
+
+      if (argc > 1)
+      {
+         // the buffer contains nul separated eleements, this will just print the first
+         std::cout << dump_buf << '\n';
+      }
+
+      if (0 == geteuid())
+      {
+         res = kenv(KENV_SET, "this", const_cast<char*>("that"), 5);
+         if (res == -1)
+         {
+             throw std::runtime_error("kenv set root");
+         }
+         res = kenv(KENV_SET, "this", const_cast<char*>("thing"), 6);
+         if (res == -1)
+         {
+             throw std::runtime_error("kenv set root");
+         }
+         res = kenv(KENV_UNSET, "this", const_cast<char*>("yes we have no bananas"), 42);
+         if (res == -1)
+         {
+             throw std::runtime_error("kenv set root");
+         }
+      }
+      else
+      {
+         // now try some things that will fail
+         int uninitInt;
+         res = kenv(KENV_SET, "this", const_cast<char*>("that"), uninitInt);
+         if (res != -1)
+         {
+             throw std::runtime_error("kenv set non-root succeeded");
+         }
+         if (errno != EPERM)
+         {
+            std::stringstream ss;
+            ss << "kenv get bogus action wrong errno, expected " << EPERM << " got " << errno;
+            throw std::runtime_error(ss.str());
+         }
+
+         // checks all the args
+         kenv(KENV_GET+x0, name.c_str()+x0, buf.get()+x0, 1024+x0);
+
+         // now some memory errors
+         char* freeName{new char[32]};
+         sprintf(freeName, "%s", "blah");
+         delete [] freeName;
+         kenv(KENV_GET, freeName, buf.get(), 32);
+         char* freeBuf{new char[32]};
+         delete [] freeBuf;
+         kenv(KENV_GET, name.c_str(), freeBuf, 32);
+         int res{kenv(KENV_GET, name.c_str(), buf.get(), 2*bufSize)};
+      }
+
+   }
+   catch (std::exception& e)
+   {
+      std::cout << "FAILED: " << e.what() << '\n';
+      exit(-1);
+   }
+   free(px);
+}
diff --git a/memcheck/tests/freebsd/kenv.stderr.exp b/memcheck/tests/freebsd/kenv.stderr.exp
new file mode 100644 (file)
index 0000000..c356c7c
--- /dev/null
@@ -0,0 +1,55 @@
+
+Warning: bad or unimplemented kenv action: 1764
+Syscall param kenv(action) contains uninitialised byte(s)
+   at 0x........: kenv (in /...libc...)
+   by 0x........: main (kenv.cpp:110)
+
+Syscall param kenv(name) contains uninitialised byte(s)
+   at 0x........: kenv (in /...libc...)
+   by 0x........: main (kenv.cpp:110)
+
+Syscall param kenv(value) contains uninitialised byte(s)
+   at 0x........: kenv (in /...libc...)
+   by 0x........: main (kenv.cpp:110)
+
+Syscall param kenv(len) contains uninitialised byte(s)
+   at 0x........: kenv (in /...libc...)
+   by 0x........: main (kenv.cpp:110)
+
+Syscall param kenv(name) points to unaddressable byte(s)
+   at 0x........: kenv (in /...libc...)
+   by 0x........: main (kenv.cpp:116)
+ Address 0x........ is 0 bytes inside a block of size 32 free'd
+   at 0x........: ...operator delete[]... (vg_replace_malloc.c:...)
+   by 0x........: main (kenv.cpp:115)
+ Block was alloc'd at
+   at 0x........: ...operator new[]... (vg_replace_malloc.c:...)
+   by 0x........: main (kenv.cpp:113)
+
+Syscall param kenv(value) points to unaddressable byte(s)
+   at 0x........: kenv (in /...libc...)
+   by 0x........: main (kenv.cpp:119)
+ Address 0x........ is 0 bytes inside a block of size 32 free'd
+   at 0x........: ...operator delete[]... (vg_replace_malloc.c:...)
+   by 0x........: main (kenv.cpp:118)
+ Block was alloc'd at
+   at 0x........: ...operator new[]... (vg_replace_malloc.c:...)
+   by 0x........: main (kenv.cpp:117)
+
+Syscall param kenv(value) points to unaddressable byte(s)
+   at 0x........: kenv (in /...libc...)
+   by 0x........: main (kenv.cpp:120)
+ Address 0x........ is 0 bytes after a block of size 1,024 alloc'd
+   at 0x........: ...operator new[]... (vg_replace_malloc.c:...)
+   by 0x........: main (kenv.cpp:18)
+
+
+HEAP SUMMARY:
+    in use at exit: 0 bytes in 0 blocks
+  total heap usage: 5 allocs, 5 frees, 4,765 bytes allocated
+
+For a detailed leak analysis, rerun with: --leak-check=full
+
+Use --track-origins=yes to see where uninitialised values come from
+For lists of detected and suppressed errors, rerun with: -s
+ERROR SUMMARY: 7 errors from 7 contexts (suppressed: 0 from 0)
diff --git a/memcheck/tests/freebsd/kenv.vgtest b/memcheck/tests/freebsd/kenv.vgtest
new file mode 100644 (file)
index 0000000..763cd16
--- /dev/null
@@ -0,0 +1 @@
+prog: kenv
index 2e6ca39b49a954aa98d135fe57ccc382e13a0a60..ae8adcd1b4888e345ea2de97ec6f376f8ec1c6c8 100644 (file)
@@ -2968,21 +2968,26 @@ Syscall param kenv(name) points to unaddressable byte(s)
    ...
  Address 0x........ is not stack'd, malloc'd or (recently) free'd
 
+Syscall param kenv(value) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
 ---------------------------------------------------------
 390:                SYS_kenv (KENV_DUMP) 4s 0m
 ---------------------------------------------------------
 Syscall param kenv(action) contains uninitialised byte(s)
    ...
 
-Syscall param kenv(name) contains uninitialised byte(s)
-   ...
-
 Syscall param kenv(value) contains uninitialised byte(s)
    ...
 
 Syscall param kenv(len) contains uninitialised byte(s)
    ...
 
+Syscall param kenv(value) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
 ---------------------------------------------------------
 391:            SYS_lchflags 2s 1m
 ---------------------------------------------------------
index 24c7caac0427e7479926aa30269b1d2eec7fc9fe..47beb3dcecb3918ccff2b3385df0583cdae935a3 100644 (file)
@@ -2974,21 +2974,26 @@ Syscall param kenv(name) points to unaddressable byte(s)
    ...
  Address 0x........ is not stack'd, malloc'd or (recently) free'd
 
+Syscall param kenv(value) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
 ---------------------------------------------------------
 390:                SYS_kenv (KENV_DUMP) 4s 0m
 ---------------------------------------------------------
 Syscall param kenv(action) contains uninitialised byte(s)
    ...
 
-Syscall param kenv(name) contains uninitialised byte(s)
-   ...
-
 Syscall param kenv(value) contains uninitialised byte(s)
    ...
 
 Syscall param kenv(len) contains uninitialised byte(s)
    ...
 
+Syscall param kenv(value) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
 ---------------------------------------------------------
 391:            SYS_lchflags 2s 1m
 ---------------------------------------------------------