openssh-7.3_p1-hpn-cipher-ctr-mt-no-deadlocks.patch 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. diff --git a/cipher-ctr-mt.c b/cipher-ctr-mt.c
  2. index fdc9b2f..300cd90 100644
  3. --- a/cipher-ctr-mt.c
  4. +++ b/cipher-ctr-mt.c
  5. @@ -127,7 +127,7 @@ struct kq {
  6. u_char keys[KQLEN][AES_BLOCK_SIZE];
  7. u_char ctr[AES_BLOCK_SIZE];
  8. u_char pad0[CACHELINE_LEN];
  9. - volatile int qstate;
  10. + int qstate;
  11. pthread_mutex_t lock;
  12. pthread_cond_t cond;
  13. u_char pad1[CACHELINE_LEN];
  14. @@ -141,6 +141,11 @@ struct ssh_aes_ctr_ctx
  15. STATS_STRUCT(stats);
  16. u_char aes_counter[AES_BLOCK_SIZE];
  17. pthread_t tid[CIPHER_THREADS];
  18. + pthread_rwlock_t tid_lock;
  19. +#ifdef __APPLE__
  20. + pthread_rwlock_t stop_lock;
  21. + int exit_flag;
  22. +#endif /* __APPLE__ */
  23. int state;
  24. int qidx;
  25. int ridx;
  26. @@ -187,6 +192,57 @@ thread_loop_cleanup(void *x)
  27. pthread_mutex_unlock((pthread_mutex_t *)x);
  28. }
  29. +#ifdef __APPLE__
  30. +/* Check if we should exit, we are doing both cancel and exit condition
  31. + * since on OSX threads seem to occasionally fail to notice when they have
  32. + * been cancelled. We want to have a backup to make sure that we won't hang
  33. + * when the main process join()-s the cancelled thread.
  34. + */
  35. +static void
  36. +thread_loop_check_exit(struct ssh_aes_ctr_ctx *c)
  37. +{
  38. + int exit_flag;
  39. +
  40. + pthread_rwlock_rdlock(&c->stop_lock);
  41. + exit_flag = c->exit_flag;
  42. + pthread_rwlock_unlock(&c->stop_lock);
  43. +
  44. + if (exit_flag)
  45. + pthread_exit(NULL);
  46. +}
  47. +#else
  48. +# define thread_loop_check_exit(s)
  49. +#endif /* __APPLE__ */
  50. +
  51. +/*
  52. + * Helper function to terminate the helper threads
  53. + */
  54. +static void
  55. +stop_and_join_pregen_threads(struct ssh_aes_ctr_ctx *c)
  56. +{
  57. + int i;
  58. +
  59. +#ifdef __APPLE__
  60. + /* notify threads that they should exit */
  61. + pthread_rwlock_wrlock(&c->stop_lock);
  62. + c->exit_flag = TRUE;
  63. + pthread_rwlock_unlock(&c->stop_lock);
  64. +#endif /* __APPLE__ */
  65. +
  66. + /* Cancel pregen threads */
  67. + for (i = 0; i < CIPHER_THREADS; i++) {
  68. + pthread_cancel(c->tid[i]);
  69. + }
  70. + for (i = 0; i < NUMKQ; i++) {
  71. + pthread_mutex_lock(&c->q[i].lock);
  72. + pthread_cond_broadcast(&c->q[i].cond);
  73. + pthread_mutex_unlock(&c->q[i].lock);
  74. + }
  75. + for (i = 0; i < CIPHER_THREADS; i++) {
  76. + pthread_join(c->tid[i], NULL);
  77. + }
  78. +}
  79. +
  80. /*
  81. * The life of a pregen thread:
  82. * Find empty keystream queues and fill them using their counter.
  83. @@ -201,6 +257,7 @@ thread_loop(void *x)
  84. struct kq *q;
  85. int i;
  86. int qidx;
  87. + pthread_t first_tid;
  88. /* Threads stats on cancellation */
  89. STATS_INIT(stats);
  90. @@ -211,11 +268,15 @@ thread_loop(void *x)
  91. /* Thread local copy of AES key */
  92. memcpy(&key, &c->aes_ctx, sizeof(key));
  93. + pthread_rwlock_rdlock(&c->tid_lock);
  94. + first_tid = c->tid[0];
  95. + pthread_rwlock_unlock(&c->tid_lock);
  96. +
  97. /*
  98. * Handle the special case of startup, one thread must fill
  99. * the first KQ then mark it as draining. Lock held throughout.
  100. */
  101. - if (pthread_equal(pthread_self(), c->tid[0])) {
  102. + if (pthread_equal(pthread_self(), first_tid)) {
  103. q = &c->q[0];
  104. pthread_mutex_lock(&q->lock);
  105. if (q->qstate == KQINIT) {
  106. @@ -245,12 +306,16 @@ thread_loop(void *x)
  107. /* Check if I was cancelled, also checked in cond_wait */
  108. pthread_testcancel();
  109. + /* Check if we should exit as well */
  110. + thread_loop_check_exit(c);
  111. +
  112. /* Lock queue and block if its draining */
  113. q = &c->q[qidx];
  114. pthread_mutex_lock(&q->lock);
  115. pthread_cleanup_push(thread_loop_cleanup, &q->lock);
  116. while (q->qstate == KQDRAINING || q->qstate == KQINIT) {
  117. STATS_WAIT(stats);
  118. + thread_loop_check_exit(c);
  119. pthread_cond_wait(&q->cond, &q->lock);
  120. }
  121. pthread_cleanup_pop(0);
  122. @@ -268,6 +333,7 @@ thread_loop(void *x)
  123. * can see that it's being filled.
  124. */
  125. q->qstate = KQFILLING;
  126. + pthread_cond_broadcast(&q->cond);
  127. pthread_mutex_unlock(&q->lock);
  128. for (i = 0; i < KQLEN; i++) {
  129. AES_encrypt(q->ctr, q->keys[i], &key);
  130. @@ -279,7 +345,7 @@ thread_loop(void *x)
  131. ssh_ctr_add(q->ctr, KQLEN * (NUMKQ - 1), AES_BLOCK_SIZE);
  132. q->qstate = KQFULL;
  133. STATS_FILL(stats);
  134. - pthread_cond_signal(&q->cond);
  135. + pthread_cond_broadcast(&q->cond);
  136. pthread_mutex_unlock(&q->lock);
  137. }
  138. @@ -371,6 +437,7 @@ ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src,
  139. pthread_cond_wait(&q->cond, &q->lock);
  140. }
  141. q->qstate = KQDRAINING;
  142. + pthread_cond_broadcast(&q->cond);
  143. pthread_mutex_unlock(&q->lock);
  144. /* Mark consumed queue empty and signal producers */
  145. @@ -397,6 +464,11 @@ ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
  146. if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
  147. c = xmalloc(sizeof(*c));
  148. + pthread_rwlock_init(&c->tid_lock, NULL);
  149. +#ifdef __APPLE__
  150. + pthread_rwlock_init(&c->stop_lock, NULL);
  151. + c->exit_flag = FALSE;
  152. +#endif /* __APPLE__ */
  153. c->state = HAVE_NONE;
  154. for (i = 0; i < NUMKQ; i++) {
  155. @@ -409,11 +481,14 @@ ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
  156. }
  157. if (c->state == (HAVE_KEY | HAVE_IV)) {
  158. - /* Cancel pregen threads */
  159. - for (i = 0; i < CIPHER_THREADS; i++)
  160. - pthread_cancel(c->tid[i]);
  161. - for (i = 0; i < CIPHER_THREADS; i++)
  162. - pthread_join(c->tid[i], NULL);
  163. + /* tell the pregen threads to exit */
  164. + stop_and_join_pregen_threads(c);
  165. +
  166. +#ifdef __APPLE__
  167. + /* reset the exit flag */
  168. + c->exit_flag = FALSE;
  169. +#endif /* __APPLE__ */
  170. +
  171. /* Start over getting key & iv */
  172. c->state = HAVE_NONE;
  173. }
  174. @@ -444,10 +519,12 @@ ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
  175. /* Start threads */
  176. for (i = 0; i < CIPHER_THREADS; i++) {
  177. debug("spawned a thread");
  178. + pthread_rwlock_wrlock(&c->tid_lock);
  179. pthread_create(&c->tid[i], NULL, thread_loop, c);
  180. + pthread_rwlock_unlock(&c->tid_lock);
  181. }
  182. pthread_mutex_lock(&c->q[0].lock);
  183. - while (c->q[0].qstate != KQDRAINING)
  184. + while (c->q[0].qstate == KQINIT)
  185. pthread_cond_wait(&c->q[0].cond, &c->q[0].lock);
  186. pthread_mutex_unlock(&c->q[0].lock);
  187. }
  188. @@ -461,15 +538,10 @@ void
  189. ssh_aes_ctr_thread_destroy(EVP_CIPHER_CTX *ctx)
  190. {
  191. struct ssh_aes_ctr_ctx *c;
  192. - int i;
  193. +
  194. c = EVP_CIPHER_CTX_get_app_data(ctx);
  195. - /* destroy threads */
  196. - for (i = 0; i < CIPHER_THREADS; i++) {
  197. - pthread_cancel(c->tid[i]);
  198. - }
  199. - for (i = 0; i < CIPHER_THREADS; i++) {
  200. - pthread_join(c->tid[i], NULL);
  201. - }
  202. +
  203. + stop_and_join_pregen_threads(c);
  204. }
  205. void
  206. @@ -481,7 +553,9 @@ ssh_aes_ctr_thread_reconstruction(EVP_CIPHER_CTX *ctx)
  207. /* reconstruct threads */
  208. for (i = 0; i < CIPHER_THREADS; i++) {
  209. debug("spawned a thread");
  210. + pthread_rwlock_wrlock(&c->tid_lock);
  211. pthread_create(&c->tid[i], NULL, thread_loop, c);
  212. + pthread_rwlock_unlock(&c->tid_lock);
  213. }
  214. }
  215. @@ -489,18 +563,13 @@ static int
  216. ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx)
  217. {
  218. struct ssh_aes_ctr_ctx *c;
  219. - int i;
  220. if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
  221. #ifdef CIPHER_THREAD_STATS
  222. debug("main thread: %u drains, %u waits", c->stats.drains,
  223. c->stats.waits);
  224. #endif
  225. - /* Cancel pregen threads */
  226. - for (i = 0; i < CIPHER_THREADS; i++)
  227. - pthread_cancel(c->tid[i]);
  228. - for (i = 0; i < CIPHER_THREADS; i++)
  229. - pthread_join(c->tid[i], NULL);
  230. + stop_and_join_pregen_threads(c);
  231. memset(c, 0, sizeof(*c));
  232. free(c);