Index: patches.chromium/0006-fix_lhash_iteration.patch |
diff --git a/patches.chromium/0006-fix_lhash_iteration.patch b/patches.chromium/0006-fix_lhash_iteration.patch |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c00b60acc997fab9952d19ff21a869a86407fe8c |
--- /dev/null |
+++ b/patches.chromium/0006-fix_lhash_iteration.patch |
@@ -0,0 +1,320 @@ |
+diff -burN android-openssl.org/openssl.config android-openssl/openssl.config |
+--- android-openssl.org/openssl.config 2013-11-05 10:26:23.008411507 +0100 |
++++ android-openssl/openssl.config 2013-11-05 10:28:13.409668262 +0100 |
+@@ -997,6 +997,7 @@ |
+ fix_clang_build.patch \ |
+ x509_hash_name_algorithm_change.patch \ |
+ reduce_client_hello_size.patch \ |
++fix_lhash_iteration.patch \ |
+ " |
+ |
+ OPENSSL_PATCHES_progs_SOURCES="\ |
+@@ -1060,3 +1061,13 @@ |
+ OPENSSL_PATCHES_reduce_client_hello_size_SOURCES="\ |
+ ssl/t1_lib.c \ |
+ " |
++ |
++OPENSSL_PATCHES_fix_lhash_iteration_SOURCES="\ |
++crypto/conf/conf_api.c |
++crypto/lhash/lhash.c |
++crypto/lhash/lhash.h |
++crypto/objects/o_names.c |
++crypto/objects/obj_dat.c |
++include/openssl/lhash.h |
++ssl/ssl_sess.c |
++" |
+diff -burN android-openssl.org/patches/fix_lhash_iteration.patch android-openssl/patches/fix_lhash_iteration.patch |
+--- android-openssl.org/patches/fix_lhash_iteration.patch 1970-01-01 01:00:00.000000000 +0100 |
++++ android-openssl/patches/fix_lhash_iteration.patch 2013-11-05 10:26:40.678612658 +0100 |
+@@ -0,0 +1,291 @@ |
++diff --git a/crypto/conf/conf_api.c b/crypto/conf/conf_api.c |
++index f5fcbb9..9a37bd4 100644 |
++--- a/crypto/conf/conf_api.c |
+++++ b/crypto/conf/conf_api.c |
++@@ -225,9 +225,6 @@ void _CONF_free_data(CONF *conf) |
++ { |
++ if (conf == NULL || conf->data == NULL) return; |
++ |
++- lh_CONF_VALUE_down_load(conf->data)=0; /* evil thing to make |
++- * sure the 'OPENSSL_free()' works as |
++- * expected */ |
++ lh_CONF_VALUE_doall_arg(conf->data, |
++ LHASH_DOALL_ARG_FN(value_free_hash), |
++ LHASH_OF(CONF_VALUE), conf->data); |
++diff --git a/crypto/lhash/lhash.c b/crypto/lhash/lhash.c |
++index 47f7480..e5b3cdf 100644 |
++--- a/crypto/lhash/lhash.c |
+++++ b/crypto/lhash/lhash.c |
++@@ -94,6 +94,7 @@ |
++ * |
++ * 1.0 eay - First version |
++ */ |
+++#include <limits.h> |
++ #include <stdio.h> |
++ #include <string.h> |
++ #include <stdlib.h> |
++@@ -107,6 +108,113 @@ const char lh_version[]="lhash" OPENSSL_VERSION_PTEXT; |
++ #define UP_LOAD (2*LH_LOAD_MULT) /* load times 256 (default 2) */ |
++ #define DOWN_LOAD (LH_LOAD_MULT) /* load times 256 (default 1) */ |
++ |
+++/* Maximum number of nodes to guarantee the load computations don't overflow */ |
+++#define MAX_LOAD_ITEMS (UINT_MAX / LH_LOAD_MULT) |
+++ |
+++/* The field 'iteration_state' is used to hold data to ensure that a hash |
+++ * table is not resized during an 'insert' or 'delete' operation performed |
+++ * within a lh_doall/lh_doall_arg call. |
+++ * |
+++ * Conceptually, this records two things: |
+++ * |
+++ * - A 'depth' count, which is incremented at the start of lh_doall*, |
+++ * and decremented just before it returns. |
+++ * |
+++ * - A 'mutated' boolean flag, which is set in lh_insert() or lh_delete() |
+++ * when the operation is performed with a non-0 depth. |
+++ * |
+++ * The following are helper macros to handle this state in a more explicit |
+++ * way. |
+++ */ |
+++ |
+++/* Reset the iteration state to its defaults. */ |
+++#define LH_ITERATION_RESET(lh) do { \ |
+++ (lh)->iteration_state = 0; \ |
+++ } while (0) |
+++ |
+++/* Returns 1 if the hash table is currently being iterated on, 0 otherwise. */ |
+++#define LH_ITERATION_IS_ACTIVE(lh) ((lh)->iteration_state >= 2) |
+++ |
+++/* Increment iteration depth. This should always be followed by a paired call |
+++ * to LH_ITERATION_DECREMENT_DEPTH(). */ |
+++#define LH_ITERATION_INCREMENT_DEPTH(lh) do { \ |
+++ (lh)->iteration_state += 2; \ |
+++ } while (0) |
+++ |
+++/* Decrement iteration depth. This should always be called after a paired call |
+++ * to LH_ITERATION_INCREMENT_DEPTH(). */ |
+++#define LH_ITERATION_DECREMENT_DEPTH(lh) do { \ |
+++ (lh)->iteration_state -= 2; \ |
+++ } while (0) |
+++ |
+++/* Return 1 if the iteration 'mutated' flag is set, 0 otherwise. */ |
+++#define LH_ITERATION_IS_MUTATED(lh) (((lh)->iteration_state & 1) != 0) |
+++ |
+++/* Set the iteration 'mutated' flag to 1. LH_ITERATION_RESET() to reset it. */ |
+++#define LH_ITERATION_SET_MUTATED(lh) do { \ |
+++ (lh)->iteration_state |= 1; \ |
+++ } while (0) |
+++ |
+++/* This macro returns 1 if the hash table should be expanded due to its current |
+++ * load, or 0 otherwise. The exact comparison to be performed is expressed by |
+++ * the mathematical expression (where '//' denotes division over real numbers): |
+++ * |
+++ * (num_items // num_nodes) >= (up_load // LOAD_MULT) or |
+++ * (num_items * LOAD_MULT // num_nodes) >= up_load. |
+++ * |
+++ * Given that the C language operator '/' implements integer division, i.e: |
+++ * a // b == (a / b) + epsilon (with 0 <= epsilon < 1, for positive a & b) |
+++ * |
+++ * This can be rewritten as: |
+++ * (num_items * LOAD_MULT / num_nodes) + epsilon >= up_load |
+++ * (num_items * LOAD_MULT / num_nodes) - up_load >= - epsilon |
+++ * |
+++ * Let's call 'A' the left-hand side of the equation above, it is an integer |
+++ * and: |
+++ * - If A >= 0, the expression is true for any value of epsilon. |
+++ * - If A <= -1, the expression is also true for any value of epsilon. |
+++ * |
+++ * In other words, this is equivalent to 'A >= 0', or: |
+++ * (num_items * LOAD_MULT / num_nodes) >= up_load |
+++ */ |
+++#define LH_SHOULD_EXPAND(lh) \ |
+++ ((lh)->num_items < MAX_LOAD_ITEMS && \ |
+++ (((lh)->num_items*LH_LOAD_MULT/(lh)->num_nodes) >= (lh)->up_load)) |
+++ |
+++/* This macro returns 1 if the hash table should be contracted due to its |
+++ * current load, or 0 otherwise. Abbreviated computations are: |
+++ * |
+++ * (num_items // num_nodes) <= (down_load // LOAD_MULT) |
+++ * (num_items * LOAD_MULT // num_nodes) <= down_load |
+++ * (num_items * LOAD_MULT / num_nodes) + epsilon <= down_load |
+++ * (num_items * LOAD_MULT / num_nodes) - down_load <= -epsilon |
+++ * |
+++ * Let's call 'B' the left-hand side of the equation above: |
+++ * - If B <= -1, the expression is true for any value of epsilon. |
+++ * - If B >= 1, the expression is false for any value of epsilon. |
+++ * - If B == 0, the expression is true for 'epsilon == 0', and false |
+++ * otherwise, which is problematic. |
+++ * |
+++ * To work around this problem, while keeping the code simple, just change |
+++ * the initial expression to use a strict inequality, i.e.: |
+++ * |
+++ * (num_items // num_nodes) < (down_load // LOAD_MULT) |
+++ * |
+++ * Which leads to: |
+++ * (num_items * LOAD_MULT / num_nodes) - down_load < -epsilon |
+++ * |
+++ * Then: |
+++ * - If 'B <= -1', the expression is true for any value of epsilon. |
+++ * - If 'B' >= 0, the expression is false for any value of epsilon, |
+++ * |
+++ * In other words, this is equivalent to 'B < 0', or: |
+++ * (num_items * LOAD_MULT / num_nodes) < down_load |
+++ */ |
+++#define LH_SHOULD_CONTRACT(lh) \ |
+++ (((lh)->num_nodes > MIN_NODES) && \ |
+++ ((lh)->num_items < MAX_LOAD_ITEMS && \ |
+++ ((lh)->num_items*LH_LOAD_MULT/(lh)->num_nodes) < (lh)->down_load)) |
+++ |
++ static void expand(_LHASH *lh); |
++ static void contract(_LHASH *lh); |
++ static LHASH_NODE **getrn(_LHASH *lh, const void *data, unsigned long *rhash); |
++@@ -147,6 +255,7 @@ _LHASH *lh_new(LHASH_HASH_FN_TYPE h, LHASH_COMP_FN_TYPE c) |
++ ret->num_hash_comps=0; |
++ |
++ ret->error=0; |
+++ LH_ITERATION_RESET(ret); |
++ return(ret); |
++ err1: |
++ OPENSSL_free(ret); |
++@@ -183,7 +292,10 @@ void *lh_insert(_LHASH *lh, void *data) |
++ void *ret; |
++ |
++ lh->error=0; |
++- if (lh->up_load <= (lh->num_items*LH_LOAD_MULT/lh->num_nodes)) |
+++ /* Do not expand the array if the table is being iterated on. */ |
+++ if (LH_ITERATION_IS_ACTIVE(lh)) |
+++ LH_ITERATION_SET_MUTATED(lh); |
+++ else if (LH_SHOULD_EXPAND(lh)) |
++ expand(lh); |
++ |
++ rn=getrn(lh,data,&hash); |
++@@ -238,8 +350,10 @@ void *lh_delete(_LHASH *lh, const void *data) |
++ } |
++ |
++ lh->num_items--; |
++- if ((lh->num_nodes > MIN_NODES) && |
++- (lh->down_load >= (lh->num_items*LH_LOAD_MULT/lh->num_nodes))) |
+++ /* Do not contract the array if the table is being iterated on. */ |
+++ if (LH_ITERATION_IS_ACTIVE(lh)) |
+++ LH_ITERATION_SET_MUTATED(lh); |
+++ else if (LH_SHOULD_CONTRACT(lh)) |
++ contract(lh); |
++ |
++ return(ret); |
++@@ -276,6 +390,7 @@ static void doall_util_fn(_LHASH *lh, int use_arg, LHASH_DOALL_FN_TYPE func, |
++ if (lh == NULL) |
++ return; |
++ |
+++ LH_ITERATION_INCREMENT_DEPTH(lh); |
++ /* reverse the order so we search from 'top to bottom' |
++ * We were having memory leaks otherwise */ |
++ for (i=lh->num_nodes-1; i>=0; i--) |
++@@ -283,10 +398,7 @@ static void doall_util_fn(_LHASH *lh, int use_arg, LHASH_DOALL_FN_TYPE func, |
++ a=lh->b[i]; |
++ while (a != NULL) |
++ { |
++- /* 28/05/91 - eay - n added so items can be deleted |
++- * via lh_doall */ |
++- /* 22/05/08 - ben - eh? since a is not passed, |
++- * this should not be needed */ |
+++ /* note that 'a' can be deleted by the callback */ |
++ n=a->next; |
++ if(use_arg) |
++ func_arg(a->data,arg); |
++@@ -295,6 +407,19 @@ static void doall_util_fn(_LHASH *lh, int use_arg, LHASH_DOALL_FN_TYPE func, |
++ a=n; |
++ } |
++ } |
+++ |
+++ LH_ITERATION_DECREMENT_DEPTH(lh); |
+++ if (!LH_ITERATION_IS_ACTIVE(lh) && LH_ITERATION_IS_MUTATED(lh)) |
+++ { |
+++ LH_ITERATION_RESET(lh); |
+++ /* Resize the buckets array if necessary. Each expand() or |
+++ * contract() call will double/halve the size of the array, |
+++ * respectively, so call them in a loop. */ |
+++ while (LH_SHOULD_EXPAND(lh)) |
+++ expand(lh); |
+++ while (LH_SHOULD_CONTRACT(lh)) |
+++ contract(lh); |
+++ } |
++ } |
++ |
++ void lh_doall(_LHASH *lh, LHASH_DOALL_FN_TYPE func) |
++diff --git a/crypto/lhash/lhash.h b/crypto/lhash/lhash.h |
++index e7d8763..75386f2 100644 |
++--- a/crypto/lhash/lhash.h |
+++++ b/crypto/lhash/lhash.h |
++@@ -163,6 +163,7 @@ typedef struct lhash_st |
++ unsigned long num_hash_comps; |
++ |
++ int error; |
+++ int iteration_state; |
++ } _LHASH; /* Do not use _LHASH directly, use LHASH_OF |
++ * and friends */ |
++ |
++diff --git a/crypto/objects/o_names.c b/crypto/objects/o_names.c |
++index 4a548c2..4e18045 100644 |
++--- a/crypto/objects/o_names.c |
+++++ b/crypto/objects/o_names.c |
++@@ -350,13 +350,9 @@ static void name_funcs_free(NAME_FUNCS *ptr) |
++ |
++ void OBJ_NAME_cleanup(int type) |
++ { |
++- unsigned long down_load; |
++- |
++ if (names_lh == NULL) return; |
++ |
++ free_type=type; |
++- down_load=lh_OBJ_NAME_down_load(names_lh); |
++- lh_OBJ_NAME_down_load(names_lh)=0; |
++ |
++ lh_OBJ_NAME_doall(names_lh,LHASH_DOALL_FN(names_lh_free)); |
++ if (type < 0) |
++@@ -366,7 +362,5 @@ void OBJ_NAME_cleanup(int type) |
++ names_lh=NULL; |
++ name_funcs_stack = NULL; |
++ } |
++- else |
++- lh_OBJ_NAME_down_load(names_lh)=down_load; |
++ } |
++ |
++diff --git a/crypto/objects/obj_dat.c b/crypto/objects/obj_dat.c |
++index 8a342ba..ef0512a 100644 |
++--- a/crypto/objects/obj_dat.c |
+++++ b/crypto/objects/obj_dat.c |
++@@ -227,7 +227,6 @@ void OBJ_cleanup(void) |
++ return ; |
++ } |
++ if (added == NULL) return; |
++- lh_ADDED_OBJ_down_load(added) = 0; |
++ lh_ADDED_OBJ_doall(added,LHASH_DOALL_FN(cleanup1)); /* zero counters */ |
++ lh_ADDED_OBJ_doall(added,LHASH_DOALL_FN(cleanup2)); /* set counters */ |
++ lh_ADDED_OBJ_doall(added,LHASH_DOALL_FN(cleanup3)); /* free objects */ |
++diff --git a/include/openssl/lhash.h b/include/openssl/lhash.h |
++index e7d8763..75386f2 100644 |
++--- a/include/openssl/lhash.h |
+++++ b/include/openssl/lhash.h |
++@@ -163,6 +163,7 @@ typedef struct lhash_st |
++ unsigned long num_hash_comps; |
++ |
++ int error; |
+++ int iteration_state; |
++ } _LHASH; /* Do not use _LHASH directly, use LHASH_OF |
++ * and friends */ |
++ |
++diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c |
++index 920b763..447a37e 100644 |
++--- a/ssl/ssl_sess.c |
+++++ b/ssl/ssl_sess.c |
++@@ -999,11 +999,8 @@ void SSL_CTX_flush_sessions(SSL_CTX *s, long t) |
++ if (tp.cache == NULL) return; |
++ tp.time=t; |
++ CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); |
++- i=CHECKED_LHASH_OF(SSL_SESSION, tp.cache)->down_load; |
++- CHECKED_LHASH_OF(SSL_SESSION, tp.cache)->down_load=0; |
++ lh_SSL_SESSION_doall_arg(tp.cache, LHASH_DOALL_ARG_FN(timeout), |
++ TIMEOUT_PARAM, &tp); |
++- CHECKED_LHASH_OF(SSL_SESSION, tp.cache)->down_load=i; |
++ CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); |
++ } |
++ |