{"action":"created","issue":{"url":"https://api.github.com/repos/OpenSC/OpenSC/issues/192","labels_url":"https://api.github.com/repos/OpenSC/OpenSC/issues/192/labels{/name}","comments_url":"https://api.github.com/repos/OpenSC/OpenSC/issues/192/comments","events_url":"https://api.github.com/repos/OpenSC/OpenSC/issues/192/events","html_url":"https://github.com/OpenSC/OpenSC/issues/192","id":21116085,"number":192,"title":"SIGSEV when re-loading opensc-pkcs11.so ","user":{"login":"commonism","id":164513,"avatar_url":"https://avatars.githubusercontent.com/u/164513?v=3","gravatar_id":"","url":"https://api.github.com/users/commonism","html_url":"https://github.com/commonism","followers_url":"https://api.github.com/users/commonism/followers","following_url":"https://api.github.com/users/commonism/following{/other_user}","gists_url":"https://api.github.com/users/commonism/gists{/gist_id}","starred_url":"https://api.github.com/users/commonism/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/commonism/subscriptions","organizations_url":"https://api.github.com/users/commonism/orgs","repos_url":"https://api.github.com/users/commonism/repos","events_url":"https://api.github.com/users/commonism/events{/privacy}","received_events_url":"https://api.github.com/users/commonism/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":4,"created_at":"2013-10-16T22:38:22Z","updated_at":"2015-07-28T06:30:38Z","closed_at":"2015-07-28T06:30:38Z","body":"The following code can be used to reproduce\r\n```c\r\n#include <stdio.h>\r\n#include <openssl/rsa.h>\r\n#include <openssl/evp.h>\r\n#include <openssl/objects.h>\r\n#include <openssl/x509.h>\r\n#include <openssl/err.h>\r\n#include <openssl/pem.h>\r\n#include <openssl/ssl.h>\r\n#include <openssl/engine.h>\r\n#include <openssl/conf.h>\r\n\r\n#define KEY_ID \"slot_X-id_Y\"\r\n#define PIN \"0000\"\r\n\r\nENGINE *ENGINE_pkcs11(void)\r\n{\r\n\tstruct command\r\n\t{\r\n\t\tchar *cmd;\r\n\t\tchar *arg;\r\n\t} commands[] =\r\n\t{\r\n\t\t{\"SO_PATH\", \"/opt/opensc/lib/engines/engine_pkcs11.so\"},\r\n\t\t{\"ID\",\"pkcs11\"},\r\n//\t\t{\"LIST_ADD\",\"1\"},\r\n\t\t{\"LOAD\", NULL},\r\n\t\t{\"MODULE_PATH\",\"/opt/opensc/lib/opensc-pkcs11.so\"},\r\n\t\t{\"PIN\", PIN},\r\n\t\t{\"VERBOSE\", NULL}\r\n\t};\r\n\r\n\tENGINE_load_dynamic();\r\n\tENGINE *e = ENGINE_by_id(\"dynamic\");\r\n\tif( e == NULL )\r\n\t{\r\n\t\tperror(\"ENGINE_by_id\");\r\n\t\tERR_print_errors_fp(stderr);\r\n\t\texit(1);\r\n\t}\r\n\r\n\tfor (int i = 0; i < sizeof(commands) / sizeof(commands[0]); i++)\r\n\t{\r\n\t\tstruct command *cmd = &commands[i];\r\n\t\tif( ENGINE_ctrl_cmd_string(e, cmd->cmd, cmd->arg, 0) != 1 )\r\n\t\t{\r\n\t\t\tprintf(\"ENGINE_ctrl_cmd_string %s %s \\n\", cmd->cmd, cmd->arg);\r\n\t\t\tERR_print_errors_fp(stderr);\r\n\t\t\texit(1);\r\n\t\t}\r\n\t}\r\n\treturn e;\r\n}\r\n\r\nint main() {\r\n\r\n\tERR_load_crypto_strings();\r\n\tENGINE_load_dynamic();\r\n\r\n\tENGINE *e = ENGINE_pkcs11();\r\n\r\n\tfor (int i=0; i<2; i++)\r\n\t{\r\n\t\tENGINE_init(e);\r\n\t\t/* Read private key */\r\n\t\tEVP_PKEY *pkey = ENGINE_load_private_key(e, KEY_ID, NULL, NULL);\r\n\t\tif (pkey == NULL) {\r\n\t\t\tperror(\"ENGINE_load_private_key\");\r\n\t\t\tERR_print_errors_fp(stderr);\r\n\t\t\texit(1);\r\n\t\t}\r\n\t\tEVP_PKEY_free(pkey);\r\n\t\tENGINE_finish(e);\r\n\t}\r\n\r\n\tENGINE_free(e);\r\n\r\n#define CRASH_NOW 1\r\n#ifdef CRASH_NOW\r\n\tSSL_CTX *ctx = NULL;\r\n\tctx = SSL_CTX_new(TLSv1_2_method());\r\n\tSSL_CTX_free(ctx);\r\n#endif\r\n\r\n\t/* OpenSSL cleanup */\r\n\tERR_free_strings();\r\n\tERR_remove_state(0);\r\n\tCOMP_zlib_cleanup();\r\n\tCONF_modules_unload(1);\r\n\tOBJ_cleanup();\r\n\tOBJ_NAME_cleanup(-1);\r\n\tBIO_sock_cleanup();\r\n\tEVP_cleanup();\r\n\r\n\t/* if not CRASH_NOW - we will crash here */\r\n\tENGINE_cleanup();\r\n\r\n\tCRYPTO_cleanup_all_ex_data();\r\n\tERR_free_strings();\r\n\tASN1_STRING_TABLE_cleanup();\r\n\tCRYPTO_set_locking_callback(NULL);\r\n\tRAND_cleanup();\r\n\t// The SSL compression method stack doesn't get freed properly by any of the functions above.\r\n\t// This was necessary as of 1.0.0-beta3, but may be fixed.\r\n\tsk_pop_free((_STACK *)SSL_COMP_get_compression_methods(), free);\r\n\r\n\treturn (0);\r\n}\r\n```\r\nSet your keyid and pin, compile with\r\n```\r\ngcc -O0 -g -std=c99 -Wall -Werror gost.c -o gost -lcrypto -lssl\r\n```\r\nrun and it'll crash, maybe not directly but you can see the memory corruption with valgrind\r\n\r\nIf CRASH_NOW is set, valgrind will provide a trace similar to\r\n```\r\n==30882== Invalid read of size 8\r\n==30882==    at 0x4F0EF53: look_str_cb (tb_asnmth.c:216)\r\n==30882==    by 0x4F1BDDE: lh_doall_arg (lhash.c:292)\r\n==30882==    by 0x4F0D71B: engine_table_doall (eng_table.c:349)\r\n==30882==    by 0x4F0F312: ENGINE_pkey_asn1_find_str (tb_asnmth.c:236)\r\n==30882==    by 0x4F417C4: EVP_PKEY_asn1_find_str (ameth_lib.c:213)\r\n==30882==    by 0x524A2E3: get_optional_pkey_id (ssl_ciph.c:356)\r\n==30882==    by 0x524B41E: ssl_create_cipher_list (ssl_ciph.c:733)\r\n==30882==    by 0x5244D2F: SSL_CTX_new (ssl_lib.c:1762)\r\n==30882==    by 0x4011EC: main (gost.c:79)\r\n==30882==  Address 0x5cbd980 is 96 bytes inside a block of size 216 free'd\r\n==30882==    at 0x4C2A82E: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)\r\n==30882==    by 0x4E933EC: CRYPTO_free (mem.c:397)\r\n==30882==    by 0x4F0BB67: engine_free_util (eng_lib.c:136)\r\n==30882==    by 0x4F0C79B: engine_unlocked_finish (eng_init.c:112)\r\n==30882==    by 0x4F0D3C1: engine_table_register (eng_table.c:178)\r\n==30882==    by 0x4F0F091: ENGINE_set_default_pkey_asn1_meths (tb_asnmth.c:106)\r\n==30882==    by 0x4F0E007: ENGINE_set_default (eng_fat.c:96)\r\n==30882==    by 0x6464D35: ???\r\n==30882==    by 0x6464A68: ???\r\n==30882==    by 0x6466AB5: ???\r\n==30882==    by 0x6461D58: ???\r\n==30882==    by 0x646218E: ???\r\n```\r\nin case it is not set, it will fault in ENGINE_cleanup() similar to\r\n```\r\n--4389-- Discarding syms at 0x624be50-0x62507d8 in /opt/opensc/lib/libp11.so.2.2.0 due to munmap()\r\n==4389== Invalid read of size 1\r\n==4389==    at 0x4F2D535: EVP_PKEY_meth_free (pmeth_lib.c:293)\r\n==4389==    by 0x4F0EE94: engine_pkey_meths_free (tb_pkmeth.c:163)\r\n==4389==    by 0x4F0BB35: engine_free_util (eng_lib.c:129)\r\n==4389==    by 0x4F0C79B: engine_unlocked_finish (eng_init.c:112)\r\n==4389==    by 0x4F0D25C: int_cleanup_cb_LHASH_DOALL (eng_table.c:220)\r\n==4389==    by 0x4F1BD6C: lh_doall (lhash.c:294)\r\n==4389==    by 0x4F0D582: engine_table_cleanup (eng_table.c:230)\r\n==4389==    by 0x4F0B8C5: engine_cleanup_cb_free (eng_lib.c:186)\r\n==4389==    by 0x4F1B47F: sk_pop_free (stack.c:283)\r\n==4389==    by 0x4F0BC71: ENGINE_cleanup (eng_lib.c:193)\r\n==4389==    by 0x401103: main (gost.c:98)\r\n==4389==  Address 0x5d08634 is 4 bytes inside a block of size 208 free'd\r\n==4389==    at 0x4C2A82E: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)\r\n==4389==    by 0x4E933EC: CRYPTO_free (mem.c:397)\r\n==4389==    by 0x4F0EE94: engine_pkey_meths_free (tb_pkmeth.c:163)\r\n==4389==    by 0x4F0BB35: engine_free_util (eng_lib.c:129)\r\n==4389==    by 0x4F0C79B: engine_unlocked_finish (eng_init.c:112)\r\n==4389==    by 0x4F0D3C1: engine_table_register (eng_table.c:178)\r\n==4389==    by 0x4F0F091: ENGINE_set_default_pkey_asn1_meths (tb_asnmth.c:106)\r\n==4389==    by 0x4F0E007: ENGINE_set_default (eng_fat.c:96)\r\n==4389==    by 0x6464D2F: ???\r\n==4389==    by 0x6464A68: ???\r\n==4389==    by 0x6466A75: ???\r\n==4389==    by 0x6461D58: ???\r\n==4389== \r\n==4389== Invalid free() / delete / delete[] / realloc()\r\n==4389==    at 0x4C2A82E: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)\r\n==4389==    by 0x4E933EC: CRYPTO_free (mem.c:397)\r\n==4389==    by 0x4F0EE94: engine_pkey_meths_free (tb_pkmeth.c:163)\r\n==4389==    by 0x4F0BB35: engine_free_util (eng_lib.c:129)\r\n==4389==    by 0x4F0C79B: engine_unlocked_finish (eng_init.c:112)\r\n==4389==    by 0x4F0D25C: int_cleanup_cb_LHASH_DOALL (eng_table.c:220)\r\n==4389==    by 0x4F1BD6C: lh_doall (lhash.c:294)\r\n==4389==    by 0x4F0D582: engine_table_cleanup (eng_table.c:230)\r\n==4389==    by 0x4F0B8C5: engine_cleanup_cb_free (eng_lib.c:186)\r\n==4389==    by 0x4F1B47F: sk_pop_free (stack.c:283)\r\n==4389==    by 0x4F0BC71: ENGINE_cleanup (eng_lib.c:193)\r\n==4389==    by 0x401103: main (gost.c:98)\r\n==4389==  Address 0x5d08630 is 0 bytes inside a block of size 208 free'd\r\n==4389==    at 0x4C2A82E: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)\r\n==4389==    by 0x4E933EC: CRYPTO_free (mem.c:397)\r\n==4389==    by 0x4F0EE94: engine_pkey_meths_free (tb_pkmeth.c:163)\r\n==4389==    by 0x4F0BB35: engine_free_util (eng_lib.c:129)\r\n==4389==    by 0x4F0C79B: engine_unlocked_finish (eng_init.c:112)\r\n==4389==    by 0x4F0D3C1: engine_table_register (eng_table.c:178)\r\n==4389==    by 0x4F0F091: ENGINE_set_default_pkey_asn1_meths (tb_asnmth.c:106)\r\n==4389==    by 0x4F0E007: ENGINE_set_default (eng_fat.c:96)\r\n==4389==    by 0x6464D2F: ???\r\n==4389==    by 0x6464A68: ???\r\n==4389==    by 0x6466A75: ???\r\n==4389==    by 0x6461D58: ???\r\n```\r\n\r\nThe problem is in OpenSSL here.\r\n```c\r\n#include <openssl/engine.h>\r\n#include <openssl/ssl.h>\r\n\r\n#define GOST\t\"gost\"\r\n\r\nvoid load(void)\r\n{\r\n\tENGINE *e = ENGINE_by_id(GOST);\r\n\tENGINE_set_default(e, ENGINE_METHOD_ALL);\r\n\tENGINE_free(e);\r\n}\r\n\r\nint main(void)\r\n{\r\n\tENGINE_load_builtin_engines();\r\n\tload();\r\n\tload();\r\n\tSSL_CTX *ctx = SSL_CTX_new(SSLv3_client_method());\r\n\treturn 0;\r\n}\r\n```\r\ncrashes the same way without using OpenSC at all.\r\n\r\nThe actual problem is in the gost engine.\r\nThe gost engine uses global statics,which do not get unregistered when unloading the engine.\r\nLoading/ENGINE_set_default gost the first time, things get initialized and registered within OpenSSL, doing it the second time, gost gets finished without unregistering the registered 'things', but they get free'd.\r\nThis way, loading gost twice destroys OpenSSL internally.\r\n\r\nTo OpenSC this is a real problem.\r\nENGINE_init for a engine_pkcs11 will load opensc-pkcs11.so.\r\nLoading opensc-pkcs11.so loads gost in sc_pkcs11_register_openssl_mechanisms().\r\nENGINE_finish() for will call the engine_pkcs11 pkcs11_finish, which will unmapp the pkcs11 library opensc-pkcs11.so.\r\nSecond time ENGINE_init is called, gost is loaded and set default the second time, things break.\r\n\r\nThis can be fixed in OpenSSL, it should be fixed in OpenSSL.\r\nI provided different patches patching it in multiple ways in OpenSSL, no patch was accepted by OpenSSL.\r\n\r\nTherefore I propose to remove gost from OpenSC, using it breaks everything else.\r\nJust do not load it, it'll be broken, but does not work reliable anyway and OpenSC is the wrong scope for repair.\r\n"},"comment":{"url":"https://api.github.com/repos/OpenSC/OpenSC/issues/comments/125466535","html_url":"https://github.com/OpenSC/OpenSC/issues/192#issuecomment-125466535","issue_url":"https://api.github.com/repos/OpenSC/OpenSC/issues/192","id":125466535,"user":{"login":"frankmorgner","id":1266577,"avatar_url":"https://avatars.githubusercontent.com/u/1266577?v=3","gravatar_id":"","url":"https://api.github.com/users/frankmorgner","html_url":"https://github.com/frankmorgner","followers_url":"https://api.github.com/users/frankmorgner/followers","following_url":"https://api.github.com/users/frankmorgner/following{/other_user}","gists_url":"https://api.github.com/users/frankmorgner/gists{/gist_id}","starred_url":"https://api.github.com/users/frankmorgner/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/frankmorgner/subscriptions","organizations_url":"https://api.github.com/users/frankmorgner/orgs","repos_url":"https://api.github.com/users/frankmorgner/repos","events_url":"https://api.github.com/users/frankmorgner/events{/privacy}","received_events_url":"https://api.github.com/users/frankmorgner/received_events","type":"User","site_admin":false},"created_at":"2015-07-28T06:30:38Z","updated_at":"2015-07-28T06:30:38Z","body":"I took your code as is and ran it with the most recent version of OpenSC and OpenSSL 1.0.2. There was no error. The output was as follows (identical for crash_now 1 and 0)\r\n```\r\ninitializing engine\r\nslot number not deciphered!\r\nThe key ID should be a valid PKCS#11 URI as defined by\r\nRFC7512. The legacy ENGINE_pkcs11 ID format is also\r\nstill accepted for now.\r\nPKCS11_get_private_key returned NULL\r\nENGINE_load_private_key: Success\r\n73922236:error:26096080:engine routines:ENGINE_load_private_key:failed loading private key:eng_pkey.c:124:\r\n```\r\nplease re-open if the problem still applies"}}