OpenSC / pkcs11-helper

Library that simplifies the interaction with PKCS#11 providers for end-user applications using a simple API and optional OpenSSL engine
Other
65 stars 43 forks source link

core: bypass atfork when within C_Initialize or hook #18

Closed alonbl closed 2 years ago

alonbl commented 5 years ago

OpenSC provide performs fork() when C_Initialize, and hooks make fork for a utility.

This attempts to perform unsafe fork and then terminate library to minimize affects on child processes.

loskutov commented 5 years ago

After applying this PR, I experience the following:

frame #0:  0x00007ffff76570bc libc.so.6`__lll_lock_wait_private at lowlevellock.S:63
frame #1:  0x00007ffff76573fb libc.so.6`__unregister_atfork(dso_handle=<unavailable>) at register-atfork.c:80
frame #2:  0x00007ffff7572b3b libc.so.6`__cxa_finalize(d=0x00007ffff506c000) at cxa_finalize.c:107
frame #3:  0x00007ffff4e63963 libpcsclite.so.1`__do_global_dtors_aux + 35
frame #4:  0x00007ffff7fe8995 ld-linux-x86-64.so.2`_dl_close_worker(map=<unavailable>, force=<unavailable>) at dl-close.c:288
frame #5:  0x00007ffff7fe9541 ld-linux-x86-64.so.2`_dl_close at dl-close.c:122
frame #6:  0x00007ffff7fe9504 ld-linux-x86-64.so.2`_dl_close(_map=0x00005555556a5f40) at dl-close.c:842
frame #7:  0x00007ffff768a48f libc.so.6`__GI__dl_catch_exception(exception=<unavailable>, operate=<unavailable>, args=<unavailable>) at dl-error-skeleton.c:196
frame #8:  0x00007ffff768a51f libc.so.6`__GI__dl_catch_error(objname=0x0000555555676a30, errstring=0x0000555555676a38, mallocedp=0x0000555555676a28, operate=<unavailable>, args=<unavailable>) at dl-error-skeleton.c:215
frame #9:  0x00007ffff7719a25 libdl.so.2`_dlerror_run(operate=(libdl.so.2`dlclose_doit at dlclose.c:35), args=0x00005555556a5f40) at dlerror.c:163
frame #10: 0x00007ffff7719364 libdl.so.2`__dlclose(handle=<unavailable>) at dlclose.c:46
frame #11: 0x00007ffff6d06f96 libopensc.so.6`sc_dlclose(handle=0x00005555556a5f40) at libscdl.c:67
frame #12: 0x00007ffff6b7fd32 libopensc.so.6`pcsc_finish(ctx=0x00005555556a55e0) at reader-pcsc.c:903
frame #13: 0x00007ffff6b38563 libopensc.so.6`sc_release_context(ctx=0x00005555556a55e0) at ctx.c:910
frame #14: 0x00007ffff6d8c25c opensc-pkcs11.so`C_Finalize(pReserved=0x0000000000000000) at pkcs11-global.c:335
frame #15: 0x00007ffff6d8be69 opensc-pkcs11.so`C_Initialize(pInitArgs=0x0000000000000000) at pkcs11-global.c:230
frame #16: 0x00007ffff7b13824 libpkcs11-helper.so.1`__pkcs11h_threading_atfork_child at pkcs11h-core.c:1335
frame #17: 0x00007ffff7b137c0 libpkcs11-helper.so.1`__pkcs11h_threading_atfork_child at pkcs11h-core.c:1288
frame #18: 0x00007ffff7657629 libc.so.6`__run_fork_handlers(who=<unavailable>) at register-atfork.c:132
frame #19: 0x00007ffff760c7e7 libc.so.6`__libc_fork at fork.c:137
frame #20: 0x000055555558df0d openvpn`openvpn_execve(a=0x00007fffffffd2a0, es=0x00007fffe800a440, flags=2) at misc.c:207
frame #21: 0x000055555558dd70 openvpn`openvpn_execve_check(a=0x00007fffffffd2a0, es=0x00007fffe800a440, flags=2, error_message="Linux ip link set failed") at misc.c:150
frame #22: 0x00005555555f96b0 openvpn`do_ifconfig(tt=0x0000555555720690, actual="tun5", tun_mtu=1500, es=0x00007fffe800a440) at tun.c:947
frame #23: 0x000055555557d244 openvpn`do_open_tun(c=0x00007fffffffd4a0) at init.c:1762
frame #24: 0x000055555557dc26 openvpn`do_up(c=0x00007fffffffd4a0, pulled_options=true, option_types_found=277876878) at init.c:2057
frame #25: 0x00005555555d09e6 openvpn`incoming_push_message(c=0x00007fffffffd4a0, buffer=0x00007fffffffd3f0) at push.c:265
frame #26: 0x0000555555573382 openvpn`check_incoming_control_channel_dowork(c=0x00007fffffffd4a0) at forward.c:164
frame #27: 0x0000555555572879 openvpn`check_incoming_control_channel(c=0x00007fffffffd4a0) at forward-inline.h:91
frame #28: 0x0000555555575ff8 openvpn`pre_select(c=0x00007fffffffd4a0) at forward.c:1594
frame #29: 0x00005555555a4863 openvpn`tunnel_point_to_point(c=0x00007fffffffd4a0) at openvpn.c:103
frame #30: 0x00005555555a4c62 openvpn`openvpn_main(argc=2, argv=0x00007fffffffe488) at openvpn.c:305
frame #31: 0x00005555555a4d8d openvpn`main(argc=2, argv=0x00007fffffffe488) at openvpn.c:388
frame #32: 0x00007ffff755209b libc.so.6`__libc_start_main(main=(openvpn`main at openvpn.c:387), argc=2, argv=0x00007fffffffe488, init=<unavailable>, fini=<unavailable>, rtld_fini=<unavailable>, stack_end=0x00007fffffffe478) at libc-start.c:308
frame #33: 0x000055555555f8ca openvpn`_start + 42

