Bug 410743 - shmat() calls for 32-bit programs fail when running in 64-bit valgrind
Summary: shmat() calls for 32-bit programs fail when running in 64-bit valgrind
Alias: None
Product: valgrind
Classification: Developer tools
Component: memcheck (show other bugs)
Version: unspecified
Platform: Other Linux
: NOR normal
Target Milestone: ---
Assignee: Julian Seward
: 423929 (view as bug list)
Depends on:
Reported: 2019-08-08 21:22 UTC by Eric Reischer
Modified: 2021-02-04 16:55 UTC (History)
3 users (show)

See Also:
Latest Commit:
Version Fixed In:

Patch: Fix shmat() on nanomips and x86 (3.84 KB, text/plain)
2020-07-02 15:12 UTC, Anssi Hannula

Note You need to log in before you can comment on or make changes to this bug.
Description Eric Reischer 2019-08-08 21:22:11 UTC
a9fc7bc seems to have injected an error that breaks calls to shmat() on amd64 Linux.  In this case I'm running a 32-bit executable.  Details:

Emulation of shmat() fails with errno=ENOSYS after the syscall in syswrap-generic.c:1974, as __NR_shmctl is 396.  Checking /usr/include/asm-generic/unistd.h on my RHEL6 system (2.6.32), __NR_shmctl is defined as 195, and (oddly) in /usr/include/asm/unistd_64.h it is {re}defined as 31.  unistd_32.h does not define __NR_shmctl.
Comment 1 Mark Wielaard 2019-08-09 09:15:09 UTC
Since you are checking on RHEL6 I assume you are using a fairly old kernel.

Otherwise this might be because in linux 5.0 the ipc () multiplexing syscall (as used on x86) was split into separate syscalls which aren't handled yet by valgrind:


arch: add split IPC system calls where needed
The IPC system call handling is highly inconsistent across architectures,
some use sys_ipc, some use separate calls, and some use both.  We also
have some architectures that require passing IPC_64 in the flags, and
others that set it implicitly.

For the addition of a y2038 safe semtimedop() system call, I chose to only
support the separate entry points, but that requires first supporting
the regular ones with their own syscall numbers.

The IPC_64 is now implied by the new semctl/shmctl/msgctl system
calls even on the architectures that require passing it with the ipc()

I'm not adding the new semtimedop() or semop() on 32-bit architectures,
those will get implemented using the new semtimedop_time64() version
that gets added along with the other time64 calls.
Three 64-bit architectures (powerpc, s390 and sparc) get semtimedop().

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Comment 2 Eric Reischer 2019-08-09 13:04:56 UTC
Correct -- 2.6.32.  However, RHEL7 still only uses 3.10.

Perhaps (at least on Linux) we should just be using the syscall macros defined in the system-level include folders rather than carrying them around with the valgrind source?  That would guarantee the binary would at least work on the distribution/release it was built on.
Comment 3 Julian Seward 2019-12-28 16:54:11 UTC
Mark, do we need to do anything about this?
Comment 4 Anssi Hannula 2020-07-02 15:12:06 UTC
Created attachment 129845 [details]
Patch: Fix shmat() on nanomips and x86

Patch attached to fix the issue. It affects all x86 and nanomips, host bitness does not matter.

