Rewrite crypto/ex_data
authorRich Salz <rsalz@akamai.com>
Fri, 24 Apr 2015 20:33:34 +0000 (16:33 -0400)
committerRich Salz <rsalz@openssl.org>
Mon, 20 Jul 2015 05:16:28 +0000 (01:16 -0400)
Removed ability to set ex_data impl at runtime.  This removed these
three functions:
    const CRYPTO_EX_DATA_IMPL *CRYPTO_get_ex_data_implementation(void);
    int CRYPTO_set_ex_data_implementation(const CRYPTO_EX_DATA_IMPL *i);
    int CRYPTO_ex_data_new_class(void);
It is no longer possible to change the ex_data implementation at
runtime.  (Luckily those functions were never documented :)

Also removed the ability to add new exdata "classes."  We don't believe
this received much (if any) use, since you can't add it to OpenSSL objects,
and there are probably better (native) methods for developers to add
their own extensible data, if they really need that.

Replaced the internal hash table (of per-"class" stacks) with a simple
indexed array.  Reserved an index for "app" application.

Each API used to take the lock twice; now it only locks once.

Use local stack storage for function pointers, rather than malloc,
if possible (i.e., number of ex_data items is under a dozen).

Make CRYPTO_EX_DATA_FUNCS opaque/internal.

Also fixes RT3710; index zero is reserved.

Reviewed-by: Richard Levitte <levitte@openssl.org>
crypto/cpt_err.c
crypto/engine/eng_dyn.c
crypto/ex_data.c
include/openssl/crypto.h
include/openssl/engine.h
include/openssl/safestack.h
include/openssl/symhacks.h
util/libeay.num

index a513838..1f9a824 100644 (file)
@@ -1,6 +1,6 @@
 /* crypto/cpt_err.c */
 /* ====================================================================
- * Copyright (c) 1999-2011 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1999-2015 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 # define ERR_REASON(reason) ERR_PACK(ERR_LIB_CRYPTO,0,reason)
 
 static ERR_STRING_DATA CRYPTO_str_functs[] = {
+    {ERR_FUNC(CRYPTO_F_CRYPTO_DUP_EX_DATA), "CRYPTO_dup_ex_data"},
+    {ERR_FUNC(CRYPTO_F_CRYPTO_FREE_EX_DATA), "CRYPTO_free_ex_data"},
     {ERR_FUNC(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX), "CRYPTO_get_ex_new_index"},
     {ERR_FUNC(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID), "CRYPTO_get_new_dynlockid"},
     {ERR_FUNC(CRYPTO_F_CRYPTO_GET_NEW_LOCKID), "CRYPTO_get_new_lockid"},
+    {ERR_FUNC(CRYPTO_F_CRYPTO_NEW_EX_DATA), "CRYPTO_new_ex_data"},
     {ERR_FUNC(CRYPTO_F_CRYPTO_SET_EX_DATA), "CRYPTO_set_ex_data"},
     {ERR_FUNC(CRYPTO_F_DEF_ADD_INDEX), "DEF_ADD_INDEX"},
     {ERR_FUNC(CRYPTO_F_DEF_GET_CLASS), "DEF_GET_CLASS"},
index 06a7018..ae7d1d0 100644 (file)
@@ -512,7 +512,6 @@ static int dynamic_load(ENGINE *e, dynamic_data_ctx *ctx)
      * would also increase opaqueness.
      */
     fns.static_state = ENGINE_get_static_state();
-    fns.ex_data_fns = CRYPTO_get_ex_data_implementation();
     CRYPTO_get_mem_functions(&fns.mem_fns.malloc_cb,
                              &fns.mem_fns.realloc_cb, &fns.mem_fns.free_cb);
     fns.lock_fns.lock_locking_cb = CRYPTO_get_locking_callback();
index bf5cf29..62d03bb 100644 (file)
@@ -1,33 +1,3 @@
-/* crypto/ex_data.c */
-
-/*
- * Overhaul notes;
- *
- * This code is now *mostly* thread-safe. It is now easier to understand in what
- * ways it is safe and in what ways it is not, which is an improvement. Firstly,
- * all per-class stacks and index-counters for ex_data are stored in the same
- * global LHASH table (keyed by class). This hash table uses locking for all
- * access with the exception of CRYPTO_cleanup_all_ex_data(), which must only be
- * called when no other threads can possibly race against it (even if it was
- * locked, the race would mean it's possible the hash table might have been
- * recreated after the cleanup). As classes can only be added to the hash table,
- * and within each class, the stack of methods can only be incremented, the
- * locking mechanics are simpler than they would otherwise be. For example, the
- * new/dup/free ex_data functions will lock the hash table, copy the method
- * pointers it needs from the relevant class, then unlock the hash table before
- * actually applying those method pointers to the task of the new/dup/free
- * operations. As they can't be removed from the method-stack, only
- * supplemented, there's no race conditions associated with using them outside
- * the lock. The get/set_ex_data functions are not locked because they do not
- * involve this global state at all - they operate directly with a previously
- * obtained per-class method index and a particular "ex_data" variable. These
- * variables are usually instantiated per-context (eg. each RSA structure has
- * one) so locking on read/write access to that variable can be locked locally
- * if required (eg. using the "RSA" lock to synchronise access to a
- * per-RSA-structure ex_data variable if required).
- * [Geoff]
- */
-
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
 #include "internal/cryptlib.h"
 #include <openssl/lhash.h>
 