It looks like the handler is applied to a fork which is not in any way related to PKCS#11.

alonbl commented 5 years ago

It looks like the handler is applied to a fork which is not in any way related to PKCS#11.

sure, every fork should go via this C_Initialize/C_Finalize to drop PKCS#11 on child to avoid exposing handles which may used to access secure resources.

it seems like pcsc-lite locks itself in some way @frankmorgner can you please look? Maybe unrelated, as I cannot figure out why C_Initalize calls C_Finalize in this case, and what waits.

eventually, I will try to install openvpn, I use softhsm to test these as I do not have a current device for opensc.

frankmorgner commented 5 years ago

As mentioned before, using pthread_atfork has other problems. That's why PCSC-Lite removed its use of it, see https://github.com/LudovicRousseau/PCSC/commit/b4d935a73e84b899dbf63bc97bca0c50c9b84f5b. Please check if your PCSC-Lite is affected.

frankmorgner commented 5 years ago

@loskutov did you find the time to check?

loskutov commented 5 years ago

Oops, I think I missed that. I have a recent version of libpcsclite (namely 1.8.23) which has the change you mentioned if that's what you mean.

frankmorgner commented 5 years ago

Please note, again, that I don't think it's possible to unregister an atfork-handler, which means that pkcs11-helper's atfork handler may be called when pkcs11-helper and OpenSC are not loaded. So forking after unloading pkcs11-helper will result in undefined behavior.

In the log above, however, I don't immediately spot the problem. Maybe @LudovicRousseau has an idea about this.

LudovicRousseau commented 5 years ago

I don't know what destructor code of pcsc-lite is called when libpcsclite.so.1 is unloaded. Maybe rebuilding pcsc-lite in debug mode could provide more information in the backtrace.