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.

79 lines
3.7 KiB

  1. commit 7bd7a8d2b8889f604b807c21190d2e70328d6674
  2. Author: Christopher Faulet <cfaulet@haproxy.com>
  3. Date: Tue Apr 30 12:17:13 2019 +0200
  4. BUG/MEDIUM: listener: Fix how unlimited number of consecutive accepts is handled
  5. There is a bug when global.tune.maxaccept is set to -1 (no limit). It is pretty
  6. visible with one process (nbproc sets to 1). The functions listener_accept() and
  7. accept_queue_process() don't expect to handle negative maxaccept values. So
  8. instead of accepting incoming connections without any limit, none are never
  9. accepted and HAProxy loop infinitly in the scheduler.
  10. When there are 2 or more processes, the bug is a bit more subtile. The limit for
  11. a listener is set to 1. So only one connection is accepted at a time by a given
  12. listener. This happens because the listener's maxaccept value is an unsigned
  13. integer. In check_config_validity(), it is first set to UINT_MAX (-1 casted in
  14. an unsigned integer), and then some calculations on it leads to an integer
  15. overflow.
  16. To fix the bug, the listener's maxaccept value is now a signed integer. So, if a
  17. negative value is set for global.tune.maxaccept, we keep it untouched for the
  18. listener and no calculation is made on it. Then, in the listener code, this
  19. signed value is casted to a unsigned one. It simplifies all tests instead of
  20. dealing with negative values. So, it limits the number of connections accepted
  21. at a time to UINT_MAX at most. But, honestly, it not an issue.
  22. This patch must be backported to 1.9 and 1.8.
  23. (cherry picked from commit 102854cbbaa4d22466dddec9035d411db244082f)
  24. Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
  25. (cherry picked from commit bca4fb2d9d7f2966d9f8270fa1796fdc0dfc866d)
  26. Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
  27. diff --git a/include/types/listener.h b/include/types/listener.h
  28. index ea2eadb5..16ef6d7a 100644
  29. --- a/include/types/listener.h
  30. +++ b/include/types/listener.h
  31. @@ -196,7 +196,7 @@ struct listener {
  32. int nbconn; /* current number of connections on this listener */
  33. int maxconn; /* maximum connections allowed on this listener */
  34. unsigned int backlog; /* if set, listen backlog */
  35. - unsigned int maxaccept; /* if set, max number of connections accepted at once */
  36. + int maxaccept; /* if set, max number of connections accepted at once (-1 when disabled) */
  37. struct list proto_list; /* list in the protocol header */
  38. int (*accept)(struct listener *l, int fd, struct sockaddr_storage *addr); /* upper layer's accept() */
  39. enum obj_type *default_target; /* default target to use for accepted sessions or NULL */
  40. diff --git a/src/listener.c b/src/listener.c
  41. index 821c931a..74990c45 100644
  42. --- a/src/listener.c
  43. +++ b/src/listener.c
  44. @@ -406,7 +406,7 @@ void listener_accept(int fd)
  45. {
  46. struct listener *l = fdtab[fd].owner;
  47. struct proxy *p;
  48. - int max_accept;
  49. + unsigned int max_accept;
  50. int next_conn = 0;
  51. int next_feconn = 0;
  52. int next_actconn = 0;
  53. @@ -420,6 +420,10 @@ void listener_accept(int fd)
  54. if (!l)
  55. return;
  56. p = l->bind_conf->frontend;
  57. +
  58. + /* if l->maxaccept is -1, then max_accept is UINT_MAX. It is not really
  59. + * illimited, but it is probably enough.
  60. + */
  61. max_accept = l->maxaccept ? l->maxaccept : 1;
  62. if (!(l->options & LI_O_UNLIMITED) && global.sps_lim) {
  63. @@ -480,7 +484,7 @@ void listener_accept(int fd)
  64. * worst case. If we fail due to system limits or temporary resource
  65. * shortage, we try again 100ms later in the worst case.
  66. */
  67. - for (; max_accept-- > 0; next_conn = next_feconn = next_actconn = 0) {
  68. + for (; max_accept; next_conn = next_feconn = next_actconn = 0, max_accept--) {
  69. struct sockaddr_storage addr;
  70. socklen_t laddr = sizeof(addr);
  71. unsigned int count;