Bug 23240 - LD_PRELOAD doesn't work with non-lazy binding and IFUNC
Summary: LD_PRELOAD doesn't work with non-lazy binding and IFUNC
Status: NEW
Alias: None
Product: glibc
Classification: Unclassified
Component: dynamic-link (show other bugs)
Version: 2.28
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-05-25 21:58 UTC by H.J. Lu
Modified: 2018-06-06 15:36 UTC (History)
1 user (show)

See Also:
Host:
Target: x86_64-*-*, i?86-*-*
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description H.J. Lu 2018-05-25 21:58:14 UTC
[hjl@gnu-cfl-1 ifunc-2]$ cat main.c 
extern void bar (char *, const char *, unsigned int);

int
main ()
{
  char dst[50];
  const char src[] =
    {
      "This is a test"
    };
  bar (dst, src, sizeof (src));
  if (__builtin_memcmp (dst, src, sizeof (src)) != 0)
    __builtin_abort ();
  return 0;
}
[hjl@gnu-cfl-1 ifunc-2]$ cat foo.c 
extern void bar (char *dst, const char *src, unsigned int);

void
foo (char *dst, const char *src, unsigned int size)
{
  bar (dst, src, size);
}
[hjl@gnu-cfl-1 ifunc-2]$ cat memmove.c 
#include <stddef.h>

void *
my_memmove(void *dst_p, const void *src_p, size_t n)
{
  const char *src = src_p;
  char *dst = dst_p;
  char *ret = dst;
  if (src < dst)
    {
      dst += n;
      src += n;
      while (n--)
	*--dst = *--src;
    }
  else
    while (n--)
      *dst++ = *src++;
  return ret;
}

void *memmove (void *, const void *, size_t)
  __attribute__ ((ifunc ("resolve_memmove")));

typedef void *(*memmove_t) (void *, const void *, size_t);

static memmove_t
resolve_memmove (void)
{
  return my_memmove;
}
[hjl@gnu-cfl-1 ifunc-2]$ make
gcc -O2 -g   -c -o main.o main.c
gcc -O2 -g -fPIC   -c -o bar.o bar.c
gcc -shared  -o libbar.so bar.o
gcc  -o x main.o libbar.so -Wl,-R,.
gcc -O2 -g -fPIC   -c -o memmove.o memmove.c
gcc -shared  -o libmemmove.so memmove.o
./x
LD_PRELOAD=./libmemmove.so ./x
LD_PRELOAD=./libmemmove.so LD_BIND_NOW=1 ./x
./x: Relink `./libbar.so' with `./libmemmove.so' for IFUNC symbol `memmove'
make: *** [Makefile:29: all] Segmentation fault
[hjl@gnu-cfl-1 ifunc-2]$
Comment 1 Florian Weimer 2018-05-25 22:03:11 UTC
This is the well-known issue caused by the interaction of IFUNC resolvers and symbol interposition.
Comment 2 H.J. Lu 2018-05-25 22:04:32 UTC
Add missing bar.c:

[hjl@gnu-cfl-1 ifunc-2]$ cat bar.c
void
bar (char *dst, const char *src, unsigned int size)
{
  __builtin_memmove (dst, src, size);
}
[hjl@gnu-cfl-1 ifunc-2]$
Comment 3 H.J. Lu 2018-05-25 22:06:16 UTC
(In reply to Florian Weimer from comment #1)
> This is the well-known issue caused by the interaction of IFUNC resolvers
> and symbol interposition.

My DT_FLAGS_2 and DF_2_GNU_IFUNC proposal:

https://sourceware.org/ml/binutils/2018-05/msg00264.html

tries to address this.
Comment 4 Florian Weimer 2018-05-25 22:07:14 UTC
Previous patch (which needs more development work):

https://sourceware.org/ml/libc-alpha/2017-01/msg00468.html

A single flag cannot solve this issue.
Comment 5 Florian Weimer 2018-06-05 19:21:38 UTC
With my IFUNC scheduler, I get this for your test case:

     32147:     applying delayed relocations for /tmp/libbar.so
     32147:     delayed relocation of symbol memmove in /tmp/libmemmove.so
     32147:     1 delayed relocations performed for /tmp/libbar.so

I need to clean up a few things and will likely post patches tomorrow.
Comment 6 cvs-commit@gcc.gnu.org 2018-06-06 15:36:33 UTC
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, hjl/pr23240/fw has been created
        at  3bc6d308ef8ba549e0ef072692903ea2afa883d1 (commit)

- Log -----------------------------------------------------------------
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=3bc6d308ef8ba549e0ef072692903ea2afa883d1

commit 3bc6d308ef8ba549e0ef072692903ea2afa883d1
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Sun May 27 07:15:35 2018 -0700

    Check non-lazy binding with LD_PRELOAD and weak reference
    
    Check non-lazy binding with
    
    1. Reference to unrelocated IFUNC function with LD_PRELOAD.
    2. Weak reference.
    
    	[BZ #23176]
    	[BZ #23240]
    	* elf/Makefile (tests): Add reldep6a.
    	(tests-internal): Add ifuncpreload1
    	(modules-names): Add ifuncpreloadmod1a and ifuncpreloadmod1b.
    	($(objpfx)reldep6a): New.
    	($(objpfx)reldep6a.out): Likewise.
    	(reldep6a-ENV): Likewise.
    	($(objpfx)ifuncpreload1): Likewise.
    	($(objpfx)ifuncpreload1.out): Likewise.
    	(ifuncpreload1-ENV): Likewise.
    	* elf/ifuncpreload1.c: New file.
    	* elf/ifuncpreloadmod1a.c: Likewise.
    	* elf/ifuncpreloadmod1b.c: Likewise.
    	* elf/reldep6a.c: Likewise.

-----------------------------------------------------------------------