vkats vkats - 5 months ago 40
Linux Question

gdb catch syscall condition and string comparisson

I would like to

catch
a system call (more specifically
access
) and set a
condition
on it based on string comparison (obviously for arguments that are strings).

Specific example: when debugging
ls
I would like to catch
access
syscalls for specific pathnames (the 1st argument)


int access(const char *pathname, int mode);


So far, I have succeeded in manually inspecting the pathname argument of
access
(see
[1]
).

I tried to use this blog post:

catch syscall access
condition 1 strcmp((char*)($rdi), "/etc/ld.so.preload") == 0


but failed (see
[2]
), as gdb informed me of a segfault and that
Evaluation of the expression containing the function (strcmp@plt) will be abandoned.
. However gdb suggested
set unwindonsignal on
.

Which I tried:

set unwindonsignal on
catch syscall access
condition 1 strcmp((char*)($rdi), "/etc/ld.so.preload") == 0


but failed again (see
[3]
) with a similar error and the suggestion
set unwindonsignal off
...

I searched for the
The program being debugged was signaled while in a function called from GDB.
error message, but (I think) I didn't find something relevant.

Any help or ideas?

[1]



$ gdb ls
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
...
Reading symbols from ls...(no debugging symbols found)...done.
(gdb) catch syscall access
Catchpoint 1 (syscall 'access' [21])
(gdb) r
Starting program: /bin/ls

Catchpoint 1 (call to syscall access), 0x00007ffff7df3537 in access () at ../sysdeps/unix/syscall-template.S:81
81 ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) x /s $rdi
0x7ffff7df6911: "/etc/ld.so.nohwcap"
(gdb) c
Continuing.

Catchpoint 1 (returned from syscall access), 0x00007ffff7df3537 in access () at ../sysdeps/unix/syscall-template.S:81
81 in ../sysdeps/unix/syscall-template.S
(gdb) x /s $rdi
0x7ffff7df6911: "/etc/ld.so.nohwcap"
(gdb) c
Continuing.

Catchpoint 1 (call to syscall access), 0x00007ffff7df3537 in access () at ../sysdeps/unix/syscall-template.S:81
81 in ../sysdeps/unix/syscall-template.S
(gdb) x /s $rdi
0x7ffff7df9420 <preload_file.9747>: "/etc/ld.so.preload"


[2]



$ gdb ls
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
...
Reading symbols from ls...(no debugging symbols found)...done.
(gdb) catch syscall access
Catchpoint 1 (syscall 'access' [21])
(gdb) condition 1 strcmp((char*)($rdi), "/etc/ld.so.preload") == 0
(gdb) info breakpoints
Num Type Disp Enb Address What
1 catchpoint keep y syscall "access"
stop only if strcmp((char*)($rdi), "/etc/ld.so.preload") == 0
(gdb) r
Starting program: /bin/ls

Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
Error in testing breakpoint condition:
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on".
Evaluation of the expression containing the function
(strcmp@plt) will be abandoned.
When the function is done executing, GDB will silently stop.

Catchpoint 1 (returned from syscall munmap), 0x0000000000000000 in ?? ()


[3]



$ gdb ls
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
...
Reading symbols from ls...(no debugging symbols found)...done.
(gdb) set unwindonsignal on
(gdb) catch syscall access
Catchpoint 1 (syscall 'access' [21])
(gdb) condition 1 strcmp((char*)($rdi), "/etc/ld.so.preload") == 0
(gdb) r
Starting program: /bin/ls

Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
Error in testing breakpoint condition:
The program being debugged was signaled while in a function called from GDB.
GDB has restored the context to what it was before the call.
To change this behavior use "set unwindonsignal off".
Evaluation of the expression containing the function
(strcmp@plt) will be abandoned.

Catchpoint 1 (returned from syscall munmap), 0x00007ffff7df3537 in access () at ../sysdeps/unix/syscall-template.S:81
81 ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) x /s $rdi
0x7ffff7df6911: "/etc/ld.so.nohwcap"

Answer

You can use the gdb internal function $_streq like this:

(gdb) catch syscall access
Catchpoint 1 (syscall 'access' [21])
(gdb) condition 1 $_streq((char *)$rdi, "/etc/ld.so.preload")
(gdb) ru
Starting program: /bin/ls 

Catchpoint 1 (call to syscall access), 0x00007ffff7df3537 in access ()
    at ../sysdeps/unix/syscall-template.S:81
81      ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) p (char *)$rdi
$1 = 0x7ffff7df9420 <preload_file> "/etc/ld.so.preload"
Comments