-/* What an "implementation of ex_data functionality" looks like */
-struct st_CRYPTO_EX_DATA_IMPL {
-        /*********************/
-    /* GLOBAL OPERATIONS */
-    /* Return a new class index */
-    int (*cb_new_class) (void);
-    /* Cleanup all state used by the implementation */
-    void (*cb_cleanup) (void);
-        /************************/
-    /* PER-CLASS OPERATIONS */
-    /* Get a new method index within a class */
-    int (*cb_get_new_index) (int class_index, long argl, void *argp,
-                             CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
-                             CRYPTO_EX_free *free_func);
-    /* Initialise a new CRYPTO_EX_DATA of a given class */
-    int (*cb_new_ex_data) (int class_index, void *obj, CRYPTO_EX_DATA *ad);
-    /* Duplicate a CRYPTO_EX_DATA of a given class onto a copy */
-    int (*cb_dup_ex_data) (int class_index, CRYPTO_EX_DATA *to,
-                           CRYPTO_EX_DATA *from);
-    /* Cleanup a CRYPTO_EX_DATA of a given class */
-    void (*cb_free_ex_data) (int class_index, void *obj, CRYPTO_EX_DATA *ad);
-};
-
-/* The implementation we use at run-time */
-static const CRYPTO_EX_DATA_IMPL *impl = NULL;
 
-/*
- * To call "impl" functions, use this macro rather than referring to 'impl'
- * directly, eg. EX_IMPL(get_new_index)(...);
- */
-#define EX_IMPL(a) impl->cb_##a
-
-/* Predeclare the "default" ex_data implementation */
-static int int_new_class(void);
-static void int_cleanup(void);
-static int int_get_new_index(int class_index, long argl, void *argp,
-                             CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
-                             CRYPTO_EX_free *free_func);
-static int int_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad);
-static int int_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
-                           CRYPTO_EX_DATA *from);
-static void int_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad);
-static CRYPTO_EX_DATA_IMPL impl_default = {
-    int_new_class,
-    int_cleanup,
-    int_get_new_index,
-    int_new_ex_data,
-    int_dup_ex_data,
-    int_free_ex_data
-};
+typedef struct {
+    long argl;                  /* Arbitary long */
+    void *argp;                 /* Arbitary void * */
+    CRYPTO_EX_new *new_func;
+    CRYPTO_EX_free *free_func;
+    CRYPTO_EX_dup *dup_func;
+} CRYPTO_EX_DATA_FUNCS;
 
-/*
- * Internal function that checks whether "impl" is set and if not, sets it to
- * the default.
- */
-static void impl_check(void)
-{
-    CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
-    if (!impl)
-        impl = &impl_default;
-    CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
-}
+DECLARE_STACK_OF(CRYPTO_EX_DATA_FUNCS)
 
 /*
- * A macro wrapper for impl_check that first uses a non-locked test before
- * invoking the function (which checks again inside a lock).
+ * State for each class; could just be a typedef, but this allows future
+ * changes.
  */
