Basic analysis of segmentation fault on Linux platforms
I was adding a few lines of new code to pkcs11-logger library on Windows last week and when I was happy with the result I wanted to test the code on Linux.
It built nicely but when I tried to use the resulting library with pkcs11-tool
I got segmentation fault.
jariq@ubuntu:~$ pkcs11-tool --module pkcs11-logger-x64.so -I
*** Error in `pkcs11-tool': munmap_chunk(): invalid pointer: 0x00007ffdd7830b6b ***
Aborted (core dumped)
Segfault indicates memory access violation and the displayed error will almost never reveal which library and/or function should be blamed for it. Luckily linux kernel has the ability to dump the memory of faulting process into a core file.
Core file gets generated automatically when segfault occurs and its size does not overflow corresponding ulimit.
Maximum allowed size of core file can be displayed with ulimit -c
command and the limit can be completely removed with ulimit -c unlimited
command.
jariq@ubuntu:~$ ulimit -c
0
jariq@ubuntu:~$ ulimit -c unlimited
jariq@ubuntu:~$ ulimit -c
unlimited
Failing program needs to be executed once again after the size limit has been removed. Right after the segfault there will be core file generated in a current directory.
jariq@ubuntu:~$ pkcs11-tool --module pkcs11-logger-x64.so -I
*** Error in `pkcs11-tool': munmap_chunk(): invalid pointer: 0x00007ffc6808db6b ***
Aborted (core dumped)
jariq@ubuntu:~$ ls –la | grep core
-rw------- 1 jariq jariq 729088 nov 21 07:50 core
Saved core file can be opened for example with GNU Debugger:
jariq@ubuntu:~$ gdb pkcs11-tool core
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from pkcs11-tool...(no debugging symbols found)...done.
[New LWP 2925]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `pkcs11-tool --module pkcs11-logger-x64.so -I'.
Program terminated with signal SIGABRT, Aborted.
#0 0x00007fe9e8250cc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56 ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb)
Backtrace of all stack frames can be printed with where
command issued in gdb shell:
(gdb) where
#0 0x00007fe9e8250cc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1 0x00007fe9e82540d8 in __GI_abort () at abort.c:89
#2 0x00007fe9e828d394 in __libc_message (do_abort=do_abort@entry=1, fmt=fmt@entry=0x7fe9e839bb28 "*** Error in `%s': %s: 0x%s ***\n") at ../sysdeps/posix/libc_fatal.c:175
#3 0x00007fe9e82980f7 in malloc_printerr (action=<optimized out>, str=0x7fe9e839bea8 "munmap_chunk(): invalid pointer", ptr=<optimized out>) at malloc.c:4996
#4 0x00007fe9e7df236c in pkcs11_logger_init_read_env_var (env_var_name=env_var_name@entry=0x7fe9e7dfa349 "PKCS11_LOGGER_LIBRARY_PATH") at ../../src/init.c:237
#5 0x00007fe9e7df23b1 in pkcs11_logger_init_parse_env_vars () at ../../src/init.c:132
#6 0x00007fe9e7df2565 in pkcs11_logger_init_orig_lib () at ../../src/init.c:75
#7 0x00007fe9e7df3529 in C_GetFunctionList (ppFunctionList=0x618f18) at ../../src/pkcs11-logger.c:191
#8 0x000000000040efc1 in ?? ()
#9 0x0000000000402ef0 in ?? ()
#10 0x00007fe9e823bec5 in __libc_start_main (main=0x402d80, argc=4, argv=0x7ffc6808c5c8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7ffc6808c5b8) at libc-start.c:287
#11 0x0000000000406072 in ?? ()
Displayed backtrace clearly identified line 237 of init.c file as a source of the failure.
I have examined the code and I found out that I was trying to free statically allocated memory returned by getenv()
function. OMG :)