Sujet : Re: (interposers): How to workaround the "strong symbols" problem?
De : invalid (at) *nospam* invalid.invalid (Richard Kettlewell)
Groupes : comp.unix.programmerDate : 19. Jan 2025, 17:04:33
Autres entêtes
Organisation : terraraq NNTP server
Message-ID : <wwvsepessby.fsf@LkoBDZeT.terraraq.uk>
References : 1 2 3 4
User-Agent : Gnus/5.13 (Gnus v5.13) Emacs/28.2 (gnu/linux)
Marcel Mueller <
news.5.maazl@spamgourmet.org> writes:
Am 18.01.25 um 01:42 schrieb Kenny McCormack:
Right. It seems to boil down to:
You can't interpose a syscall.
I.e., so if a library function calls the syscall directly (rather
than going through the Glibc wrapper), you can't interpose it. This
is, of course, as it should be.
>
Hmm, it may be related to optimizations. Assuming the openat call is
inlined in another compilation unit there is no option to change this
at link time.
Inlining and compiler optimization aren’t relevant here.
“System call” can mean two things:
1) The actual transfer to the kernel, via an instruction such as SYSCALL
(x86) or SVC (Arm). This is what appears in strace.
2) The function in the C library that contains this instruction.
Normally the distinction is irrelevant, but here it matters.
“You can’t interpose a syscall”, is only true for sense 1. That
instruction is somewhere the middle of a function and the interposition
technique he’s using relies on runtime symbol resolution rules, so it
doesn’t apply to sense-1 syscalls.
It’s not true in sense 2. If you write an interposition library with the
symbol open(), and use LD_PRELOAD to insert it into a program that calls
open(), then the interposition will succeed. The output I quoted in my
previous posting shows this happening.
However there are several further issues.
Firstly, normally sense 1 and sense 2 amount to the same underlying
system call. The function openat() will call the openat system call. But
they don’t have to be, and indeed in the case at hand they’re not: in
Glibc the function open() will call the openat system call, not the open
system call:
https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/open.cThat’s why, if you strace a program that uses open(), you still see
openat() in the trace output. (Even in the absence of any further
obstacles) an attempt to use ELF interposition on openat would not work
in this case, but (again in the absence of further obstcales)
interposing open would do the job.
Secondly, if you follow the call chain from stdio functions like fopen
(or fopen64) then the point where it calls open is via the name
__open, not open. (Both names are aliases for __libc_open.) So,
interposing the name open won’t work (on this call); one would have to
interpose __open instead.
Thirdly, however, there is a final obstacle. __open is a hidden alias
for __libc_open. The effect of this is that calls to the name __open the
originate inside Glibc don’t participate in runtime symbol resolution so
cannot be interposed. See the discussion of PLT bypassing in:
https://sourceware.org/git/?p=glibc.git;a=blob;f=include/libc-symbols.hSo “you can’t interpose syscalls” is true in one sense, but not in the
sense that matters. The thing that got in Kenny’s way is the PLT bypass
logic.
-- https://www.greenend.org.uk/rjk/