-#define IMPL_CHECK if(!impl) impl_check();
-
-/* API functions to get/set the "ex_data" implementation */
-const CRYPTO_EX_DATA_IMPL *CRYPTO_get_ex_data_implementation(void)
-{
-    IMPL_CHECK return impl;
-}
-
-int CRYPTO_set_ex_data_implementation(const CRYPTO_EX_DATA_IMPL *i)
-{
-    int toret = 0;
-    CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
-    if (!impl) {
-        impl = i;
-        toret = 1;
-    }
-    CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
-    return toret;
-}
-
-/****************************************************************************/
-/*
- * Interal (default) implementation of "ex_data" support. API functions are
- * further down.
- */
-
-/*
- * The type that represents what each "class" used to implement locally. A
- * STACK of CRYPTO_EX_DATA_FUNCS plus a index-counter. The 'class_index' is
- * the global value representing the class that is used to distinguish these
- * items.
- */
-typedef struct st_ex_class_item {
-    int class_index;
+typedef struct {
     STACK_OF(CRYPTO_EX_DATA_FUNCS) *meth;
-    int meth_num;
 } EX_CLASS_ITEM;
 
-/* When assigning new class indexes, this is our counter */
-static int ex_class = CRYPTO_EX_INDEX_USER;
-
-/* The global hash table of EX_CLASS_ITEM items */
-DECLARE_LHASH_OF(EX_CLASS_ITEM);
-static LHASH_OF(EX_CLASS_ITEM) *ex_data = NULL;
-
-/* The callbacks required in the "ex_data" hash table */
-static unsigned long ex_class_item_hash(const EX_CLASS_ITEM *a)
-{
-    return a->class_index;
-}
-
-static IMPLEMENT_LHASH_HASH_FN(ex_class_item, EX_CLASS_ITEM)
-
-static int ex_class_item_cmp(const EX_CLASS_ITEM *a, const EX_CLASS_ITEM *b)
-{
-    return a->class_index - b->class_index;
-}
-
-static IMPLEMENT_LHASH_COMP_FN(ex_class_item, EX_CLASS_ITEM)
+static EX_CLASS_ITEM ex_data[CRYPTO_EX_INDEX__COUNT];
 
 /*
- * Internal functions used by the "impl_default" implementation to access the
- * state
+ * Return the EX_CLASS_ITEM from the "ex_data" array that corresponds to
+ * a given class.  On success, *holds the lock.*
  */
-static int ex_data_check(void)
+static EX_CLASS_ITEM *def_get_class(int class_index)
 {
-    int toret = 1;
+    EX_CLASS_ITEM *ip;
+
+    if (class_index < 0 || class_index >= CRYPTO_EX_INDEX__COUNT) {
+        CRYPTOerr(CRYPTO_F_DEF_GET_CLASS, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    ip = &ex_data[class_index];
     CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
-    if (!ex_data && (ex_data = lh_EX_CLASS_ITEM_new()) == NULL)
-        toret = 0;
-    CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
-    return toret;
+    if (ip->meth == NULL) {
+        ip->meth = sk_CRYPTO_EX_DATA_FUNCS_new_null();
+        /* We push an initial value on the stack because the SSL
+         * "app_data" routines use ex_data index zero.  See RT 3710. */
+        if (ip->meth == NULL
+            || !sk_CRYPTO_EX_DATA_FUNCS_push(ip->meth, NULL)) {
+            CRYPTOerr(CRYPTO_F_DEF_GET_CLASS, ERR_R_MALLOC_FAILURE);
+            CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
+            return NULL;
+        }
+    }
+    return ip;
 }
 
-/*
- * This macros helps reduce the locking from repeated checks because the
- * ex_data_check() function checks ex_data again inside a lock.
- */
-#define EX_DATA_CHECK(iffail) if(!ex_data && !ex_data_check()) {iffail}
-
-/* This "inner" callback is used by the callback function that follows it */
-static void def_cleanup_util_cb(CRYPTO_EX_DATA_FUNCS *funcs)
+static void cleanup_cb(CRYPTO_EX_DATA_FUNCS *funcs)
 {
     OPENSSL_free(funcs);
 }
 
 /*
- * This callback is used in lh_doall to destroy all EX_CLASS_ITEM values from
- * "ex_data" prior to the ex_data hash table being itself destroyed. Doesn't
- * do any locking.
+ * Release all "ex_data" state to prevent memory leaks. This can't be made
+ * thread-safe without overhauling a lot of stuff, and shouldn't really be
+ * called under potential race-conditions anyway (it's for program shutdown
+ * after all).
  */
-static void def_cleanup_cb(void *a_void)
+void CRYPTO_cleanup_all_ex_data(void)
 {
-    EX_CLASS_ITEM *item = (EX_CLASS_ITEM *)a_void;
-    sk_CRYPTO_EX_DATA_FUNCS_pop_free(item->meth, def_cleanup_util_cb);
-    OPENSSL_free(item);
-}
+    int i;
 
-/*
- * Return the EX_CLASS_ITEM from the "ex_data" hash table that corresponds to
- * a given class. Handles locking.
- */
-static EX_CLASS_ITEM *def_get_class(int class_index)
-{
-    EX_CLASS_ITEM d, *p, *gen;
-    EX_DATA_CHECK(return NULL;)
-        d.class_index = class_index;
-    CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
-    p = lh_EX_CLASS_ITEM_retrieve(ex_data, &d);
-    if (!p) {
-        gen = OPENSSL_malloc(sizeof(*gen));
-        if (gen) {
-            gen->class_index = class_index;
-            gen->meth_num = 0;
-            gen->meth = sk_CRYPTO_EX_DATA_FUNCS_new_null();
-            if (!gen->meth)
-                OPENSSL_free(gen);
-            else {
-                /*
-                 * Because we're inside the ex_data lock, the return value
-                 * from the insert will be NULL
-                 */
-                (void)lh_EX_CLASS_ITEM_insert(ex_data, gen);
-                p = gen;
-            }
-        }
+    for (i = 0; i < CRYPTO_EX_INDEX__COUNT; ++i) {
+        EX_CLASS_ITEM *ip = &ex_data[i];
+
+        sk_CRYPTO_EX_DATA_FUNCS_pop_free(ip->meth, cleanup_cb);
+        ip->meth = NULL;
     }
-    CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
-    if (!p)
-        CRYPTOerr(CRYPTO_F_DEF_GET_CLASS, ERR_R_MALLOC_FAILURE);
-    return p;
 }
 
 /*
- * Add a new method to the given EX_CLASS_ITEM and return the corresponding
- * index (or -1 for error). Handles locking.
+ * Inside an existing class, get/register a new index.
  */
-static int def_add_index(EX_CLASS_ITEM *item, long argl, void *argp,
-                         CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
-                         CRYPTO_EX_free *free_func)
+int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
+                            CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
+                            CRYPTO_EX_free *free_func)
 {
     int toret = -1;
-    CRYPTO_EX_DATA_FUNCS *a = OPENSSL_malloc(sizeof(*a));
-    if (!a) {
-        CRYPTOerr(CRYPTO_F_DEF_ADD_INDEX, ERR_R_MALLOC_FAILURE);
+    CRYPTO_EX_DATA_FUNCS *a;
+    EX_CLASS_ITEM *ip = def_get_class(class_index);
+
+    if (!ip)
         return -1;
+    a = (CRYPTO_EX_DATA_FUNCS *)OPENSSL_malloc(sizeof(*a));
+    if (!a) {
+        CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
+        goto err;
     }
     a->argl = argl;
     a->argp = argp;
     a->new_func = new_func;
     a->dup_func = dup_func;
     a->free_func = free_func;
-    CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
-    while (sk_CRYPTO_EX_DATA_FUNCS_num(item->meth) <= item->meth_num) {
-        if (!sk_CRYPTO_EX_DATA_FUNCS_push(item->meth, NULL)) {
-            CRYPTOerr(CRYPTO_F_DEF_ADD_INDEX, ERR_R_MALLOC_FAILURE);
-            OPENSSL_free(a);
-            goto err;
-        }
-    }
-    toret = item->meth_num++;
-    (void)sk_CRYPTO_EX_DATA_FUNCS_set(item->meth, toret, a);
- err:
-    CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
-    return toret;
-}
 
-/**************************************************************/
-/* The functions in the default CRYPTO_EX_DATA_IMPL structure */
+    if (!sk_CRYPTO_EX_DATA_FUNCS_push(ip->meth, NULL)) {
+        CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
+        OPENSSL_free(a);
+        goto err;
+    }
+    toret = sk_CRYPTO_EX_DATA_FUNCS_num(ip->meth) - 1;
+    (void)sk_CRYPTO_EX_DATA_FUNCS_set(ip->meth, toret, a);
 
-static int int_new_class(void)
-{
-    int toret;
-    CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
-    toret = ex_class++;
+ err:
     CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
     return toret;
 }
 
-static void int_cleanup(void)
-{
-    EX_DATA_CHECK(return;)
-        lh_EX_CLASS_ITEM_doall(ex_data, def_cleanup_cb);
-    lh_EX_CLASS_ITEM_free(ex_data);
-    ex_data = NULL;
-    impl = NULL;
-}
-
-static int int_get_new_index(int class_index, long argl, void *argp,
-                             CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
-                             CRYPTO_EX_free *free_func)
-{
-    EX_CLASS_ITEM *item = def_get_class(class_index);
-    if (!item)
-        return -1;
-    return def_add_index(item, argl, argp, new_func, dup_func, free_func);
-}
-
 /*
+ * Initialise a new CRYPTO_EX_DATA for use in a particular class - including
+ * calling new() callbacks for each index in the class used by this variable
  * Thread-safe by copying a class's array of "CRYPTO_EX_DATA_FUNCS" entries
- * in the lock, then using them outside the lock. NB: Thread-safety only
- * applies to the global "ex_data" state (ie. class definitions), not
- * thread-safe on 'ad' itself.
+ * in the lock, then using them outside the lock. Note this only applies
+ * to the global "ex_data" state (ie. class definitions), not 'ad' itself.
  */
-static int int_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
+int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
 {
     int mx, i;
     void *ptr;
     CRYPTO_EX_DATA_FUNCS **storage = NULL;
-    EX_CLASS_ITEM *item = def_get_class(class_index);
-    if (!item)
-        /* error is already set */
+    CRYPTO_EX_DATA_FUNCS *stack[10];
+    EX_CLASS_ITEM *ip = def_get_class(class_index);
+
+    if (!ip)
         return 0;
+
     ad->sk = NULL;
-    CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
-    mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth);
+
+    mx = sk_CRYPTO_EX_DATA_FUNCS_num(ip->meth);
     if (mx > 0) {
-        storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS *));
-        if (!storage)
-            goto skip;
-        for (i = 0; i < mx; i++)
-            storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth, i);
+        if (mx < (int)OSSL_NELEM(stack))
+            storage = stack;
+        else
+            storage = OPENSSL_malloc(sizeof(*storage) * mx);
+        if (storage)
+            for (i = 0; i < mx; i++)
+                storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(ip->meth, i);
     }
- skip:
-    CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA);
-    if ((mx > 0) && !storage) {
-        CRYPTOerr(CRYPTO_F_INT_NEW_EX_DATA, ERR_R_MALLOC_FAILURE);
+    CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
+
+    if (mx > 0 && storage == NULL) {
+        CRYPTOerr(CRYPTO_F_CRYPTO_NEW_EX_DATA, ERR_R_MALLOC_FAILURE);
         return 0;
     }
     for (i = 0; i < mx; i++) {
@@ -444,41 +264,50 @@ static int int_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
                                  storage[i]->argl, storage[i]->argp);
         }
     }
