Signed-off-by: Visser Sander <sander.visse...@consultant.volvo.com>
Signed-off-by: Andrej Valek <andrej.va...@siemens.com>
---
 .../busybox-udhcpd-fix-not-dying-on-SIGTERM.patch  | 272 +++++++++++++++++++++
 meta/recipes-core/busybox/busybox_1.27.2.bb        |   1 +
 2 files changed, 273 insertions(+)
 create mode 100644 
meta/recipes-core/busybox/busybox/busybox-udhcpd-fix-not-dying-on-SIGTERM.patch

diff --git 
a/meta/recipes-core/busybox/busybox/busybox-udhcpd-fix-not-dying-on-SIGTERM.patch
 
b/meta/recipes-core/busybox/busybox/busybox-udhcpd-fix-not-dying-on-SIGTERM.patch
new file mode 100644
index 0000000000..96be486c61
--- /dev/null
+++ 
b/meta/recipes-core/busybox/busybox/busybox-udhcpd-fix-not-dying-on-SIGTERM.patch
@@ -0,0 +1,272 @@
+From 1384459d88cb0f5f47b6a36b8346dcf425a643f5 Mon Sep 17 00:00:00 2001
+From: Denys Vlasenko <vda.li...@googlemail.com>
+Date: Sat, 10 Mar 2018 19:01:48 +0100
+Subject: [PATCH] udhcpd: fix "not dying on SIGTERM"
+
+Upstream-status: Backport 
[https://git.busybox.net/busybox/commit/?id=3293bc146985c56790033409facc0ad64a471084]
+
+Fixes:
+       commit 52a515d18724bbb34e3ccbbb0218efcc4eccc0a8
+       "udhcp: use poll() instead of select()"
+       Feb 16 2017
+
+udhcp_sp_read() is meant to check whether signal pipe indeed has some data to 
read.
+In the above commit, it was changed as follows:
+
+-      if (!FD_ISSET(signal_pipe.rd, rfds))
++      if (!pfds[0].revents)
+               return 0;
+
+The problem is, the check was working for select() purely by accident.
+Caught signal interrupts select()/poll() syscalls, they return with EINTR
+(regardless of SA_RESTART flag in sigaction). _Then_ signal handler is invoked.
+IOW: they can't see any changes to fd state caused by signal haldler
+(in our case, signal handler makes signal pipe ready to be read).
+
+For select(), it means that rfds[] bit array is unmodified, bit of signal
+pipe's read fd is still set, and the above check "works": it thinks select()
+says there is data to read.
+
+This accident does not work for poll(): .revents stays clear, and we do not
+try reading signal pipe as we should. In udhcpd, we fall through and block
+in socket read. Further SIGTERM signals simply cause socket read to be
+interrupted and then restarted (since SIGTERM handler has SA_RESTART=1).
+
+Fixing this as follows: remove the check altogether. Set signal pipe read fd
+to nonblocking mode. Always read it in udhcp_sp_read().
+If read fails, assume it's EAGAIN and return 0 ("no signal seen").
+
+udhcpd avoids reading signal pipe on every recvd packet by looping if EINTR
+(using safe_poll()) - thus ensuring we have correct .revents for all fds -
+and calling udhcp_sp_read() only if pfds[0].revents!=0.
+
+udhcpc performs much fewer reads (typically it sleeps >99.999% of the time),
+there is no need to optimize it: can call udhcp_sp_read() after each poll
+unconditionally.
+
+To robustify socket reads, unconditionally set pfds[1].revents=0
+in udhcp_sp_fd_set() (which is before poll), and check it before reading
+network socket in udhcpd.
+
+TODO:
+This might still fail: if pfds[1].revents=POLLIN, socket read may still block.
+There are rare cases when select/poll indicates that data can be read,
+but then actual read still blocks (one such case is UDP packets with
+wrong checksum). General advise is, if you use a poll/select loop,
+keep all your fds nonblocking.
+Maybe we should also do that to our network sockets?
+
+function                                             old     new   delta
+udhcp_sp_setup                                        55      65     +10
+udhcp_sp_fd_set                                       54      60      +6
+udhcp_sp_read                                         46      36     -10
+udhcpd_main                                         1451    1437     -14
+udhcpc_main                                         2723    2708     -15
+------------------------------------------------------------------------------
+(add/remove: 0/0 grow/shrink: 2/3 up/down: 16/-39)            Total: -23 bytes
+
+Signed-off-by: Denys Vlasenko <vda.li...@googlemail.com>
+---
+ examples/var_service/dhcpd_if/run                  |  4 +--
+ .../dhcpd_if/{udhcpc.conf => udhcpd.conf}          |  0
+ networking/udhcp/common.h                          |  2 +-
+ networking/udhcp/d6_dhcpc.c                        |  9 +++---
+ networking/udhcp/dhcpc.c                           |  9 +++---
+ networking/udhcp/dhcpd.c                           | 34 ++++++++++++----------
+ networking/udhcp/signalpipe.c                      | 11 +++----
+ 7 files changed, 35 insertions(+), 34 deletions(-)
+ rename examples/var_service/dhcpd_if/{udhcpc.conf => udhcpd.conf} (100%)
+
+diff --git a/examples/var_service/dhcpd_if/run 
b/examples/var_service/dhcpd_if/run
+index de85dece0..a603bdc71 100755
+--- a/examples/var_service/dhcpd_if/run
++++ b/examples/var_service/dhcpd_if/run
+@@ -11,13 +11,13 @@ echo "* Upping iface $if"
+ ip link set dev $if up
+ 
+ >>udhcpd.leases
+-sed 's/^interface.*$/interface '"$if/" -i udhcpc.conf
++sed 's/^interface.*$/interface '"$if/" -i udhcpd.conf
+ 
+ echo "* Starting udhcpd"
+ exec \
+ env - PATH="$PATH" \
+ softlimit \
+ setuidgid root \
+-udhcpd -f -vv udhcpc.conf
++udhcpd -f -vv udhcpd.conf
+ 
+ exit $?
+diff --git a/examples/var_service/dhcpd_if/udhcpc.conf 
b/examples/var_service/dhcpd_if/udhcpd.conf
+similarity index 100%
+rename from examples/var_service/dhcpd_if/udhcpc.conf
+rename to examples/var_service/dhcpd_if/udhcpd.conf
+diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
+index a9c23a186..866f3d8b1 100644
+--- a/networking/udhcp/common.h
++++ b/networking/udhcp/common.h
+@@ -312,7 +312,7 @@ int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
+ 
+ void udhcp_sp_setup(void) FAST_FUNC;
+ void udhcp_sp_fd_set(struct pollfd *pfds, int extra_fd) FAST_FUNC;
+-int udhcp_sp_read(struct pollfd *pfds) FAST_FUNC;
++int udhcp_sp_read(void) FAST_FUNC;
+ 
+ int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, 
uint8_t *mac) FAST_FUNC;
+ 
+diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
+index f6d3fb98b..bdf8dad17 100644
+--- a/networking/udhcp/d6_dhcpc.c
++++ b/networking/udhcp/d6_dhcpc.c
+@@ -1371,13 +1371,12 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
+                       /* yah, I know, *you* say it would never happen */
+                       timeout = INT_MAX;
+                       continue; /* back to main loop */
+-              } /* if select timed out */
++              } /* if poll timed out */
+ 
+-              /* select() didn't timeout, something happened */
++              /* poll() didn't timeout, something happened */
+ 
+               /* Is it a signal? */
+-              /* note: udhcp_sp_read checks poll result before reading */
+-              switch (udhcp_sp_read(pfds)) {
++              switch (udhcp_sp_read()) {
+               case SIGUSR1:
+                       client_config.first_secs = 0; /* make secs field count 
from 0 */
+                       already_waited_sec = 0;
+@@ -1412,7 +1411,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
+               }
+ 
+               /* Is it a packet? */
+-              if (listen_mode == LISTEN_NONE || !pfds[1].revents)
++              if (!pfds[1].revents)
+                       continue; /* no */
+ 
+               {
+diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
+index 1a66c610e..c8027983e 100644
+--- a/networking/udhcp/dhcpc.c
++++ b/networking/udhcp/dhcpc.c
+@@ -1588,13 +1588,12 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
+                       /* yah, I know, *you* say it would never happen */
+                       timeout = INT_MAX;
+                       continue; /* back to main loop */
+-              } /* if select timed out */
++              } /* if poll timed out */
+ 
+-              /* select() didn't timeout, something happened */
++              /* poll() didn't timeout, something happened */
+ 
+               /* Is it a signal? */
+-              /* note: udhcp_sp_read checks poll result before reading */
+-              switch (udhcp_sp_read(pfds)) {
++              switch (udhcp_sp_read()) {
+               case SIGUSR1:
+                       client_config.first_secs = 0; /* make secs field count 
from 0 */
+                       already_waited_sec = 0;
+@@ -1629,7 +1628,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
+               }
+ 
+               /* Is it a packet? */
+-              if (listen_mode == LISTEN_NONE || !pfds[1].revents)
++              if (!pfds[1].revents)
+                       continue; /* no */
+ 
+               {
+diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
+index 3a5fc2db7..c4e990a48 100644
+--- a/networking/udhcp/dhcpd.c
++++ b/networking/udhcp/dhcpd.c
+@@ -912,20 +912,18 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
+ 
+               udhcp_sp_fd_set(pfds, server_socket);
+               tv = timeout_end - monotonic_sec();
+-              retval = 0;
+-              if (!server_config.auto_time || tv > 0) {
+-                      retval = poll(pfds, 2, server_config.auto_time ? tv * 
1000 : -1);
+-              }
+-              if (retval == 0) {
+-                      write_leases();
+-                      goto continue_with_autotime;
+-              }
+-              if (retval < 0 && errno != EINTR) {
+-                      log1("error on select");
+-                      continue;
++              /* Block here waiting for either signal or packet */
++              retval = safe_poll(pfds, 2, server_config.auto_time ? tv * 1000 
: -1);
++              if (retval <= 0) {
++                      if (retval == 0) {
++                              write_leases();
++                              goto continue_with_autotime;
++                      }
++                      /* < 0 and not EINTR: should not happen */
++                      bb_perror_msg_and_die("poll");
+               }
+ 
+-              switch (udhcp_sp_read(pfds)) {
++              if (pfds[0].revents) switch (udhcp_sp_read()) {
+               case SIGUSR1:
+                       bb_error_msg("received %s", "SIGUSR1");
+                       write_leases();
+@@ -935,12 +933,16 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
+                       bb_error_msg("received %s", "SIGTERM");
+                       write_leases();
+                       goto ret0;
+-              case 0: /* no signal: read a packet */
+-                      break;
+-              default: /* signal or error (probably EINTR): back to select */
+-                      continue;
+               }
+ 
++              /* Is it a packet? */
++              if (!pfds[1].revents)
++                      continue; /* no */
++
++              /* Note: we do not block here, we block on poll() instead.
++               * Blocking here would prevent SIGTERM from working:
++               * socket read inside this call is restarted on caught signals.
++               */
+               bytes = udhcp_recv_kernel_packet(&packet, server_socket);
+               if (bytes < 0) {
+                       /* bytes can also be -2 ("bad packet data") */
+diff --git a/networking/udhcp/signalpipe.c b/networking/udhcp/signalpipe.c
+index b101b4ce4..2ff78f0f2 100644
+--- a/networking/udhcp/signalpipe.c
++++ b/networking/udhcp/signalpipe.c
+@@ -40,6 +40,7 @@ void FAST_FUNC udhcp_sp_setup(void)
+       xpiped_pair(signal_pipe);
+       close_on_exec_on(signal_pipe.rd);
+       close_on_exec_on(signal_pipe.wr);
++      ndelay_on(signal_pipe.rd);
+       ndelay_on(signal_pipe.wr);
+       bb_signals(0
+               + (1 << SIGUSR1)
+@@ -61,20 +62,20 @@ void FAST_FUNC udhcp_sp_fd_set(struct pollfd pfds[2], int 
extra_fd)
+               pfds[1].fd = extra_fd;
+               pfds[1].events = POLLIN;
+       }
++      /* this simplifies "is extra_fd ready?" tests elsewhere: */
++      pfds[1].revents = 0;
+ }
+ 
+ /* Read a signal from the signal pipe. Returns 0 if there is
+  * no signal, -1 on error (and sets errno appropriately), and
+  * your signal on success */
+-int FAST_FUNC udhcp_sp_read(struct pollfd pfds[2])
++int FAST_FUNC udhcp_sp_read(void)
+ {
+       unsigned char sig;
+ 
+-      if (!pfds[0].revents)
+-              return 0;
+-
++      /* Can't block here, fd is in nonblocking mode */
+       if (safe_read(signal_pipe.rd, &sig, 1) != 1)
+-              return -1;
++              return 0;
+ 
+       return sig;
+ }
+-- 
+2.16.4
diff --git a/meta/recipes-core/busybox/busybox_1.27.2.bb 
b/meta/recipes-core/busybox/busybox_1.27.2.bb
index 716a0650fc..45369808ac 100644
--- a/meta/recipes-core/busybox/busybox_1.27.2.bb
+++ b/meta/recipes-core/busybox/busybox_1.27.2.bb
@@ -49,6 +49,7 @@ SRC_URI = 
"http://www.busybox.net/downloads/busybox-${PV}.tar.bz2;name=tarball \
            file://busybox-fix-lzma-segfaults.patch \
            file://umount-ignore-c.patch \
            file://CVE-2017-15874.patch \
+           file://busybox-udhcpd-fix-not-dying-on-SIGTERM.patch \
 "
 SRC_URI_append_libc-musl = " file://musl.cfg "
 
-- 
2.11.0

-- 
_______________________________________________
Openembedded-core mailing list
Openembedded-core@lists.openembedded.org
http://lists.openembedded.org/mailman/listinfo/openembedded-core

Reply via email to