aboutsummaryrefslogtreecommitdiffstats
path: root/src/init.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2019-01-04 12:13:53 +0000
committerWerner Koch <[email protected]>2019-01-04 12:13:53 +0000
commit933bfd7b652a907c0d8dd5337c6b5b9cb82ce7b7 (patch)
tree2c3d78726642c6ccad34296082d5c85e3189a51c /src/init.c
parentestream: Use correct POSIX name THOUSEP. (diff)
downloadlibgpg-error-933bfd7b652a907c0d8dd5337c6b5b9cb82ce7b7.tar.gz
libgpg-error-933bfd7b652a907c0d8dd5337c6b5b9cb82ce7b7.zip
core: New functions gpgrt_abort and gpgrt_add_emergency_cleanup.
* src/init.c (emergency_cleanup_list): New gloabl var. (_gpgrt_add_emergency_cleanup): New. (_gpgrt_abort): New. Repalce all calls to abort by this. Also replace all assert by either log_assert or a stderr output followed by a _gpgrt_abort. (run_emergency_cleanup): New. * src/visibility.c (gpgrt_add_emergency_cleanup): New public API. (gpgrt_abort): New public API. -- Libgcrypt uses its own assert function which makes sure to terminate the secure memory. This is safe as log as an assert is triggered internally in Libgcrypt. GnuPG runs emergency cleanup handlers right before log_fatal etc to tell Libgcrypt to terminate the secure memory. With the move of the logging function to gpgrt in gnupg 2.3 this did not anymore. Thus we now provide a mechanism in gpgrt to do right that. Eventually Libgcrypt can also make use of this. What this does not handle are calls to abort or failed asserts in external libraries or in libc. We can't do anything about it in a library because a library may not setup signal handlers. Signed-off-by: Werner Koch <[email protected]>
Diffstat (limited to 'src/init.c')
-rw-r--r--src/init.c79
1 files changed, 77 insertions, 2 deletions
diff --git a/src/init.c b/src/init.c
index f104ec4..8ddf0c0 100644
--- a/src/init.c
+++ b/src/init.c
@@ -61,6 +61,20 @@ static void drop_locale_dir (char *locale_dir);
#endif /*!HAVE_W32_SYSTEM*/
+/* The list of emergency cleanup functions; see _gpgrt_abort and
+ * _gpgrt_add_emergency_cleanup. */
+struct emergency_cleanup_item_s;
+typedef struct emergency_cleanup_item_s *emergency_cleanup_item_t;
+struct emergency_cleanup_item_s
+{
+ emergency_cleanup_item_t next;
+ void (*func) (void);
+};
+static emergency_cleanup_item_t emergency_cleanup_list;
+
+
+
+
/* The realloc function as set by gpgrt_set_alloc_func. */
static void *(*custom_realloc)(void *a, size_t n);
@@ -106,7 +120,7 @@ _gpg_err_init (void)
if (tls_index == TLS_OUT_OF_INDEXES)
{
/* No way to continue - commit suicide. */
- abort ();
+ _gpgrt_abort ();
}
_gpg_w32__init_gettext_module ();
real_init ();
@@ -151,6 +165,67 @@ _gpg_err_deinit (int mode)
}
+/* Add the emergency cleanup function F to the list of those function.
+ * If the a function with that address has already been registered, it
+ * is not added a second time. These emergency functions are called
+ * whenever gpgrt_abort is called and at no other place. Like signal
+ * handles the emergency cleanup functions shall not call any
+ * non-trivial functions and return as soon as possible. They allow
+ * to cleanup internal states which should not go into a core dumps or
+ * similar. This is independent of any atexit functions. We don't
+ * use locks here because in an emergency case we can't use them
+ * anyway. */
+void
+_gpgrt_add_emergency_cleanup (void (*f)(void))
+{
+ emergency_cleanup_item_t item;
+
+ for (item = emergency_cleanup_list; item; item = item->next)
+ if (item->func == f)
+ return; /* Function has already been registered. */
+
+ /* We use a standard malloc here. */
+ item = malloc (sizeof *item);
+ if (item)
+ {
+ item->func = f;
+ item->next = emergency_cleanup_list;
+ emergency_cleanup_list = item;
+ }
+ else
+ _gpgrt_log_fatal ("out of core in gpgrt_add_emergency_cleanup\n");
+}
+
+
+/* Run the emergency handlers. No locks are used because we are anyway
+ * in an emergency state. We also can't release any memory. */
+static void
+run_emergency_cleanup (void)
+{
+ emergency_cleanup_item_t next;
+ void (*f)(void);
+
+ while (emergency_cleanup_list)
+ {
+ next = emergency_cleanup_list->next;
+ f = emergency_cleanup_list->func;
+ emergency_cleanup_list->func = NULL;
+ emergency_cleanup_list = next;
+ if (f)
+ f ();
+ }
+}
+
+
+/* Wrapper around abort to be able to run all emergency cleanup
+ * functions. */
+void
+_gpgrt_abort (void)
+{
+ run_emergency_cleanup ();
+ abort ();
+}
+
/* Register F as allocation function. This function is used for all
@@ -503,7 +578,7 @@ get_tls (void)
if (!tls)
{
/* No way to continue - commit suicide. */
- abort ();
+ _gpgrt_abort ();
}
tls->gt_use_utf8 = 0;
TlsSetValue (tls_index, tls);