-    OPENSSL_free(storage);
+    if (storage != stack)
+        OPENSSL_free(storage);
     return 1;
 }
 
-/* Same thread-safety notes as for "int_new_ex_data" */
-static int int_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
-                           CRYPTO_EX_DATA *from)
+/*
+ * Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks
+ * for each index in the class used by this variable
+ */
+int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
+                       CRYPTO_EX_DATA *from)
 {
     int mx, j, i;
     char *ptr;
+    CRYPTO_EX_DATA_FUNCS *stack[10];
     CRYPTO_EX_DATA_FUNCS **storage = NULL;
-    EX_CLASS_ITEM *item;
-    if (!from->sk)
-        /* 'to' should be "blank" which *is* just like 'from' */
+    EX_CLASS_ITEM *ip;
+
+    if (from->sk == NULL)
+        /* Nothing to copy over */
         return 1;
-    if ((item = def_get_class(class_index)) == NULL)
+    if ((ip = def_get_class(class_index)) == NULL)
         return 0;
-    CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
-    mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth);
+
+    mx = sk_CRYPTO_EX_DATA_FUNCS_num(ip->meth);
     j = sk_void_num(from->sk);
     if (j < mx)
         mx = j;
     if (mx > 0) {
-        storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS *));
-        if (!storage)
-            goto skip;
-        for (i = 0; i < mx; i++)
-            storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth, i);
+        if (mx < (int)OSSL_NELEM(stack))
+            storage = stack;
+        else
+            storage = OPENSSL_malloc(sizeof(*storage) * mx);
+        if (storage)
+            for (i = 0; i < mx; i++)
+                storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(ip->meth, i);
     }
- skip:
-    CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA);
-    if ((mx > 0) && !storage) {
-        CRYPTOerr(CRYPTO_F_INT_DUP_EX_DATA, ERR_R_MALLOC_FAILURE);
+    CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
+
+    if (mx > 0 && storage == NULL) {
+        CRYPTOerr(CRYPTO_F_CRYPTO_DUP_EX_DATA, ERR_R_MALLOC_FAILURE);
         return 0;
     }
+
     for (i = 0; i < mx; i++) {
         ptr = CRYPTO_get_ex_data(from, i);
         if (storage[i] && storage[i]->dup_func)
@@ -486,34 +315,41 @@ static int int_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
                                  storage[i]->argl, storage[i]->argp);
         CRYPTO_set_ex_data(to, i, ptr);
     }
-    OPENSSL_free(storage);
+    if (storage != stack)
+        OPENSSL_free(storage);
     return 1;
 }
 
-/* Same thread-safety notes as for "int_new_ex_data" */
-static void int_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
+
+/*
+ * Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for
+ * each index in the class used by this variable
+ */
+void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
 {
     int mx, i;
-    EX_CLASS_ITEM *item;
+    EX_CLASS_ITEM *ip;
     void *ptr;
+    CRYPTO_EX_DATA_FUNCS *stack[10];
     CRYPTO_EX_DATA_FUNCS **storage = NULL;
-    if (ex_data == NULL)
-        return;
-    if ((item = def_get_class(class_index)) == NULL)
+
+    if ((ip = def_get_class(class_index)) == NULL)
         return;
-    CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
-    mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth);
+
+    mx = sk_CRYPTO_EX_DATA_FUNCS_num(ip->meth);
     if (mx > 0) {
-        storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS *));
-        if (!storage)
-            goto skip;
-        for (i = 0; i < mx; i++)
-            storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth, i);
+        if (mx < (int)OSSL_NELEM(stack))
+            storage = stack;
+        else
+            storage = OPENSSL_malloc(sizeof(*storage) * mx);
+        if (storage)
+            for (i = 0; i < mx; i++)
+                storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(ip->meth, i);
     }
- skip:
-    CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA);
-    if ((mx > 0) && !storage) {
-        CRYPTOerr(CRYPTO_F_INT_FREE_EX_DATA, ERR_R_MALLOC_FAILURE);
+    CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
+
+    if (mx > 0 && storage == NULL) {
+        CRYPTOerr(CRYPTO_F_CRYPTO_FREE_EX_DATA, ERR_R_MALLOC_FAILURE);
         return;
     }
     for (i = 0; i < mx; i++) {
@@ -523,79 +359,13 @@ static void int_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
                                   storage[i]->argl, storage[i]->argp);
         }
     }
-    OPENSSL_free(storage);
+
+    if (storage != stack)
+        OPENSSL_free(storage);
     sk_void_free(ad->sk);
     ad->sk = NULL;
 }
 
-/********************************************************************/
-/*
- * API functions that defer all "state" operations to the "ex_data"
- * implementation we have set.
- */
-
-/*
- * Obtain an index for a new class (not the same as getting a new index
- * within an existing class - this is actually getting a new *class*)
- */
-int CRYPTO_ex_data_new_class(void)
-{
-    IMPL_CHECK return EX_IMPL(new_class) ();
-}
-
-/*
- * Release all "ex_data" state to prevent memory leaks. This can't be made
- * thread-safe without overhauling a lot of stuff, and shouldn't really be
- * called under potential race-conditions anyway (it's for program shutdown
- * after all).
- */
-void CRYPTO_cleanup_all_ex_data(void)
-{
-    IMPL_CHECK EX_IMPL(cleanup) ();
-}
-
-/* Inside an existing class, get/register a new index. */
-int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
-                            CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
-                            CRYPTO_EX_free *free_func)
-{
-    int ret = -1;
-
-    IMPL_CHECK
-        ret = EX_IMPL(get_new_index) (class_index,
-                                      argl, argp, new_func, dup_func,
-                                      free_func);
-    return ret;
-}
-
-/*
- * Initialise a new CRYPTO_EX_DATA for use in a particular class - including
- * calling new() callbacks for each index in the class used by this variable
- */
-int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
-{
-    IMPL_CHECK return EX_IMPL(new_ex_data) (class_index, obj, ad);
-}
-
-/*
- * Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks
- * for each index in the class used by this variable
- */
-int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
-                       CRYPTO_EX_DATA *from)
-{
-    IMPL_CHECK return EX_IMPL(dup_ex_data) (class_index, to, from);
-}
-
-/*
- * Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for
- * each index in the class used by this variable
- */
-void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
-{
-    IMPL_CHECK EX_IMPL(free_ex_data) (class_index, obj, ad);
-}
-
 /*
  * For a given CRYPTO_EX_DATA variable, set the value corresponding to a
  * particular index in the class used by this variable
@@ -607,20 +377,18 @@ int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val)
     if (ad->sk == NULL) {
         if ((ad->sk = sk_void_new_null()) == NULL) {
             CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE);
-            return (0);
+            return 0;
         }
     }
-    i = sk_void_num(ad->sk);
 
-    while (i <= idx) {
+    for (i = sk_void_num(ad->sk); i <= idx; ++i) {
         if (!sk_void_push(ad->sk, NULL)) {
             CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE);
-            return (0);
+            return 0;
         }
-        i++;
     }
     sk_void_set(ad->sk, idx, val);
-    return (1);
+    return 1;
 }
 
 /*
@@ -629,10 +397,7 @@ int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val)
  */
 void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx)
 {
-    if (ad->sk == NULL)
-        return (0);
-    else if (idx >= sk_void_num(ad->sk))
-        return (0);
-    else
-        return (sk_void_value(ad->sk, idx));
+    if (ad->sk == NULL || idx >= sk_void_num(ad->sk))
+        return NULL;
+    return sk_void_value(ad->sk, idx);
 }
index 1bda645..faaf1d5 100644 (file)
@@ -284,25 +284,9 @@ struct crypto_ex_data_st {
 DECLARE_STACK_OF(void)
 
 /*
- * This stuff is basically class callback functions The current classes are
- * SSL_CTX, SSL, SSL_SESSION, and a few more
- */
-
-typedef struct crypto_ex_data_func_st {
-    long argl;                  /* Arbitary long */
-    void *argp;                 /* Arbitary void * */
-    CRYPTO_EX_new *new_func;
-    CRYPTO_EX_free *free_func;
-    CRYPTO_EX_dup *dup_func;
-} CRYPTO_EX_DATA_FUNCS;
-
-DECLARE_STACK_OF(CRYPTO_EX_DATA_FUNCS)
-
-/*
  * Per class, we have a STACK of CRYPTO_EX_DATA_FUNCS for each CRYPTO_EX_DATA
  * entry.
  */
-
 # define CRYPTO_EX_INDEX_BIO             0
 # define CRYPTO_EX_INDEX_SSL             1
 # define CRYPTO_EX_INDEX_SSL_CTX         2
@@ -319,12 +303,8 @@ DECLARE_STACK_OF(CRYPTO_EX_DATA_FUNCS)
 # define CRYPTO_EX_INDEX_ECDH            13
 # define CRYPTO_EX_INDEX_COMP            14
 # define CRYPTO_EX_INDEX_STORE           15
-
-/*
- * Dynamically assigned indexes start from this value (don't use directly,
- * use via CRYPTO_ex_data_new_class).
- */
-# define CRYPTO_EX_INDEX_USER            100
+# define CRYPTO_EX_INDEX_APP             16
+# define CRYPTO_EX_INDEX__COUNT          17
 
 /*
  * This is the default callbacks, but we can have others as well: this is
@@ -386,14 +366,6 @@ unsigned long SSLeay(void);
 
 int OPENSSL_issetugid(void);
 
-/* An opaque type representing an implementation of "ex_data" support */
-typedef struct st_CRYPTO_EX_DATA_IMPL CRYPTO_EX_DATA_IMPL;
-/* Return an opaque pointer to the current "ex_data" implementation */
-const CRYPTO_EX_DATA_IMPL *CRYPTO_get_ex_data_implementation(void);
-/* Sets the "ex_data" implementation to be used (if it's not too late) */
-int CRYPTO_set_ex_data_implementation(const CRYPTO_EX_DATA_IMPL *i);
-/* Get a new "ex_data" class, and return the corresponding "class_index" */
-int CRYPTO_ex_data_new_class(void);
 /* Within a given class, get/register a new index */
 int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
                             CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
@@ -611,6 +583,11 @@ int FIPS_mode_set(int r);
 
 void OPENSSL_init(void);
 
+struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result);
+int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, long offset_sec);
+int OPENSSL_gmtime_diff(int *pday, int *psec,
+                        const struct tm *from, const struct tm *to);
+
 /*
  * CRYPTO_memcmp returns zero iff the |len| bytes at |a| and |b| are equal.
  * It takes an amount of time dependent on |len|, but independent of the
@@ -627,17 +604,15 @@ int CRYPTO_memcmp(const void *a, const void *b, size_t len);
  */
 void ERR_load_CRYPTO_strings(void);
 
-struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result);
-int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, long offset_sec);
-int OPENSSL_gmtime_diff(int *pday, int *psec,
-                        const struct tm *from, const struct tm *to);
-
 /* Error codes for the CRYPTO functions. */
 
 /* Function codes. */
+# define CRYPTO_F_CRYPTO_DUP_EX_DATA                      110
+# define CRYPTO_F_CRYPTO_FREE_EX_DATA                     111
 # define CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX                 100
 # define CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID                103
 # define CRYPTO_F_CRYPTO_GET_NEW_LOCKID                   101
+# define CRYPTO_F_CRYPTO_NEW_EX_DATA                      112
 # define CRYPTO_F_CRYPTO_SET_EX_DATA                      102
 # define CRYPTO_F_DEF_ADD_INDEX                           104
 # define CRYPTO_F_DEF_GET_CLASS                           105
index fa1d694..c228487 100644 (file)
@@ -776,7 +776,6 @@ typedef struct st_dynamic_LOCK_fns {
 /* The top-level structure */
 typedef struct st_dynamic_fns {
     void *static_state;
-    const CRYPTO_EX_DATA_IMPL *ex_data_fns;
     dynamic_MEM_fns mem_fns;
     dynamic_LOCK_fns lock_fns;
 } dynamic_fns;
@@ -834,8 +833,6 @@ typedef int (*dynamic_bind_engine) (ENGINE *e, const char *id,
                 CRYPTO_set_dynlock_create_callback(fns->lock_fns.dynlock_create_cb); \
                 CRYPTO_set_dynlock_lock_callback(fns->lock_fns.dynlock_lock_cb); \
                 CRYPTO_set_dynlock_destroy_callback(fns->lock_fns.dynlock_destroy_cb); \
-                if(!CRYPTO_set_ex_data_implementation(fns->ex_data_fns)) \
-                        return 0; \
         skip_cbs: \
                 if(!fn(e,id)) return 0; \
                 return 1; }
index e138bfc..785bec6 100644 (file)
@@ -2251,24 +2251,6 @@ DECLARE_SPECIAL_STACK_OF(OPENSSL_BLOCK, void)
   LHM_lh_stats_bio(ERR_STRING_DATA,lh,out)
 # define lh_ERR_STRING_DATA_free(lh) LHM_lh_free(ERR_STRING_DATA,lh)
 
-# define lh_EX_CLASS_ITEM_new() LHM_lh_new(EX_CLASS_ITEM,ex_class_item)
-# define lh_EX_CLASS_ITEM_insert(lh,inst) LHM_lh_insert(EX_CLASS_ITEM,lh,inst)
-# define lh_EX_CLASS_ITEM_retrieve(lh,inst) LHM_lh_retrieve(EX_CLASS_ITEM,lh,inst)
-# define lh_EX_CLASS_ITEM_delete(lh,inst) LHM_lh_delete(EX_CLASS_ITEM,lh,inst)
-# define lh_EX_CLASS_ITEM_doall(lh,fn) LHM_lh_doall(EX_CLASS_ITEM,lh,fn)
-# define lh_EX_CLASS_ITEM_doall_arg(lh,fn,arg_type,arg) \
-  LHM_lh_doall_arg(EX_CLASS_ITEM,lh,fn,arg_type,arg)
-# define lh_EX_CLASS_ITEM_error(lh) LHM_lh_error(EX_CLASS_ITEM,lh)
-# define lh_EX_CLASS_ITEM_num_items(lh) LHM_lh_num_items(EX_CLASS_ITEM,lh)
-# define lh_EX_CLASS_ITEM_down_load(lh) LHM_lh_down_load(EX_CLASS_ITEM,lh)
-# define lh_EX_CLASS_ITEM_node_stats_bio(lh,out) \
-  LHM_lh_node_stats_bio(EX_CLASS_ITEM,lh,out)
-# define lh_EX_CLASS_ITEM_node_usage_stats_bio(lh,out) \
-  LHM_lh_node_usage_stats_bio(EX_CLASS_ITEM,lh,out)
-# define lh_EX_CLASS_ITEM_stats_bio(lh,out) \
-  LHM_lh_stats_bio(EX_CLASS_ITEM,lh,out)
-# define lh_EX_CLASS_ITEM_free(lh) LHM_lh_free(EX_CLASS_ITEM,lh)
-
 # define lh_FUNCTION_new() LHM_lh_new(FUNCTION,function)
 # define lh_FUNCTION_insert(lh,inst) LHM_lh_insert(FUNCTION,lh,inst)
 # define lh_FUNCTION_retrieve(lh,inst) LHM_lh_retrieve(FUNCTION,lh,inst)
index 9785685..3253df8 100644 (file)
  */
 # ifdef OPENSSL_SYS_VMS
 
-/* Hack a long name in crypto/ex_data.c */
-#  undef CRYPTO_get_ex_data_implementation
-#  define CRYPTO_get_ex_data_implementation       CRYPTO_get_ex_data_impl
-#  undef CRYPTO_set_ex_data_implementation
-#  define CRYPTO_set_ex_data_implementation       CRYPTO_set_ex_data_impl
-
 /* Hack a long name in crypto/asn1/a_mbstr.c */
 #  undef ASN1_STRING_set_default_mask_asc
 #  define ASN1_STRING_set_default_mask_asc        ASN1_STRING_set_def_mask_asc
index 731db22..a82db68 100755 (executable)
@@ -2328,8 +2328,8 @@ X509_CRL_set_lastUpdate                 2837      EXIST::FUNCTION:
 OCSP_BASICRESP_free                     2838   EXIST::FUNCTION:
 OCSP_BASICRESP_add1_ext_i2d             2839   EXIST::FUNCTION:
 d2i_KRB5_AUTHENTBODY                    2840   NOEXIST::FUNCTION:
-CRYPTO_set_ex_data_implementation       2841   EXIST:!VMS:FUNCTION:
-CRYPTO_set_ex_data_impl                 2841   EXIST:VMS:FUNCTION:
+CRYPTO_set_ex_data_impl                 2841   NOEXIST::FUNCTION:
+CRYPTO_set_ex_data_implementation       2841   NOEXIST::FUNCTION:
 KRB5_ENCDATA_new                        2842   NOEXIST::FUNCTION:
 DSO_up_ref                              2843   EXIST::FUNCTION:
 OCSP_crl_reason_str                     2844   EXIST::FUNCTION:
@@ -2559,7 +2559,7 @@ AES_encrypt                             3033      EXIST::FUNCTION:AES
 OCSP_REQUEST_new                        3034   EXIST::FUNCTION:
 ASN1_ANY_it                             3035   EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
 ASN1_ANY_it                             3035   EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
-CRYPTO_ex_data_new_class                3036   EXIST::FUNCTION:
+CRYPTO_ex_data_new_class                3036   NOEXIST::FUNCTION:
 _ossl_old_des_ncbc_encrypt              3037   NOEXIST::FUNCTION:
 i2d_KRB5_TKTBODY                        3038   NOEXIST::FUNCTION:
 EC_POINT_clear_free                     3039   EXIST::FUNCTION:EC
@@ -2676,8 +2676,8 @@ USERNOTICE_it                           3132      EXIST:!EXPORT_VAR_AS_FUNCTION:VARIA
 USERNOTICE_it                           3132   EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
 OCSP_REQINFO_new                        3133   EXIST::FUNCTION:
 OCSP_BASICRESP_get_ext                  3134   EXIST::FUNCTION:
-CRYPTO_get_ex_data_implementation       3135   EXIST:!VMS:FUNCTION:
-CRYPTO_get_ex_data_impl                 3135   EXIST:VMS:FUNCTION:
+CRYPTO_get_ex_data_impl                 3135   NOEXIST::FUNCTION:
+CRYPTO_get_ex_data_implementation       3135   NOEXIST::FUNCTION:
 ASN1_item_pack                          3136   EXIST::FUNCTION:
 i2d_KRB5_ENCDATA                        3137   NOEXIST::FUNCTION:
 X509_PURPOSE_set                        3138   EXIST::FUNCTION: