0

I am trying to use -Wl, -wrap=sendto -Wl, -wrap, sendto in my final g++ link command that links my app to replace the standard sendto function with my own.

I compile the following source code with:

gcc -c -o wrap.o wrap.c

and include the wrap.o in the final g++ command that links the app (the rest of the app is C++ hence the use of g++):

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>

ssize_t __real_sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t);

ssize_t __wrap_sendto
(
    int sockfd,
    const void *buf,
    size_t len,
    int flags,
    const struct sockaddr *dest_addr,
    socklen_t addrlen
)
{
    printf("my wrap sendto ...\n");
    return __real_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
}

When I use sendto in my own source code, the wrapper is in fact used ok but all 3rd party shared objects i linked against in my final g++ command that use sendto still use the system sendto i.e. not my wrapper. How can I get my sendto wrapper used throughout?

I have also tried an LD_PRELOAD approach with a sendto and dlsym(RTLD_NEXT) inside but that did not work either.

How can I figure out why the 3rd party library keeps on using the libc sendto directly?

When I use ldd to find all shared object dependencies of my compiled app and then objdump -T on each one of them grepping for sendto, I get UND (undefined) for all the 3rd party shared objects. The shared objects that do define it however is:

/lib64/libpthread.so.0
000000000000ed80  w   DF .text  0000000000000064  GLIBC_2.2.5 sendto
/lib64/libc.so.6
00000000000e98d0  w   DF .text  0000000000000064  GLIBC_2.2.5 sendto

I see in glibc sendto.c on git the following:

weak_alias (__libc_sendto, sendto)
weak_alias (__libc_sendto, __sendto)
double-beep
  • 5,031
  • 17
  • 33
  • 41
Waslap
  • 572
  • 3
  • 23

2 Answers2

0

The --wrap sendto option does not define the sendto symbol in your binary. Instead, it replaces references to this symbols with __wrap_sendto and leaves sendto undefined.

In other words, your executable does not provide sendto, so the run-time symbol resolution picks the one from glibc.

To fix this you need to define sendto in your executable. Try dlsym once again, but this time without LD_PRELOAD/shim library:

ssize_t sendto
(
    int sockfd,
    const void *buf,
    size_t len,
    int flags,
    const struct sockaddr *dest_addr,
    socklen_t addrlen
)
{
    ssize_t (*libc_sendto)(int, const void *, size_t, int, const struct sockaddr *, socklen_t)
        = dlsym(RTLD_NEXT, "sendto");
    printf("my wrap sendto ...\n");
    return libc_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
}

If third-party libraries keep finding wrong sendto after this, then I see only one (not particularly likely) possibility. Shared libraries are linked with -Bsymbolic/-Bsymbolic-functions and provide their own sendto.

Also, since you've tagged this question as g++, make sure that your symbol names don't get mangled - use extern "C".

Nikita Kakuev
  • 1,096
  • 9
  • 13
  • Symbol names not mangled (compiled as c using gcc and extern "C" using g++ no difference). Tried your suggestion without LD_PRELOAD but still no difference, I see 'my wrap sendto' only when called from my own code, not linked 3rd party .so . I am sure they are calling sendto as I can see it from an strace output. They definitely don't provide own sendto as I've confirmed with objdump -T and all shows UND. – Waslap Jul 13 '16 at 07:51
0

I have eventually managed to figure out what was going on here. Even though the strace states sendto is being called:

[pid 17956] sendto(4, "abc"..., 2052, 0, NULL, 0) = 2052  

what was in fact happening was send(...) was being called (probably possible because 0, null, 0 last three parameters). The moment I made an interceptor for send(...) it worked.

Waslap
  • 572
  • 3
  • 23