diff -up libgcrypt-1.5.3/src/ath.c.ath-reinstall libgcrypt-1.5.3/src/ath.c --- libgcrypt-1.5.3/src/ath.c.ath-reinstall 2013-07-25 11:10:04.000000000 +0200 +++ libgcrypt-1.5.3/src/ath.c 2017-02-28 14:37:15.267668432 +0100 @@ -36,7 +36,7 @@ #include #include "ath.h" - +#include "g10lib.h" /* The interface table. */ @@ -45,6 +45,13 @@ static struct ath_ops ops; /* True if we should use the external callbacks. */ static int ops_set; +struct lock_list +{ + ath_mutex_t *lock; + struct lock_list *next; +}; + +static struct lock_list *reinstallable_locks; /* For the dummy interface. */ #define MUTEX_UNLOCKED ((ath_mutex_t) 0) @@ -62,6 +69,50 @@ static int ops_set; /* The lock we take while checking for lazy lock initialization. */ static ath_mutex_t check_init_lock = ATH_MUTEX_INITIALIZER; +static void +add_reinstallable_lock(ath_mutex_t *lock) +{ + struct lock_list *ll, *new, **ptr; + + new = gcry_calloc(1, sizeof(*new)); + if (!new) + abort(); + + for (ll = reinstallable_locks, ptr = &reinstallable_locks; ll != NULL; ptr = &ll->next, ll = ll->next) + { + if (ll->lock == lock) + { + gcry_free(new); + return; + } + } + + new->lock = lock; + *ptr = new; +} + +static void +remove_reinstallable_lock(ath_mutex_t *lock) +{ + struct lock_list *ll, **ptr; + + for (ll = reinstallable_locks, ptr = &reinstallable_locks; ll != NULL; ptr = &ll->next, ll = ll->next) + { + if (ll->lock == lock) + { + *ptr = ll->next; + gcry_free(ll); + /* we do not store duplicates */ + return; + } + } + +#ifndef NDEBUG + /* lock not found, should not happen */ + abort(); +#endif +} + int ath_init (void) { @@ -85,7 +136,9 @@ ath_init (void) gpg_err_code_t ath_install (struct ath_ops *ath_ops, int check_only) { - if (check_only) + gpg_err_code_t err = 0; + + if (check_only && ops_set) { unsigned int option = 0; @@ -119,7 +172,25 @@ ath_install (struct ath_ops *ath_ops, in else ops_set = 0; - return 0; + if (ops_set && reinstallable_locks) + { + struct lock_list *ll; + + ath_init(); + for (ll = reinstallable_locks; ll != NULL;) + { + struct lock_list *prev; + + if (ath_mutex_init(ll->lock)) + err = GPG_ERR_NOT_SUPPORTED; + prev = ll; + ll = ll->next; + gcry_free(prev); + } + reinstallable_locks = NULL; + } + + return err; } @@ -143,6 +214,8 @@ ath_mutex_init (ath_mutex_t *lock) { if (ops_set) return mutex_init (lock, 0); + else + add_reinstallable_lock(lock); #ifndef NDEBUG *lock = MUTEX_UNLOCKED; @@ -168,6 +241,8 @@ ath_mutex_destroy (ath_mutex_t *lock) (*ops.mutex_unlock) (&check_init_lock); return (*ops.mutex_destroy) (lock); } + else + remove_reinstallable_lock(lock); #ifndef NDEBUG assert (*lock == MUTEX_UNLOCKED);