]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: proto_ux: properly suspend named UNIX listeners
authorAurelien DARRAGON <adarragon@haproxy.com>
Wed, 22 Feb 2023 13:34:28 +0000 (14:34 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Thu, 23 Feb 2023 14:05:05 +0000 (15:05 +0100)
When a listener is suspended, we expect that it may not process any data for
the time it is suspended.

Yet for named UNIX socket, as the suspend operation is a no-op at the proto
level, recv events on the socket may still be processed by the polling loop.

This is quite disturbing as someone may rely on a paused proxy being harmless,
which is true for all protos except for named UNIX sockets.

To fix this behavior, we explicitely disable io recv events when suspending a
named UNIX socket listener (we call disable() method on the listener).

The io recv events will automatically be restored when the listener is resumed
since the l->enable() method is called at the end of the resume() operation.

This could be backported up to 2.4 after a reasonable observation
period to make sure that this change doesn't cause unwanted side-effects.

src/proto_uxdg.c
src/proto_uxst.c

index 68fe207de060a8db54133f381bbc4afa0b77b0e2..0e3e1d0f343121180b8415f5633198743ba7a1d7 100644 (file)
@@ -126,17 +126,20 @@ static void uxdg_disable_listener(struct listener *l)
 }
 
 /* Suspend a receiver. Returns < 0 in case of failure, 0 if the receiver
- * was totally stopped, or > 0 if correctly suspended. Nothing is done for
- * plain unix sockets since currently it's the new process which handles
- * the renaming. Abstract sockets are completely unbound and closed so
- * there's no need to stop the poller.
+ * was totally stopped, or > 0 if correctly suspended. For plain unix sockets
+ * we only disable the listener to prevent data from being handled but nothing
+ * more is done since currently it's the new process which handles the renaming.
+ * Abstract sockets are completely unbound and closed so there's no need to stop
+ * the poller.
  */
 static int uxdg_suspend_receiver(struct receiver *rx)
 {
         struct listener *l = LIST_ELEM(rx, struct listener *, rx);
 
-        if (((struct sockaddr_un *)&rx->addr)->sun_path[0])
+        if (((struct sockaddr_un *)&rx->addr)->sun_path[0]) {
+               uxdg_disable_listener(l);
                 return 1;
+       }
 
         /* Listener's lock already held. Call lockless version of
          * unbind_listener. */
index 08b8d274712dc5f538095d5c0371753ed0edd3c3..9678a49a8ce19f7b3dfa22cdc5a741e4967e2683 100644 (file)
@@ -165,17 +165,20 @@ static void uxst_disable_listener(struct listener *l)
 }
 
 /* Suspend a receiver. Returns < 0 in case of failure, 0 if the receiver
- * was totally stopped, or > 0 if correctly suspended. Nothing is done for
- * plain unix sockets since currently it's the new process which handles
- * the renaming. Abstract sockets are completely unbound and closed so
- * there's no need to stop the poller.
+ * was totally stopped, or > 0 if correctly suspended. For plain unix sockets
+ * we only disable the listener to prevent data from being handled but nothing
+ * more is done since currently it's the new process which handles the renaming.
+ * Abstract sockets are completely unbound and closed so there's no need to stop
+ * the poller.
  */
 static int uxst_suspend_receiver(struct receiver *rx)
 {
        struct listener *l = LIST_ELEM(rx, struct listener *, rx);
 
-       if (((struct sockaddr_un *)&rx->addr)->sun_path[0])
+       if (((struct sockaddr_un *)&rx->addr)->sun_path[0]) {
+               uxst_disable_listener(l);
                return 1;
+       }
 
        /* Listener's lock already held. Call lockless version of
         * unbind_listener. */