NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: lib/54527: syslogd hangs when forwarding logs to a IPv6 host that is down



Congratulations, you found a kernel bug. MSG_PEEK is not supposed to reset so->so_{r,}error.
Try this (not even compile-tested).

christos

diff -u -u -r1.281 uipc_socket.c
--- uipc_socket.c       16 Jul 2019 22:57:55 -0000      1.281
+++ uipc_socket.c       14 Sep 2019 13:52:57 -0000
@@ -928,7 +928,8 @@
                }
                if (so->so_error) {
                        error = so->so_error;
-                       so->so_error = 0;
+                       if ((flags & MSG_PEEK) == 0)
+                               so->so_error = 0;
                        goto release;
                }
                if ((so->so_state & SS_ISCONNECTED) == 0) {
@@ -1227,13 +1228,10 @@
                if (so->so_error || so->so_rerror) {
                        if (m != NULL)
                                goto dontblock;
-                       if (so->so_error) {
-                               error = so->so_error;
-                               so->so_error = 0;
-                       } else {
-                               error = so->so_rerror;
-                               so->so_rerror = 0;
-                       }
+                       int *e = so->so_error ? &so->so_error : &so->so_rerror;
+                       error = *e;
+                       if ((flags & MSG_PEEK) == 0)
+                               *e = 0;
                        goto release;
                }
                if (so->so_state & SS_CANTRCVMORE) {


On Sep 14, 2019, at 9:40 AM, Anthony Mallet <anthony.mallet%useless-ficus.net@localhost> wrote:

#include <sys/socket.h>
#include <netinet/in.h>

#include <err.h>
#include <event.h>
#include <netdb.h>
#include <poll.h>

int
main()
{
  struct addrinfo hints = { 0 }, *res, *r;
  struct sockaddr_storage frominet;
  struct pollfd fds;
  socklen_t len;
  char buf[16];
  ssize_t s;
  int error;
  int fd;

  /* setup sending socket */
  hints.ai_flags = AI_PASSIVE;
  hints.ai_family = AF_INET6;
  hints.ai_socktype = SOCK_DGRAM;
  error = getaddrinfo(NULL, "12345", &hints, &res);
  if (error) err(2, "getaddrinfo bind");

  for (r = res; r; r = r->ai_next) {
    fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
    if (fd < 0) err(2, "socket");

    if (bind(fd, r->ai_addr, r->ai_addrlen) < 0)
      err(2, "bind");

    break;
  }
  freeaddrinfo(res);

  /* non-existent host */
  hints.ai_flags = AI_NUMERICHOST;
  hints.ai_family = AF_INET6;
  hints.ai_socktype = SOCK_DGRAM;
  error = getaddrinfo("fc00::", "12345", &hints, &res);
  if (error) err(2, "getaddrinfo sendto");

  /* send empty datagram */
  for (r = res; r; r = r->ai_next) {
    s = sendto(fd, "", 1, 0, r->ai_addr, r->ai_addrlen);
    if (s == -1)
      err(2, "sendto");
    warnx("sent %zd bytes", s);
    break;
  }
  freeaddrinfo(res);

  /* wait for events: sock will be readable and return EHOSTDOWN */
  while (1) {
    fds.fd = fd;
    fds.events = POLLIN;
    if (poll(&fds, 1, -1) == 1) {
      warnx("events %d %d", fds.events, fds.revents);

      /* do the equivalent of a libwarp "hostfrom" */
      len = sizeof(frominet);
      if (recvfrom(fd, buf, sizeof(buf), MSG_PEEK,
                   (struct sockaddr *)&frominet, &len) < 0) {
        warn("can't get client address");
      }

      /* this blocks because the EHOSTDOWN was eaten above */
      s = recv(fd, buf, sizeof(buf), 0);
      warn("recv %zd", s);
    }

    warnx("not reached :/");
  }

  return 0;
}



Home | Main Index | Thread Index | Old Index