You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

268 lines
9.6 KiB

  1. From bf583640ff69104e228b5f04e149b800ebc9e7d8 Mon Sep 17 00:00:00 2001
  2. From: Thierry FOURNIER <thierry.fournier@ozon.io>
  3. Date: Tue, 13 Dec 2016 13:06:23 +0100
  4. Subject: [PATCH 01/19] BUG/MEDIUM: lua: In some case, the return of
  5. sample-fetches is ignored (2)
  6. This problem is already detected here:
  7. 8dc7316a6fa8cc6f3a60456376c8a13a6902a5be
  8. Another case raises. Now HAProxy sends a final message (typically
  9. with "http-request deny"). Once the the message is sent, the response
  10. channel flags are not modified.
  11. HAProxy executes a Lua sample-fecthes for building logs, and the
  12. result is ignored because the response flag remains set to the value
  13. HTTP_MSG_RPBEFORE. So the Lua function hlua_check_proto() want to
  14. guarantee the valid state of the buffer and ask for aborting the
  15. request.
  16. The function check_proto() is not the good way to ensure request
  17. consistency. The real question is not "Are the message valid ?", but
  18. "Are the validity of message unchanged ?"
  19. This patch memorize the parser state before entering int the Lua
  20. code, and perform a check when it go out of the Lua code. If the parser
  21. state change for down, the request is aborted because the HTTP message
  22. is degraded.
  23. This patch should be backported in version 1.6 and 1.7
  24. (cherry picked from commit 11cfb3daecd789416103837001e30e9644b4c722)
  25. ---
  26. include/types/hlua.h | 17 ++++++++++
  27. src/hlua.c | 96 ++++++++++++++++++++++++++++++++++++----------------
  28. 2 files changed, 83 insertions(+), 30 deletions(-)
  29. diff --git a/include/types/hlua.h b/include/types/hlua.h
  30. index d2aaa4a..7a7c37f 100644
  31. --- a/include/types/hlua.h
  32. +++ b/include/types/hlua.h
  33. @@ -49,6 +49,22 @@ enum hlua_exec {
  34. HLUA_E_ERR, /* LUA stack execution failed without error message. */
  35. };
  36. +/* This struct is use for storing HAProxy parsers state
  37. + * before executing some Lua code. The goal is we can
  38. + * check and compare the parser state a the end of Lua
  39. + * execution. If the state is changed by Lua towards
  40. + * an unexpected state, we can abort the transaction.
  41. + */
  42. +struct hlua_consistency {
  43. + enum pr_mode mode;
  44. + union {
  45. + struct {
  46. + int dir;
  47. + enum ht_state state;
  48. + } http;
  49. + } data;
  50. +};
  51. +
  52. struct hlua {
  53. lua_State *T; /* The LUA stack. */
  54. int Tref; /* The reference of the stack in coroutine case.
  55. @@ -65,6 +81,7 @@ struct hlua {
  56. We must wake this task to continue the task execution */
  57. struct list com; /* The list head of the signals attached to this task. */
  58. struct ebpt_node node;
  59. + struct hlua_consistency cons; /* Store data consistency check. */
  60. };
  61. struct hlua_com {
  62. diff --git a/src/hlua.c b/src/hlua.c
  63. index 6889f2f..b91414b 100644
  64. --- a/src/hlua.c
  65. +++ b/src/hlua.c
  66. @@ -2397,33 +2397,49 @@ static void hlua_resynchonize_proto(struct stream *stream, int dir)
  67. }
  68. }
  69. -/* Check the protocole integrity after the Lua manipulations. Close the stream
  70. - * and returns 0 if fails, otherwise returns 1. The direction is set using dir,
  71. - * which equals either SMP_OPT_DIR_REQ or SMP_OPT_DIR_RES.
  72. +/* This function is called before the Lua execution. It stores
  73. + * the differents parsers state before executing some Lua code.
  74. */
  75. -static int hlua_check_proto(struct stream *stream, int dir)
  76. +static inline void consistency_set(struct stream *stream, int opt, struct hlua_consistency *c)
  77. +{
  78. + c->mode = stream->be->mode;
  79. + switch (c->mode) {
  80. + case PR_MODE_HTTP:
  81. + c->data.http.dir = opt & SMP_OPT_DIR;
  82. + if (c->data.http.dir == SMP_OPT_DIR_REQ)
  83. + c->data.http.state = stream->txn->req.msg_state;
  84. + else
  85. + c->data.http.state = stream->txn->rsp.msg_state;
  86. + break;
  87. + default:
  88. + break;
  89. + }
  90. +}
  91. +
  92. +/* This function is called after the Lua execution. it
  93. + * returns true if the parser state is consistent, otherwise,
  94. + * it return false.
  95. + *
  96. + * In HTTP mode, the parser state must be in the same state
  97. + * or greater when we exit the function. Even if we do a
  98. + * control yield. This prevent to break the HTTP message
  99. + * from the Lua code.
  100. + */
  101. +static inline int consistency_check(struct stream *stream, int opt, struct hlua_consistency *c)
  102. {
  103. - const struct chunk msg = { .len = 0 };
  104. + if (c->mode != stream->be->mode)
  105. + return 0;
  106. - /* Protocol HTTP. The message parsing state must match the request or
  107. - * response state. The problem that may happen is that Lua modifies
  108. - * the request or response message *after* it was parsed, and corrupted
  109. - * it so that it could not be processed anymore. We just need to verify
  110. - * if the parser is still expected to run or not.
  111. - */
  112. - if (stream->be->mode == PR_MODE_HTTP) {
  113. - if (dir == SMP_OPT_DIR_REQ &&
  114. - !(stream->req.analysers & AN_REQ_WAIT_HTTP) &&
  115. - stream->txn->req.msg_state < HTTP_MSG_ERROR) {
  116. - stream_int_retnclose(&stream->si[0], &msg);
  117. - return 0;
  118. - }
  119. - else if (dir == SMP_OPT_DIR_RES &&
  120. - !(stream->res.analysers & AN_RES_WAIT_HTTP) &&
  121. - stream->txn->rsp.msg_state < HTTP_MSG_ERROR) {
  122. - stream_int_retnclose(&stream->si[0], &msg);
  123. + switch (c->mode) {
  124. + case PR_MODE_HTTP:
  125. + if (c->data.http.dir != (opt & SMP_OPT_DIR))
  126. return 0;
  127. - }
  128. + if (c->data.http.dir == SMP_OPT_DIR_REQ)
  129. + return stream->txn->req.msg_state >= c->data.http.state;
  130. + else
  131. + return stream->txn->rsp.msg_state >= c->data.http.state;
  132. + default:
  133. + return 1;
  134. }
  135. return 1;
  136. }
  137. @@ -5324,6 +5340,7 @@ static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp
  138. struct hlua_function *fcn = private;
  139. struct stream *stream = smp->strm;
  140. const char *error;
  141. + const struct chunk msg = { .len = 0 };
  142. if (!stream)
  143. return 0;
  144. @@ -5338,6 +5355,8 @@ static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp
  145. return 0;
  146. }
  147. + consistency_set(stream, smp->opt, &stream->hlua.cons);
  148. +
  149. /* If it is the first run, initialize the data for the call. */
  150. if (!HLUA_IS_RUNNING(&stream->hlua)) {
  151. @@ -5393,8 +5412,10 @@ static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp
  152. switch (hlua_ctx_resume(&stream->hlua, 0)) {
  153. /* finished. */
  154. case HLUA_E_OK:
  155. - if (!hlua_check_proto(stream, (smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES))
  156. + if (!consistency_check(stream, smp->opt, &stream->hlua.cons)) {
  157. + stream_int_retnclose(&stream->si[0], &msg);
  158. return 0;
  159. + }
  160. /* Convert the returned value in sample. */
  161. hlua_lua2smp(stream->hlua.T, -1, smp);
  162. lua_pop(stream->hlua.T, 1);
  163. @@ -5405,13 +5426,15 @@ static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp
  164. /* yield. */
  165. case HLUA_E_AGAIN:
  166. - hlua_check_proto(stream, (smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES);
  167. + if (!consistency_check(stream, smp->opt, &stream->hlua.cons))
  168. + stream_int_retnclose(&stream->si[0], &msg);
  169. SEND_ERR(smp->px, "Lua sample-fetch '%s': cannot use yielded functions.\n", fcn->name);
  170. return 0;
  171. /* finished with error. */
  172. case HLUA_E_ERRMSG:
  173. - hlua_check_proto(stream, (smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES);
  174. + if (!consistency_check(stream, smp->opt, &stream->hlua.cons))
  175. + stream_int_retnclose(&stream->si[0], &msg);
  176. /* Display log. */
  177. SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n",
  178. fcn->name, lua_tostring(stream->hlua.T, -1));
  179. @@ -5419,7 +5442,8 @@ static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp
  180. return 0;
  181. case HLUA_E_ERR:
  182. - hlua_check_proto(stream, (smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES);
  183. + if (!consistency_check(stream, smp->opt, &stream->hlua.cons))
  184. + stream_int_retnclose(&stream->si[0], &msg);
  185. /* Display log. */
  186. SEND_ERR(smp->px, "Lua sample-fetch '%s' returns an unknown error.\n", fcn->name);
  187. @@ -5556,6 +5580,7 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
  188. unsigned int analyzer;
  189. int dir;
  190. const char *error;
  191. + const struct chunk msg = { .len = 0 };
  192. switch (rule->from) {
  193. case ACT_F_TCP_REQ_CNT: analyzer = AN_REQ_INSPECT_FE ; dir = SMP_OPT_DIR_REQ; break;
  194. @@ -5567,6 +5592,8 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
  195. return ACT_RET_CONT;
  196. }
  197. + consistency_set(s, dir, &s->hlua.cons);
  198. +
  199. /* In the execution wrappers linked with a stream, the
  200. * Lua context can be not initialized. This behavior
  201. * permits to save performances because a systematic
  202. @@ -5635,8 +5662,10 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
  203. switch (hlua_ctx_resume(&s->hlua, !(flags & ACT_FLAG_FINAL))) {
  204. /* finished. */
  205. case HLUA_E_OK:
  206. - if (!hlua_check_proto(s, dir))
  207. + if (!consistency_check(s, dir, &s->hlua.cons)) {
  208. + stream_int_retnclose(&s->si[0], &msg);
  209. return ACT_RET_ERR;
  210. + }
  211. if (s->hlua.flags & HLUA_STOP)
  212. return ACT_RET_STOP;
  213. return ACT_RET_CONT;
  214. @@ -5661,12 +5690,17 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
  215. }
  216. if (HLUA_IS_WAKEREQWR(&s->hlua))
  217. s->req.flags |= CF_WAKE_WRITE;
  218. + /* We can quit the fcuntion without consistency check
  219. + * because HAProxy is not able to manipulate data, it
  220. + * is only allowed to call me again. */
  221. return ACT_RET_YIELD;
  222. /* finished with error. */
  223. case HLUA_E_ERRMSG:
  224. - if (!hlua_check_proto(s, dir))
  225. + if (!consistency_check(s, dir, &s->hlua.cons)) {
  226. + stream_int_retnclose(&s->si[0], &msg);
  227. return ACT_RET_ERR;
  228. + }
  229. /* Display log. */
  230. SEND_ERR(px, "Lua function '%s': %s.\n",
  231. rule->arg.hlua_rule->fcn.name, lua_tostring(s->hlua.T, -1));
  232. @@ -5674,8 +5708,10 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
  233. return ACT_RET_CONT;
  234. case HLUA_E_ERR:
  235. - if (!hlua_check_proto(s, dir))
  236. + if (!consistency_check(s, dir, &s->hlua.cons)) {
  237. + stream_int_retnclose(&s->si[0], &msg);
  238. return ACT_RET_ERR;
  239. + }
  240. /* Display log. */
  241. SEND_ERR(px, "Lua function '%s' return an unknown error.\n",
  242. rule->arg.hlua_rule->fcn.name);
  243. --
  244. 2.10.2