From: Paul Floyd Date: Sat, 12 Jul 2025 14:21:29 +0000 (+0200) Subject: FreeBSD syscall: improve kenv wrapper and add a test for it X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7cbcd30804fc5fa412ae516ea05cbdb57ea8952a;p=thirdparty%2Fvalgrind.git FreeBSD syscall: improve kenv wrapper and add a test for it --- diff --git a/.gitignore b/.gitignore index e4ddf5dc6..19c2a9300 100644 --- a/.gitignore +++ b/.gitignore @@ -1445,6 +1445,7 @@ /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 diff --git a/coregrind/m_syswrap/syswrap-freebsd.c b/coregrind/m_syswrap/syswrap-freebsd.c index e6e71c78d..4ce860976 100644 --- a/coregrind/m_syswrap/syswrap-freebsd.c +++ b/coregrind/m_syswrap/syswrap-freebsd.c @@ -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; diff --git a/include/vki/vki-freebsd.h b/include/vki/vki-freebsd.h index 6be56c27a..63ffbe7e5 100644 --- a/include/vki/vki-freebsd.h +++ b/include/vki/vki-freebsd.h @@ -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) diff --git a/memcheck/tests/freebsd/Makefile.am b/memcheck/tests/freebsd/Makefile.am index 091d05678..db1e2aca5 100644 --- a/memcheck/tests/freebsd/Makefile.am +++ b/memcheck/tests/freebsd/Makefile.am @@ -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 index 000000000..5f029370f --- /dev/null +++ b/memcheck/tests/freebsd/kenv.cpp @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include +#include +#include + +static long x0; + +int main(int argc, char** argv) +{ + long *px{static_cast(malloc(2*sizeof(long)))}; + x0 = px[0]; + try + { + const size_t bufSize{1024}; + auto buf{std::make_unique(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(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("that"), 5); + if (res == -1) + { + throw std::runtime_error("kenv set root"); + } + res = kenv(KENV_SET, "this", const_cast("thing"), 6); + if (res == -1) + { + throw std::runtime_error("kenv set root"); + } + res = kenv(KENV_UNSET, "this", const_cast("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("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 index 000000000..c356c7c83 --- /dev/null +++ b/memcheck/tests/freebsd/kenv.stderr.exp @@ -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 index 000000000..763cd16a2 --- /dev/null +++ b/memcheck/tests/freebsd/kenv.vgtest @@ -0,0 +1 @@ +prog: kenv diff --git a/memcheck/tests/freebsd/scalar.stderr.exp b/memcheck/tests/freebsd/scalar.stderr.exp index 2e6ca39b4..ae8adcd1b 100644 --- a/memcheck/tests/freebsd/scalar.stderr.exp +++ b/memcheck/tests/freebsd/scalar.stderr.exp @@ -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 --------------------------------------------------------- diff --git a/memcheck/tests/freebsd/scalar.stderr.exp-x86 b/memcheck/tests/freebsd/scalar.stderr.exp-x86 index 24c7caac0..47beb3dce 100644 --- a/memcheck/tests/freebsd/scalar.stderr.exp-x86 +++ b/memcheck/tests/freebsd/scalar.stderr.exp-x86 @@ -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 ---------------------------------------------------------