Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
  • GHC GHC
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 5,357
    • Issues 5,357
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 565
    • Merge requests 565
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Releases
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell CompilerGlasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #20051
Closed
Open
Issue created Jun 27, 2021 by Sergei Trofimovich@trofiReporter

GHC's `allocateExec()` fails on libffi-3.4, corrupts memory.

Summary

GHC's allocateExec() fails on libffi-3.4, corrupts memory.

The problem is observed on ghc built against libffi-3.4-rc1:

$ ghci
GHCi, version 8.10.5: https://www.haskell.org/ghc/  :? for help
ghc: freeHaskellFunctionPtr: not for me, guv! 0x7f0417a1efe8
ghc: freeHaskellFunctionPtr: not for me, guv! 0x7f0417a1efc8

Here ghc tells us that freeHaskellFunctionPtr sees corrupted code memory where trampoline should be stored.

Details

That happens because ghc has very strong assumptions about libffi's void * ret = ffi_closure_alloc (size_t size, void **code) semantics:

  1. code has at least size bytes of executable memory
  2. ret data is not used by libffi
#if defined(linux_HOST_OS) || defined(netbsd_HOST_OS)

// On Linux we need to use libffi for allocating executable memory,
// because it knows how to work around the restrictions put in place
// by SELinux. The same goes for NetBSD where it is prohibited to
// mark a page mapping both writable and executable at the same time.

AdjustorWritable allocateExec (W_ bytes, AdjustorExecutable *exec_ret)
{
    void **ret, **exec;
    ACQUIRE_SM_LOCK;
    ret = ffi_closure_alloc (sizeof(void *) + (size_t)bytes, (void**)&exec);
    RELEASE_SM_LOCK;
    if (ret == NULL) return ret;
/// breaks [1.] assumption: writes into libffi's space:
    *ret = ret; // save the address of the writable mapping, for freeExec().
    *exec_ret = exec + 1;
/// breaks [2.] assumption:
    return (ret + 1);
}

Starting from https://github.com/libffi/libffi/commit/9ba559217bea0803263a9a9a0bafcf9203606f5b libffi-3.4 neither of [1.] or [2.] is true:

  1. code now is a small trampoline of very specific form, user can't write arbitrary instructions there.
  2. ret now keeps a pointer to the trampoline used later by ffi_closure_free().

I think ghc needs to implement it's own form of allocateExec() and should stop relying on libffi's internals to provide executable scratch space.

workaround

As a workaround https://github.com/libffi/libffi/pull/647 adds --disable-exec-static-tramp build-time libffi flag to allow ghc to limp along for a while.

Environment

  • GHC version used: 8.10.5 and HEAD, both have a problem.

Optional:

  • Operating System: linux
  • System Architecture: x86_64
Edited Jun 27, 2021 by Sergei Trofimovich
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking