I have a question in this area, not necessarily a result of this commit.

I have been playing with a new crypto provider, in a non-DSO build,
intended to be used with httpd.

The provider does have both an initialization and termination API.

My issue is a result of the "rootp" being used for the driver hashmap
but "pconf" (in the httpd/mod_session_crypto case) being passed to the
drivers init() function the first time it's loaded.  This means at
graceful restart, cleanups registered by the drivers init() function
will run, but apr_crypto_term will not, and the next call to get the
driver will not re-run the init().

Making the lifetimes match either way fixes my test -- either moving
the "rootp" stuff to DSO-only for apr_crypto_init or by passing
"rootp" to the DRIVER_LOAD macro for non-DSO init.

Any opinions?

On Thu, Jun 14, 2018 at 12:34 PM <yla...@apache.org> wrote:
>
> Author: ylavic
> Date: Thu Jun 14 16:34:49 2018
> New Revision: 1833525
>
> URL: http://svn.apache.org/viewvc?rev=1833525&view=rev
> Log:
> apr_crypto: follow up to r1833359: fix some root pool scopes (possible leaks).
>
> Keep the root pool scope for things that need it only (global lists of drivers
> or libs), but otherwise use the passed in pool (default/global PRNG, errors).
>
> This allows the caller to control the scope of initialization functions, and
> for instance be able to re-initialize when apr_crypto is unloaded/reloaded 
> from
> a DSO attached to the passed-in pool (e.g. mod_ssl in httpd).
>
>
> Modified:
>     apr/apr/trunk/crypto/apr_crypto.c
>     apr/apr/trunk/crypto/apr_crypto_internal.c
>     apr/apr/trunk/test/testcrypto.c
>     apr/apr/trunk/util-misc/apu_dso.c
>
> Modified: apr/apr/trunk/crypto/apr_crypto.c
> URL: 
> http://svn.apache.org/viewvc/apr/apr/trunk/crypto/apr_crypto.c?rev=1833525&r1=1833524&r2=1833525&view=diff
> ==============================================================================
> --- apr/apr/trunk/crypto/apr_crypto.c (original)
> +++ apr/apr/trunk/crypto/apr_crypto.c Thu Jun 14 16:34:49 2018
> @@ -37,8 +37,6 @@ static apr_hash_t *drivers = NULL;
>
>  #define ERROR_SIZE 1024
>
> -#define CLEANUP_CAST (apr_status_t (*)(void*))
> -
>  APR_TYPEDEF_STRUCT(apr_crypto_t,
>      apr_pool_t *pool;
>      apr_crypto_driver_t *provider;
> @@ -87,26 +85,29 @@ static apr_status_t apr_crypto_term(void
>  APR_DECLARE(apr_status_t) apr_crypto_init(apr_pool_t *pool)
>  {
>      apr_status_t rv;
> -    apr_pool_t *parent;
> +    apr_pool_t *rootp;
>      int flags = 0;
>
>      if (drivers != NULL) {
>          return APR_SUCCESS;
>      }
>
> -    /* Top level pool scope, need process-scope lifetime */
> -    for (parent = apr_pool_parent_get(pool);
> -         parent && parent != pool;
> -         parent = apr_pool_parent_get(pool))
> -        pool = parent;
> +    /* Top level pool scope, for drivers' process-scope lifetime */
> +    rootp = pool;
> +    for (;;) {
> +        apr_pool_t *p = apr_pool_parent_get(rootp);
> +        if (!p || p == rootp) {
> +            break;
> +        }
> +        rootp = p;
> +    }
>  #if APR_HAVE_MODULAR_DSO
>      /* deprecate in 2.0 - permit implicit initialization */
> -    apu_dso_init(pool);
> +    apu_dso_init(rootp);
>  #endif
> -    drivers = apr_hash_make(pool);
> -
> -    apr_pool_cleanup_register(pool, NULL, apr_crypto_term,
> -            apr_pool_cleanup_null);
> +    drivers = apr_hash_make(rootp);
> +    apr_pool_cleanup_register(rootp, NULL, apr_crypto_term,
> +                              apr_pool_cleanup_null);
>
>      /* apr_crypto_prng_init() may already have been called with
>       * non-default parameters, so ignore APR_EREINIT.
> @@ -203,6 +204,7 @@ APR_DECLARE(apr_status_t) apr_crypto_get
>      char symname[34];
>      apr_dso_handle_t *dso;
>      apr_dso_handle_sym_t symbol;
> +    apr_pool_t *rootp;
>  #endif
>      apr_status_t rv;
>
> @@ -227,7 +229,7 @@ APR_DECLARE(apr_status_t) apr_crypto_get
>  #if APR_HAVE_MODULAR_DSO
>      /* The driver DSO must have exactly the same lifetime as the
>       * drivers hash table; ignore the passed-in pool */
> -    pool = apr_hash_pool_get(drivers);
> +    rootp = apr_hash_pool_get(drivers);
>
>  #if defined(NETWARE)
>      apr_snprintf(modname, sizeof(modname), "crypto%s.nlm", name);
> @@ -239,21 +241,19 @@ APR_DECLARE(apr_status_t) apr_crypto_get
>              "apr_crypto_%s-" APR_STRINGIFY(APR_MAJOR_VERSION) ".so", name);
>  #endif
>      apr_snprintf(symname, sizeof(symname), "apr_crypto_%s_driver", name);
> -    rv = apu_dso_load(&dso, &symbol, modname, symname, pool);
> +    rv = apu_dso_load(&dso, &symbol, modname, symname, rootp);
>      if (rv == APR_SUCCESS || rv == APR_EINIT) { /* previously loaded?!? */
>          apr_crypto_driver_t *d = symbol;
>          rv = APR_SUCCESS;
>          if (d->init) {
> -            rv = d->init(pool, params, result);
> +            rv = d->init(rootp, params, result);
>              if (rv == APR_EREINIT) {
>                  rv = APR_SUCCESS;
>              }
>          }
>          if (rv == APR_SUCCESS) {
> -            *driver = symbol;
> -            name = apr_pstrdup(pool, name);
> -            apr_hash_set(drivers, name, APR_HASH_KEY_STRING, *driver);
> -            rv = APR_SUCCESS;
> +            apr_hash_set(drivers, d->name, APR_HASH_KEY_STRING, d);
> +            *driver = d;
>          }
>      }
>      apu_dso_mutex_unlock();
> @@ -274,32 +274,38 @@ APR_DECLARE(apr_status_t) apr_crypto_get
>
>      /* Load statically-linked drivers: */
>  #if APU_HAVE_OPENSSL
> -    if (name[0] == 'o' && !strcmp(name, "openssl")) {
> +    if (!strcmp(name, "openssl")) {
>          DRIVER_LOAD("openssl", apr_crypto_openssl_driver, pool, params, rv, 
> result);
>      }
> +    else
>  #endif
>  #if APU_HAVE_NSS
> -    if (name[0] == 'n' && !strcmp(name, "nss")) {
> +    if (!strcmp(name, "nss")) {
>          DRIVER_LOAD("nss", apr_crypto_nss_driver, pool, params, rv, result);
>      }
> +    else
>  #endif
>  #if APU_HAVE_COMMONCRYPTO
> -    if (name[0] == 'c' && !strcmp(name, "commoncrypto")) {
> +    if (!strcmp(name, "commoncrypto")) {
>          DRIVER_LOAD("commoncrypto", apr_crypto_commoncrypto_driver, pool, 
> params, rv, result);
>      }
> +    else
>  #endif
>  #if APU_HAVE_MSCAPI
> -    if (name[0] == 'm' && !strcmp(name, "mscapi")) {
> +    if (!strcmp(name, "mscapi")) {
>          DRIVER_LOAD("mscapi", apr_crypto_mscapi_driver, pool, params, rv, 
> result);
>      }
> +    else
>  #endif
>  #if APU_HAVE_MSCNG
> -    if (name[0] == 'm' && !strcmp(name, "mscng")) {
> +    if (!strcmp(name, "mscng")) {
>          DRIVER_LOAD("mscng", apr_crypto_mscng_driver, pool, params, rv, 
> result);
>      }
> +    else
>  #endif
> +    ;
>
> -#endif
> +#endif /* !APR_HAVE_MODULAR_DSO */
>
>      return rv;
>  }
> @@ -407,7 +413,7 @@ APR_DECLARE(apr_status_t) apr_crypto_lib
>                                                apr_pool_t *pool)
>  {
>      apr_status_t rv;
> -    apr_pool_t *rootp, *p;
> +    apr_pool_t *rootp;
>      struct crypto_lib *lib;
>
>      if (!name) {
> @@ -419,7 +425,11 @@ APR_DECLARE(apr_status_t) apr_crypto_lib
>      }
>
>      rootp = pool;
> -    while ((p = apr_pool_parent_get(rootp))) {
> +    for (;;) {
> +        apr_pool_t *p = apr_pool_parent_get(rootp);
> +        if (!p || p == rootp) {
> +            break;
> +        }
>          rootp = p;
>      }
>
> @@ -495,8 +505,10 @@ APR_DECLARE(apr_status_t) apr_crypto_lib
>      if (rv == APR_SUCCESS) {
>          lib->pool = pool;
>          apr_hash_set(active_libs, lib->name, APR_HASH_KEY_STRING, lib);
> -        apr_pool_cleanup_register(lib->pool, lib, crypto_lib_cleanup,
> -                                  apr_pool_cleanup_null);
> +        if (apr_pool_parent_get(pool)) {
> +            apr_pool_cleanup_register(pool, lib, crypto_lib_cleanup,
> +                                      apr_pool_cleanup_null);
> +        }
>      }
>      else {
>          spare_lib_push(lib);
> @@ -513,6 +525,9 @@ static apr_status_t crypto_lib_term(cons
>      if (!lib) {
>          return APR_EINIT;
>      }
> +    if (!apr_pool_parent_get(lib->pool)) {
> +        return APR_EBUSY;
> +    }
>
>      rv = APR_ENOTIMPL;
>  #if APU_HAVE_OPENSSL
> @@ -560,12 +575,15 @@ APR_DECLARE(apr_status_t) apr_crypto_lib
>      }
>
>      if (!name) {
> +        apr_status_t rv = APR_SUCCESS;
>          apr_hash_index_t *hi = apr_hash_first(NULL, active_libs);
>          for (; hi; hi = apr_hash_next(hi)) {
> -            name = apr_hash_this_key(hi);
> -            crypto_lib_term(name);
> +            apr_status_t rt = crypto_lib_term(apr_hash_this_key(hi));
> +            if (rt != APR_SUCCESS && (rv == APR_SUCCESS || rv == APR_EBUSY)) 
> {
> +                rv = rt;
> +            }
>          }
> -        return APR_SUCCESS;
> +        return rv;
>      }
>
>      return crypto_lib_term(name);
>
> Modified: apr/apr/trunk/crypto/apr_crypto_internal.c
> URL: 
> http://svn.apache.org/viewvc/apr/apr/trunk/crypto/apr_crypto_internal.c?rev=1833525&r1=1833524&r2=1833525&view=diff
> ==============================================================================
> --- apr/apr/trunk/crypto/apr_crypto_internal.c (original)
> +++ apr/apr/trunk/crypto/apr_crypto_internal.c Thu Jun 14 16:34:49 2018
> @@ -284,8 +284,8 @@ const char *apr__crypto_mscng_version(vo
>  }
>
>  apr_status_t apr__crypto_mscng_init(const char *params,
> -                                           const apu_err_t **result,
> -                                           apr_pool_t *pool)
> +                                    const apu_err_t **result,
> +                                    apr_pool_t *pool)
>  {
>      return APR_ENOTIMPL;
>  }
>
> Modified: apr/apr/trunk/test/testcrypto.c
> URL: 
> http://svn.apache.org/viewvc/apr/apr/trunk/test/testcrypto.c?rev=1833525&r1=1833524&r2=1833525&view=diff
> ==============================================================================
> --- apr/apr/trunk/test/testcrypto.c (original)
> +++ apr/apr/trunk/test/testcrypto.c Thu Jun 14 16:34:49 2018
> @@ -559,7 +559,10 @@ static void test_crypto_init(abts_case *
>
>      apr_pool_create(&pool, NULL);
>
> -    rv = apr_crypto_init(pool);
> +    /* Use root pool (top level init) so that the crypto lib is
> +     * not cleanup on pool destroy below (e.g. openssl can't re-init).
> +     */
> +    rv = apr_crypto_init(apr_pool_parent_get(pool));
>      ABTS_ASSERT(tc, "failed to init apr_crypto", rv == APR_SUCCESS);
>
>      apr_pool_destroy(pool);
> @@ -1680,7 +1683,7 @@ abts_suite *testcrypto(abts_suite *suite
>  {
>      suite = ADD_SUITE(suite);
>
> -    /* test simple init and shutdown */
> +    /* test simple init and shutdown (keep first) */
>      abts_run_test(suite, test_crypto_init, NULL);
>
>      /* test key parsing - openssl */
>
> Modified: apr/apr/trunk/util-misc/apu_dso.c
> URL: 
> http://svn.apache.org/viewvc/apr/apr/trunk/util-misc/apu_dso.c?rev=1833525&r1=1833524&r2=1833525&view=diff
> ==============================================================================
> --- apr/apr/trunk/util-misc/apu_dso.c (original)
> +++ apr/apr/trunk/util-misc/apu_dso.c Thu Jun 14 16:34:49 2018
> @@ -106,6 +106,11 @@ apr_status_t apu_dso_init(apr_pool_t *po
>      return ret;
>  }
>
> +struct dso_entry {
> +    apr_dso_handle_t *handle;
> +    apr_dso_handle_sym_t *sym;
> +};
> +
>  apr_status_t apu_dso_load(apr_dso_handle_t **dlhandleptr,
>                            apr_dso_handle_sym_t *dsoptr,
>                            const char *module,
> @@ -118,11 +123,14 @@ apr_status_t apu_dso_load(apr_dso_handle
>      apr_array_header_t *paths;
>      apr_pool_t *global;
>      apr_status_t rv = APR_EDSOOPEN;
> +    struct dso_entry *entry;
>      char *eos = NULL;
>      int i;
>
> -    *dsoptr = apr_hash_get(dsos, module, APR_HASH_KEY_STRING);
> -    if (*dsoptr) {
> +    entry = apr_hash_get(dsos, module, APR_HASH_KEY_STRING);
> +    if (entry) {
> +        *dlhandleptr = entry->handle;
> +        *dsoptr = entry->sym;
>          return APR_EINIT;
>      }
>
> @@ -199,7 +207,10 @@ apr_status_t apu_dso_load(apr_dso_handle
>      }
>      else {
>          module = apr_pstrdup(global, module);
> -        apr_hash_set(dsos, module, APR_HASH_KEY_STRING, *dsoptr);
> +        entry = apr_palloc(global, sizeof(*entry));
> +        entry->handle = dlhandle;
> +        entry->sym = *dsoptr;
> +        apr_hash_set(dsos, module, APR_HASH_KEY_STRING, entry);
>      }
>      return rv;
>  }
>
>


--
Eric Covener
cove...@gmail.com

Reply via email to