From: Paul Floyd Date: Sat, 3 Jan 2026 20:17:00 +0000 (+0100) Subject: readlink[at] syswrap: limit copy to bufsiz when path is proc self exe X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bd9edb8fcd0a8692d865e08fab2a573a4cde4c16;p=thirdparty%2Fvalgrind.git readlink[at] syswrap: limit copy to bufsiz when path is proc self exe --- diff --git a/.gitignore b/.gitignore index 5ac1f3cb9..5754f271f 100644 --- a/.gitignore +++ b/.gitignore @@ -1921,6 +1921,7 @@ /none/tests/linux/mremap6 /none/tests/linux/open_client /none/tests/linux/pthread-stack +/none/tests/linux/readlinkat_self /none/tests/linux/stack-overflow /none/tests/linux/getdents_filter diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c index c0e717d27..406e6960b 100644 --- a/coregrind/m_syswrap/syswrap-generic.c +++ b/coregrind/m_syswrap/syswrap-generic.c @@ -5095,6 +5095,7 @@ PRE(sys_readlink) && (VG_STREQ(arg1s, name) || VG_STREQ(arg1s, SELF_EXEPATH))) { HChar* out_name = (HChar*)ARG2; SizeT res = VG_(strlen)(VG_(resolved_exename)); + res = VG_MIN(res, ARG3); VG_(strncpy)(out_name, VG_(resolved_exename), res); SET_STATUS_Success(res); fuse_may_block = False; diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c index 10e63348d..53b620585 100644 --- a/coregrind/m_syswrap/syswrap-linux.c +++ b/coregrind/m_syswrap/syswrap-linux.c @@ -6684,14 +6684,10 @@ PRE(sys_readlinkat) ML_(fd_at_check_allowed)(SARG1, (const HChar*)ARG2, "readlinkat", tid, status); PRE_MEM_RASCIIZ( "readlinkat(path)", ARG2 ); PRE_MEM_WRITE( "readlinkat(buf)", ARG3,ARG4 ); -} -POST(sys_readlinkat) -{ + Bool fuse_may_block = True; HChar name[30]; // large enough - Word saved = SYSNO; - // @todo PJF why is this done in POST and not in PRE? /* * Handle the case where readlinkat is looking at /proc/self/exe or * /proc//exe. @@ -6700,13 +6696,21 @@ POST(sys_readlinkat) if (ML_(safe_to_deref)((void*)(Addr)ARG2, 1) && (VG_(strcmp)((HChar *)(Addr)ARG2, name) == 0 || VG_(strcmp)((HChar *)(Addr)ARG2, "/proc/self/exe") == 0)) { - VG_(sprintf)(name, "/proc/self/fd/%d", VG_(cl_exec_fd)); - SET_STATUS_from_SysRes( VG_(do_syscall4)(saved, ARG1, (UWord)name, - ARG3, ARG4)); + HChar* out_name = (HChar*)ARG3; + SizeT res = VG_(strlen)(VG_(resolved_exename)); + res = VG_MIN(res, ARG4); + VG_(strncpy)(out_name, VG_(resolved_exename), res); + SET_STATUS_Success(res); + fuse_may_block = False; } - if (SUCCESS && RES > 0) - POST_MEM_WRITE( ARG3, RES ); + if (fuse_may_block) + FUSE_COMPATIBLE_MAY_BLOCK(); +} + +POST(sys_readlinkat) +{ + POST_MEM_WRITE( ARG3, RES ); } PRE(sys_fchmodat) diff --git a/none/tests/bug514094.c b/none/tests/bug514094.c index d5fcd299a..848db1d82 100644 --- a/none/tests/bug514094.c +++ b/none/tests/bug514094.c @@ -24,5 +24,17 @@ int main(int argc, char** argv) char resolved[PATH_MAX]; realpath(argv[0], resolved); assert(strcmp(resolved, buf) == 0); + + const size_t small_buf_size = 11; + char small_buf[11]; + memset(small_buf, '#', 11); +#if defined(VGO_solaris) + ret = readlink("/proc/self/path/a.out", small_buf, 10); +#else + ret = readlink("/proc/self/exe", small_buf, 10); +#endif + assert(strncmp(resolved, small_buf, 10) == 0); + assert(small_buf[10] == '#'); + } diff --git a/none/tests/linux/Makefile.am b/none/tests/linux/Makefile.am index 519eb7dd6..20540247f 100644 --- a/none/tests/linux/Makefile.am +++ b/none/tests/linux/Makefile.am @@ -20,6 +20,7 @@ EXTRA_DIST = \ mremap6.stderr.exp mremap6.vgtest \ open_client.stderr.exp open_client.vgtest \ pthread-stack.stderr.exp pthread-stack.vgtest \ + readlinkat_self.stderr.exp readlinkat_self.vgtest \ stack-overflow.stderr.exp stack-overflow.vgtest check_PROGRAMS = \ @@ -36,6 +37,7 @@ check_PROGRAMS = \ mremap5 \ mremap6 \ pthread-stack \ + readlinkat_self \ stack-overflow if HAVE_OPENAT2