From: Paul Floyd Date: Sat, 3 Jan 2026 12:48:50 +0000 (+0100) Subject: Bug 514094 - readlink("/proc/self/exe") overwrites buffer beyond its return value X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5c0f5e604bc3a4e8822ea59c488c123af6284afd;p=thirdparty%2Fvalgrind.git Bug 514094 - readlink("/proc/self/exe") overwrites buffer beyond its return value Used the reproducer as the basis for a test on Solaris and Linux. --- diff --git a/.gitignore b/.gitignore index 039ce52a9..5ac1f3cb9 100644 --- a/.gitignore +++ b/.gitignore @@ -1579,6 +1579,7 @@ /none/tests/bug290061 /none/tests/bug491394 /none/tests/bug492678 +/none/tests/bug514094 /none/tests/closeall /none/tests/coolo_sigaction /none/tests/coolo_strlen diff --git a/NEWS b/NEWS index e0bdc122c..1da711b26 100644 --- a/NEWS +++ b/NEWS @@ -55,6 +55,7 @@ are not entered into bugzilla tend to get forgotten about or ignored. 513522 m_libcassert.c: 'ordered comparison of pointer with integer zero' compiler warning 513475 Add SSE4.1 PMULLD instruction for x86 32 bit +514094 readlink("/proc/self/exe") overwrites buffer beyond its return value To see details of a given bug, visit https://bugs.kde.org/show_bug.cgi?id=XXXXXX diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c index 2c113c69c..c0e717d27 100644 --- a/coregrind/m_syswrap/syswrap-generic.c +++ b/coregrind/m_syswrap/syswrap-generic.c @@ -5065,20 +5065,16 @@ POST(sys_poll) PRE(sys_readlink) { - FUSE_COMPATIBLE_MAY_BLOCK(); PRINT("sys_readlink ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x, %llu )", ARG1, (char*)(Addr)ARG1, ARG2, (ULong)ARG3); PRE_REG_READ3(long, "readlink", const char *, path, char *, buf, int, bufsiz); PRE_MEM_RASCIIZ( "readlink(path)", ARG1 ); PRE_MEM_WRITE( "readlink(buf)", ARG2,ARG3 ); -} -POST(sys_readlink) -{ + Bool fuse_may_block = True; #if defined(VGO_linux) || defined(VGO_solaris) { - Word saved = SYSNO; #if defined(VGO_linux) #define PID_EXEPATH "/proc/%d/exe" #define SELF_EXEPATH "/proc/self/exe" @@ -5097,14 +5093,22 @@ POST(sys_readlink) VG_(sprintf)(name, PID_EXEPATH, VG_(getpid)()); if (ML_(safe_to_deref)(arg1s, 1) && (VG_STREQ(arg1s, name) || VG_STREQ(arg1s, SELF_EXEPATH))) { - VG_(sprintf)(name, SELF_EXEFD, VG_(cl_exec_fd)); - SET_STATUS_from_SysRes( VG_(do_syscall3)(saved, (UWord)name, - ARG2, ARG3)); + HChar* out_name = (HChar*)ARG2; + SizeT res = VG_(strlen)(VG_(resolved_exename)); + VG_(strncpy)(out_name, VG_(resolved_exename), res); + SET_STATUS_Success(res); + fuse_may_block = False; } } #endif - if (SUCCESS && RES > 0) - POST_MEM_WRITE( ARG2, RES ); + + if (fuse_may_block) + FUSE_COMPATIBLE_MAY_BLOCK(); +} + +POST(sys_readlink) +{ + POST_MEM_WRITE( ARG2, RES ); } PRE(sys_readv) diff --git a/none/tests/Makefile.am b/none/tests/Makefile.am index 0cc4ca8b0..3147d784c 100644 --- a/none/tests/Makefile.am +++ b/none/tests/Makefile.am @@ -111,6 +111,7 @@ EXTRA_DIST = \ bug290061.vgtest bug290061.stderr.exp \ bug491394.vgtest bug491394.stderr.exp \ bug492678.vgtest bug492678.stderr.exp \ + bug514094,vgtest bug514094.stderr.exp \ closeall.stderr.exp closeall.vgtest \ cmdline0.stderr.exp cmdline0.stdout.exp cmdline0.vgtest \ cmdline1.stderr.exp cmdline1.stdout.exp cmdline1.vgtest \ @@ -285,6 +286,7 @@ check_PROGRAMS = \ bug129866 bug234814 \ bug290061 \ bug492678 \ + bug514094 \ closeall coolo_strlen \ discard exec-sigmask execve faultstatus fcntl_setown \ fdleak_cmsg fdleak_creat fdleak_doubleclose0 fdleak_dup fdleak_dup2 \ diff --git a/none/tests/bug514094.c b/none/tests/bug514094.c new file mode 100644 index 000000000..d5fcd299a --- /dev/null +++ b/none/tests/bug514094.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include +#include +#include +#include "../../config.h" + +int main(int argc, char** argv) +{ + char buf[PATH_MAX]; + memset(buf, 0, PATH_MAX); +#if defined(VGO_solaris) + int ret = readlink("/proc/self/path/a.out", buf, PATH_MAX); +#else + // Linux, and maybe one day NetBSD + // other platforms excluded by .vgtest prereq + int ret = readlink("/proc/self/exe", buf, PATH_MAX); +#endif + if (argc > 1) { + printf("ret = %d, buf = %.64s\n", ret, buf); + } + char resolved[PATH_MAX]; + realpath(argv[0], resolved); + assert(strcmp(resolved, buf) == 0); +} + diff --git a/none/tests/bug514094.stderr.exp b/none/tests/bug514094.stderr.exp new file mode 100644 index 000000000..139597f9c --- /dev/null +++ b/none/tests/bug514094.stderr.exp @@ -0,0 +1,2 @@ + + diff --git a/none/tests/bug514094.vgtest b/none/tests/bug514094.vgtest new file mode 100644 index 000000000..292428cb7 --- /dev/null +++ b/none/tests/bug514094.vgtest @@ -0,0 +1,2 @@ +prereq: ../../tests/os_test solaris || ../../tests/os_test linux +prog: bug514094