public inbox for libc-help@sourceware.org
 help / color / mirror / Atom feed
* Hooking execve for an LD_PRELOAD library
@ 2021-01-17  7:07 Andreas Fink
  2021-01-17  8:30 ` Florian Weimer
  0 siblings, 1 reply; 5+ messages in thread
From: Andreas Fink @ 2021-01-17  7:07 UTC (permalink / raw)
  To: libc-help

Hello,
I would like to hook a call to execve, and have the code:
############### execve_override.c ######################
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>

int (*real_execve)(const char *pathname, char *const argv[], char *const envp[])=NULL;
int execve(const char *pathname, char *const argv[], char *const envp[]) {
    if (real_execve==NULL) {
        real_execve = dlsym(RTLD_NEXT, "execve");
    }
    FILE* logfile = fopen("/tmp/execve_override.log", "a");
    fprintf(logfile, "intercepted execve for %s\n", pathname);
    fclose(logfile);
    return real_execve(pathname, argv, envp);
}
############################################################
I compiled it:
gcc -o libexecve_override.so -shared -fPIC execve_override.c -ldl

and start an executable that calls execve:
LD_PRELOAD=/path/to/libexecve_override.so my_binary_calling_execve

Up to this point everything works as expected. The call to execve is
hooked, logged in the file /tmp/execve_override.log and forwarded to
the next execve implementation.
I compiled my executable without any specific flags, i.e. a vanilla:
gcc test_exec.c

Now I would like the same for execvp to happen. Reading the man page of
execvp it is mentioned that exec-family functions are just
frontends to execve, so I replaced in my executable source code the
explicit call to execve with a call to execvp. I expected that this
would just work, as execvp would in turn call execve and this would be
caught by the hook, then logged and forwarded to the real
implementation. But to my surprise no such thing happened. execvp would
run successfully, but my hook would never be called.
Why is the hook not called, what did I miss?

Thanks for any help
Andreas

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Hooking execve for an LD_PRELOAD library
  2021-01-17  7:07 Hooking execve for an LD_PRELOAD library Andreas Fink
@ 2021-01-17  8:30 ` Florian Weimer
  2021-01-17 11:28   ` Andreas Fink
  0 siblings, 1 reply; 5+ messages in thread
From: Florian Weimer @ 2021-01-17  8:30 UTC (permalink / raw)
  To: Andreas Fink via Libc-help

* Andreas Fink via Libc-help:

> Now I would like the same for execvp to happen. Reading the man page of
> execvp it is mentioned that exec-family functions are just
> frontends to execve, so I replaced in my executable source code the
> explicit call to execve with a call to execvp. I expected that this
> would just work, as execvp would in turn call execve and this would be
> caught by the hook, then logged and forwarded to the real
> implementation. But to my surprise no such thing happened. execvp would
> run successfully, but my hook would never be called.
> Why is the hook not called, what did I miss?

Most internal function calls are implemented as direct function call,
and it is not possible to use symbol interposition to redirect them.
An exception is the malloc family of functions:

  Replacing malloc
  <http://www.gnu.org/software/libc/manual/html_node/Replacing-malloc.html>

If you want to modify the behavior of execve, you should consider a
kernel-based mechanism.  This will likely make it easier to achieve
correct behavior after vfork, too.

Thanks,
Florian
-- 
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Hooking execve for an LD_PRELOAD library
  2021-01-17  8:30 ` Florian Weimer
@ 2021-01-17 11:28   ` Andreas Fink
  2021-01-18 10:39     ` Florian Weimer
  0 siblings, 1 reply; 5+ messages in thread
From: Andreas Fink @ 2021-01-17 11:28 UTC (permalink / raw)
  To: libc-help

On Sun, 17 Jan 2021 09:30:10 +0100
Florian Weimer <fweimer@redhat.com> wrote:

> * Andreas Fink via Libc-help:
>
> > Now I would like the same for execvp to happen. Reading the man page of
> > execvp it is mentioned that exec-family functions are just
> > frontends to execve, so I replaced in my executable source code the
> > explicit call to execve with a call to execvp. I expected that this
> > would just work, as execvp would in turn call execve and this would be
> > caught by the hook, then logged and forwarded to the real
> > implementation. But to my surprise no such thing happened. execvp would
> > run successfully, but my hook would never be called.
> > Why is the hook not called, what did I miss?
>
> Most internal function calls are implemented as direct function call,
> and it is not possible to use symbol interposition to redirect them.
> An exception is the malloc family of functions:
>
>   Replacing malloc
>   <http://www.gnu.org/software/libc/manual/html_node/Replacing-malloc.html>
>
> If you want to modify the behavior of execve, you should consider a
> kernel-based mechanism.  This will likely make it easier to achieve
> correct behavior after vfork, too.
>
> Thanks,
> Florian


Ok, if I understood you correctly this is the expected behaviour. I was
afraid of it, but ok I can live with it.
Assuming I want to hook the whole exec-family, it seems easy to just
add hooks for the execv* functions while forwarding all arguments to
the corresponding glibc implementation. Forwarding the execl*
functions seems a bit more involved, as I would have to bend the
va_list to an array, or is there some way to forward the arguments to
the glibc function without unwrapping the va_list?