There is a detailed explanation in the patch message, but the short version is that valgrind shmctl syscall variant selection was not correct.
Comment 5 Eric Reischer 2021-01-28 15:19:44 UTC
FYI that patch resolves the bug, but it looks like it hasn't made it into the mainline branch yet.
Comment 6 Mark Wielaard 2021-01-30 13:22:27 UTC
This looks similar to what is reported against Fedora arm64:
Comment 7 Mark Wielaard 2021-02-03 15:13:07 UTC
(In reply to Mark Wielaard from comment #6)
> This looks similar to what is reported against Fedora arm64:
> https://bugzilla.redhat.com/show_bug.cgi?id=1909548

It isn't exactly the same issue. But related.

The issue in that bug is that syswrap-linux.c calls generic_PRE_sys_shmctl and generic_POST_sys_shmctl with an extra VKI_IPC_64 only for amd64_linux, but not for arm64_linux. In both cases (and riscv, but we don't have a port for that) the VKI_IPC_64 is implied. The fix for that is simply:

diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c
index 328e02a98..52074149d 100644
--- a/coregrind/m_syswrap/syswrap-linux.c
+++ b/coregrind/m_syswrap/syswrap-linux.c
@@ -5127,7 +5127,7 @@ PRE(sys_shmctl)
    PRINT("sys_shmctl ( %ld, %ld, %#" FMT_REGWORD "x )", SARG1, SARG2, ARG3);
    PRE_REG_READ3(long, "shmctl",
                  int, shmid, int, cmd, struct shmid_ds *, buf);
-#ifdef VGP_amd64_linux
+#if defined(VGP_amd64_linux) || defined(VGP_arm64_linux)
    ML_(generic_PRE_sys_shmctl)(tid, ARG1,ARG2|VKI_IPC_64,ARG3);
    ML_(generic_PRE_sys_shmctl)(tid, ARG1,ARG2,ARG3);
@@ -5136,7 +5136,7 @@ PRE(sys_shmctl)
-#ifdef VGP_amd64_linux
+#if defined(VGP_amd64_linux) || defined(VGP_arm64_linux)
    ML_(generic_POST_sys_shmctl)(tid, RES,ARG1,ARG2|VKI_IPC_64,ARG3);
    ML_(generic_POST_sys_shmctl)(tid, RES,ARG1,ARG2,ARG3);

Then the generic PRE/POST do the right thing selecting the correct data structure size.
Comment 8 Mark Wielaard 2021-02-03 18:52:27 UTC
Tested on x86 (32bit) and arm64 (64bit) and pushed as two separate commits:

commit 889bffd9860337720a00cce888648b2262177ff2
Author: Anssi Hannula <anssi.hannula@bitwise.fi>
Date:   Thu Jul 2 14:49:17 2020 +0300

    Fix shmat() on Linux nanomips and x86
    On Linux, there are two variants of the direct shmctl syscall:
    - sys_shmctl: always uses shmid64_ds, does not accept IPC_64
    - sys_old_shmctl: uses shmid_ds or shmid64_ds depending on IPC_64
    The following Linux ABIs have the sys_old_shmctl variant:
      alpha, arm, microblaze, mips n32/n64, xtensa
    Other ABIs (and future ABIs) have the sys_shmctl variant, including ABIs
    that only got sys_shmctl in Linux 5.1 (such as x86, mips o32, ppc,
    We incorrectly assume the sys_old_shmctl variant on nanomips and x86,
    causing shmat() calls under valgrind to fail with EINVAL.
    On x86, the issue was previously masked by the non-existence of
    __NR_shmctl until a9fc7bceeb0b0 ("Update Linux x86 system call number
    definitions") in 2019.
    On mips o32, ppc, and s390x this issue is not visible as our headers do
    not have __NR_shmctl for those ABIs (396 since Linux 5.1).
    Fix the issue by correcting the preprocessor check in get_shm_size() to
    only assume the old Linux sys_old_shmctl behavior on the specific
    affected platforms.
    Also, exclude the use of direct shmctl entirely on Linux x86, ppc,
    mips o32, s390x in order to keep compatibility with pre-5.1 kernel
    versions that did not yet have direct shmctl for those ABIs.
    This currently only has actual effect on x86 as only it has __NR_shmctl
    in our headers.
    Fixes tests mremap4, mremap5, mremap6.

commit 7ada4d26d7cd3eb14904a398e6646f8b4e7d8a64
Author: Mark Wielaard <mark@klomp.org>
Date:   Wed Feb 3 16:56:14 2021 +0100

    syswrap-linux.c: Pass implicit VKI_IPC_64 for shmctl also on arm64.
    The shmctl syscall on amd64, arm64 and riscv (but we don't have a port
    for that last one) always use IPC_64. Explicitly pass it to the generic
    PRE/POST handlers so they select the correct (64bit) data structures on
    those architectures.
Comment 9 Mark Wielaard 2021-02-04 16:55:15 UTC
*** Bug 423929 has been marked as a duplicate of this bug. ***