5

I use the LD_PRELOAD trick to catch open64() calls and I think I know how to do it correctly: with the program foobar compiled from

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main() {
  open64("foobar.txt", 0);
  return 0;
}

I catch open64 as I expect:

>LD_PRELOAD=$PWD/catch.so ./foobar
open64 called

However, when open64 is replaced with fopen64:

#include <stdio.h>

int main() {
  fopen64("foobar.txt", "r");
  return 0;
}

now open64 is not caught. Why?

In case that fopen64 calls open, I do have both open and open64 intercepted, none is caught.

Both versions of the program foobar, when executed with strace, show that open is called, which means that fopen64 does call internally open or open64.

I thought that perhaps something is statically linked, but that seems not the case:

>ldd foobar

shows

libc.so.6 => /lib64/libc.so.6 

which is a shared library, and

>nm /lib64/libc.so.6

shows both open64 and fopen64 as defined (but not fopen, that's why in the question, I used the "64" versions for the purpose of argument; perhaps fopen is a macro to fopen64 or something like that, does not matter, since the problem happens with or without 64).

Mark Galeck
  • 6,155
  • 1
  • 28
  • 55
  • What differences between the two do _ltrace_ [sic] and/or LD_DEBUG=all show you? – pilcrow Mar 03 '16 at 17:24
  • @pilcrow not sure what you mean... I explained all of that above, `strace` shows `open(foobar.txt`... (and other irrelevant stuff), `LD_PRELOAD` shows nothing. – Mark Galeck Mar 03 '16 at 20:12
  • Having the same problem. Wondering what's going on. – JC1 Nov 04 '16 at 05:08

2 Answers2

9

I think it works like this: user space programs call library functions in libc, and libc calls system calls in the kernel. With LD_PRELOAD it is possible to intercept libc calls between the program and libc. You can not intercept system calls. If glibc calls another function internally (e.g. fopen calls open), you can not intercept it.

Instead of using strace, it is better to use ltrace in this case because that shows which library calls are done. These are the calls that you can intercept.

enter image description here

Sjoerd
  • 74,049
  • 16
  • 131
  • 175
  • OK, if I use `ltrace`, it just shows that my program is calling `fopen()` , that's all and I already know that. So it's not helpful at all... `fopen()` must be calling `open()` or some such, or perhaps `syscall()` but these are not shown in `ltrace`, why, I am not sure, but it does not seem helpful... – Mark Galeck Nov 10 '21 at 10:04
  • what do you mean by "if fopen calls open, you cannot intercept it"? If `fopen` is defined in `libc` then yes I should be able to intercept `fopen` if I use `LD_PRELOAD` to load `libc`. It does not matter what `fopen` is calling. Please comment. – Mark Galeck Nov 10 '21 at 10:13
  • "it" in "you cannot intercept it" refers to `open`, not `fopen`. If `fopen` calls `open`, you cannot intercept `open`. – Sjoerd Nov 10 '21 at 11:35
0

You want ptrace with PTRACE_SYSCALL. Here's an blog on it.

Matt Joiner
  • 112,946
  • 110
  • 377
  • 526
  • I read this blog post and I am not sure what you mean.... The blog describes how to use the function `ptrace()` to implement a simple version of command `strace`. I don't need that - I am perfectly fine with the full version of `strace`, I used it as I showed above and it is showing that the system call `open` is used. That is not what I want. I want to know what the user function is that is calling that system call, is it `open()` or `open64()` and if so, then why can't I catch it. – Mark Galeck Nov 10 '21 at 09:56