Kernel-based mechanism (in my case that's Linux) sounds also interesting
as it is one level lower I guess, but honestly speaking I have no idea
where to start to look at. Do you know of an example (not necesserily
execve, but any system call where this is done)? I guess glibc must do
this of course, but I could not directly find for example the real
implementation of execve. Only the stub one in posix/execve.c, but this
is certainly not the real implementation, as it returns always an error
;)

I think for my real use case I can get away with hooking all functions
on top of glibc, still interested to learn new things.

Best
Andreas

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Hooking execve for an LD_PRELOAD library
  2021-01-17 11:28   ` Andreas Fink
@ 2021-01-18 10:39     ` Florian Weimer
  2021-01-20 11:00       ` Andreas Fink
  0 siblings, 1 reply; 5+ messages in thread
From: Florian Weimer @ 2021-01-18 10:39 UTC (permalink / raw)
  To: Andreas Fink via Libc-help

* Andreas Fink via Libc-help:

> Ok, if I understood you correctly this is the expected behaviour. I was
> afraid of it, but ok I can live with it.
> Assuming I want to hook the whole exec-family, it seems easy to just
> add hooks for the execv* functions while forwarding all arguments to
> the corresponding glibc implementation.

You will also have to deal with system, popen, posix_spawn,
posix_spawnp.

> Forwarding the execl* functions seems a bit more involved, as I would
> have to bend the va_list to an array, or is there some way to forward
> the arguments to the glibc function without unwrapping the va_list?

I don't think this is possible in general.  GCC has __builtin_apply and
__builtin_apply_args, but I don't know if they work with variadic
functions on all architectures.

> Kernel-based mechanism (in my case that's Linux) sounds also interesting
> as it is one level lower I guess, but honestly speaking I have no idea
> where to start to look at. Do you know of an example (not necesserily
> execve, but any system call where this is done)?

You can find examples for ptrace system call interception and emulation
on the web.  Niels Provos' systrace also has a ptrace backend, which
could serve as a source of inspiration.

> I guess glibc must do this of course, but I could not directly find
> for example the real implementation of execve.

glibc doesn't do this, not even in its test suite.  (We probably should
use this for testing obscure kernel features, but as far as I know, we
currently don't.)

Thanks,
Florian
-- 
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Hooking execve for an LD_PRELOAD library
  2021-01-18 10:39     ` Florian Weimer
@ 2021-01-20 11:00       ` Andreas Fink
  0 siblings, 0 replies; 5+ messages in thread
From: Andreas Fink @ 2021-01-20 11:00 UTC (permalink / raw)
  To: libc-help

On Mon, 18 Jan 2021 11:39:49 +0100
Florian Weimer <fweimer@redhat.com> wrote:

> * Andreas Fink via Libc-help:
>
> > Ok, if I understood you correctly this is the expected behaviour. I was
> > afraid of it, but ok I can live with it.
> > Assuming I want to hook the whole exec-family, it seems easy to just
> > add hooks for the execv* functions while forwarding all arguments to
> > the corresponding glibc implementation.
>
> You will also have to deal with system, popen, posix_spawn,
> posix_spawnp.
Yes, definitely for posix_spawn and posix_spawnp (I did not know about
these two).
I figured out, that I can ignore system(cmd) and popen(cmd, type) at the
moment, as the actual stuff in cmd would come in later by execve because
/bin/sh inherits the environment with LD_PRELOAD and calls itself
execve for everything that is in cmd.
I.e. I "miss" the call to /bin/sh, but this is ok for my use-case.

>
> > Forwarding the execl* functions seems a bit more involved, as I would
> > have to bend the va_list to an array, or is there some way to forward
> > the arguments to the glibc function without unwrapping the va_list?
>
> I don't think this is possible in general.  GCC has __builtin_apply and
> __builtin_apply_args, but I don't know if they work with variadic
> functions on all architectures.
I think I will skip it, if it is non-standard, wrap it into arrays
and forward to execv-family.

>
> > Kernel-based mechanism (in my case that's Linux) sounds also interesting
> > as it is one level lower I guess, but honestly speaking I have no idea
> > where to start to look at. Do you know of an example (not necesserily
> > execve, but any system call where this is done)?
>
> You can find examples for ptrace system call interception and emulation
> on the web.  Niels Provos' systrace also has a ptrace backend, which
> could serve as a source of inspiration.
Thanks for the pointers, I had a quick look at them, but for now I
think I can get away with overriding all exec-family functions and
posix_spawn(p).

Your help is highly appreciated, and was very helpful to get to a
working solution.
Thank you
Andreas

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-01-20 11:00 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-17  7:07 Hooking execve for an LD_PRELOAD library Andreas Fink
2021-01-17  8:30 ` Florian Weimer
2021-01-17 11:28   ` Andreas Fink
2021-01-18 10:39     ` Florian Weimer
2021-01-20 11:00       ` Andreas Fink

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).