Hello,

This patch (3/5) reorganises console read and selection operations on the
boot server to improve
 asynchronous I/O response times and prevent memory issues in pending read
operations. Key Changes:

         poll() and wake_pipe Architecture: The temporary select() loop in
the main function has been replaced with a
         modern poll() mechanism. Incoming read requests (queue_read) now
wake the main loop via a wake_pipe to
         dynamically monitor stdin.

        Dedicated Select Thread: A dedicated select_thread and queue
(selq), supported by CLOCK_MONOTONIC,
        have been added to safely process non-console select requests
without clock drift side-effects.

         Buffer and Memory Safeguards: Console and in-band reads have been
limited by `CONSOLE_READ_MAX`
         and `IO_INBAND_MAX`. To prevent OOL queue page leaks, appropriate
`memcpy` + `munmap` pruning operations
        have been implemented within `read_reply`, and a feature for
handling zero-length reads immediately has been added.

         Lock Clean-up and EOF Handling: Lock boundaries (queuelock,
selq_lock) have been simplified, the old spin lock within
        `unlock_readlock` has been removed, and atomic `stdin_eof`
monitoring has been integrated to respond immediately to
         EOF conditions.

The patch is provided below for your consideration ;)
>From 6a9ac9915e800ddc9fe597d17f84bae441d13f30 Mon Sep 17 00:00:00 2001
From: Alperen ERKAN <[email protected]>
Date: Sat, 16 Sep 2026 12:50:33 +0300
Subject: [PATCH 3/5] boot: rework console read queue and add select queue

Replace the ad-hoc select() loop in main with poll() driven by a
wake pipe, rework the queued console read logic to bound request
sizes, track stdin EOF and answer zero-length reads immediately, and
add a select queue with a dedicated select thread.  Also clean up
the device server entry points and the console io_read/io_write
routines.

---
 hurd/boot/boot.c | 653
++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 470 insertions(+), 183 deletions(-)

diff --git a/hurd/boot/boot.c b/hurd/boot/boot.c
--- a/hurd/boot/boot.c
+++ b/hurd/boot/boot.c
@@ -907,24 +946,63 @@ main (int argc, char **argv, char **envp)
   mach_port_deallocate (mach_task_self (), pseudo_master_device_port);

   err = pthread_create (&pthread_id, NULL, msg_thread, NULL);
-  if (!err)
-    pthread_detach (pthread_id);
-  else
-    {
-      errno = err;
-      perror ("pthread_create");
-    }
+  if (err)
+    error (1, err, "pthread_create");
+  pthread_detach (pthread_id);
+
+  err = pthread_create (&pthread_id, NULL, select_thread, NULL);
+  if (err)
+    error (1, err, "pthread_create");
+  pthread_detach (pthread_id);

   for (;;)
     {
-      fd_set rmask;
-      FD_ZERO (&rmask);
-      FD_SET (0, &rmask);
-      if (select (1, &rmask, 0, 0, 0) == 1)
+      int want_stdin;
+      struct pollfd pfd[2];
+      int n;
+
+      if (atomic_load_explicit (&stdin_eof, memory_order_relaxed))
+ {
+  /* Satisfy remaining waiters with EOF replies.  */
+  pthread_spin_lock (&queuelock);
+  want_stdin = qrhead != NULL;
+  pthread_spin_unlock (&queuelock);
+  if (want_stdin)
+    {
+      read_reply ();
+      continue;
+    }
+ }
+      else
+ {
+  pthread_spin_lock (&queuelock);
+  want_stdin = qrhead != NULL;
+  pthread_spin_unlock (&queuelock);
+ }
+
+      pfd[0].fd = wake_pipe[0];
+      pfd[0].events = POLLIN;
+      pfd[0].revents = 0;
+      pfd[1].fd = 0;
+      pfd[1].events = POLLIN;
+      pfd[1].revents = 0;
+
+      n = poll (pfd, want_stdin ? 2 : 1, -1);
+      if (n < 0)
+ {
+  if (errno == EINTR)
+    continue;
+  error (5, errno, "poll");
+ }
+
+      if (pfd[0].revents & POLLIN)
+ {
+  char c[128];
+  read (wake_pipe[0], c, sizeof c);
+ }
+
+      if (want_stdin && (pfd[1].revents & (POLLIN | POLLHUP | POLLERR)))
  read_reply ();
-      else if (errno != EINTR)
-        /* We hosed */
- error (5, errno, "select");
     }
 }

@@ -987,136 +1218,367 @@ struct qr
   enum read_type type;
   mach_port_t reply_port;
   mach_msg_type_name_t reply_type;
-  int amount;
+  vm_size_t amount;
   struct qr *next;
 };
 struct qr *qrhead, *qrtail;

-/* Queue a read for later reply. */
-kern_return_t
-queue_read (enum read_type type,
-    mach_port_t reply_port,
-    mach_msg_type_name_t reply_type,
-    int amount)
+struct selq
+{
+  mach_port_t reply_port;
+  mach_msg_type_name_t reply_type;
+  int is_timeout; /* Use io_select_timeout_reply.  */
+  int type; /* Requested SELECT_* mask.  */
+  struct timespec deadline; /* Valid iff IS_TIMEOUT.  */
+  struct selq *next;
+};
+static struct selq *selq_head, *selq_tail;
+static pthread_mutex_t selq_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* Send the reply for a queued console read QR.  BUF/LEN are the data;
+   if ERR is nonzero, it is an errno-style error code and no data is
+   returned.  */
+static void
+send_read_reply (struct qr *qr, const void *buf, ssize_t len, int err)
+{
+  switch (qr->type)
+    {
+    case DEV_READ:
+      ds_device_read_reply (qr->reply_port, qr->reply_type, err,
+    (io_buf_ptr_t) (err ? 0 : buf),
+    err ? 0 : len);
+      break;
+
+    case DEV_READI:
+      ds_device_read_reply_inband (qr->reply_port, qr->reply_type, err,
+   err ? (const void *) 0 : buf,
+   err ? 0 : len);
+      break;
+
+    case IO_READ:
+      io_read_reply (qr->reply_port, qr->reply_type, err,
+     err ? (void *) 0 : buf, err ? 0 : len);
+      break;
+    }
+}
+
+/* Queue a read for later reply.  */
+static kern_return_t
+queue_read (enum read_type type, mach_port_t reply_port,
+    mach_msg_type_name_t reply_type, vm_size_t amount)
 {
   struct qr *qr;

-  qr = malloc (sizeof (struct qr));
+  /* Zero-length requests and EOF get an immediate answer.  */
+  if (amount == 0 || atomic_load_explicit (&stdin_eof,
memory_order_relaxed))
+    {
+      struct qr qr0 = { type, reply_port, reply_type, 0, NULL };
+      send_read_reply (&qr0, NULL, 0, 0);
+      return D_SUCCESS;
+    }
+
+  qr = malloc (sizeof *qr);
   if (!qr)
     return D_NO_MEMORY;

-  pthread_spin_lock (&queuelock);
-
   qr->type = type;
   qr->reply_port = reply_port;
   qr->reply_type = reply_type;
   qr->amount = amount;
   qr->next = 0;
+
+  pthread_spin_lock (&queuelock);
   if (qrtail)
     qrtail->next = qr;
   else
-    qrhead = qrtail = qr;
-
+    qrhead = qr;
+  qrtail = qr;
   pthread_spin_unlock (&queuelock);
+
+  /* Wake the main thread so it starts polling stdin.  */
+  if (write (wake_pipe[1], "", 1) < 0 && errno != EAGAIN && errno != EINTR)
+    /* ignore */;
+
   return D_SUCCESS;
 }

-/* TRUE if there's data available on stdin, which should be used to satisfy
-   console read requests.  */
-static int should_read = 0;
-
-/* Reply to a queued read. */
+/* Reply to the oldest queued console read, if any, using input from
+   host stdin.  Called by the main thread when stdin is readable (or
+   at EOF, where read returns 0).  */
 static void
 read_reply (void)
 {
-  int avail;
   struct qr *qr;
-  char * buf;
-  int amtread;
-
-  /* By forcing SHOULD_READ to true before trying the lock, we ensure that
-     either we get the lock ourselves or that whoever currently holds the
-     lock will service this read when he unlocks it.  */
-  should_read = 1;
-  if (pthread_spin_trylock (&readlock))
-    return;
+  ssize_t amtread = 0;
+  void *buf = NULL;
+  vm_size_t bufsize = 0;
+  char inband_buf[IO_INBAND_MAX];

-  /* Since we're committed to servicing the read, no one else need do so.
 */
-  should_read = 0;
+  pthread_spin_lock (&readlock);

-  ioctl (0, FIONREAD, &avail);
-  if (!avail)
+  pthread_spin_lock (&queuelock);
+  qr = qrhead;
+  if (qr)
+    {
+      qrhead = qr->next;
+      if (qrhead == NULL)
+        qrtail = NULL;
+    }
+  pthread_spin_unlock (&queuelock);
+
+  if (! qr)
     {
       pthread_spin_unlock (&readlock);
       return;
     }

-  pthread_spin_lock (&queuelock);
-
-  if (!qrhead)
+  if (qr->type == DEV_READI)
     {
-      pthread_spin_unlock (&queuelock);
+      /* Amounts for in-band reads were validated at enqueue time.  */
+      amtread = read (0, inband_buf, qr->amount);
+      if (amtread == 0)
+ atomic_store_explicit (&stdin_eof, 1, memory_order_relaxed);
       pthread_spin_unlock (&readlock);
-      return;
+      if (amtread < 0)
+ send_read_reply (qr, NULL, 0, errno ? errno : EIO);
+      else
+ send_read_reply (qr, inband_buf, amtread, 0);
+    }
+  else
+    {
+      bufsize = qr->amount;
+      buf = mmap (0, bufsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+      if (buf == MAP_FAILED)
+ {
+  int e = errno ? errno : EIO;
+  pthread_spin_unlock (&readlock);
+  send_read_reply (qr, NULL, 0, e);
+  free (qr);
+  return;
+ }
+      amtread = read (0, buf, bufsize);
+      if (amtread == 0)
+ atomic_store_explicit (&stdin_eof, 1, memory_order_relaxed);
+      if (amtread > 0 && (vm_size_t) amtread < bufsize)
+ {
+  /* Shrink the mapping so the tail pages cannot leak.  */
+  void *nbuf = mmap (0, amtread, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+  if (nbuf != MAP_FAILED)
+    {
+      memcpy (nbuf, buf, amtread);
+      munmap (buf, bufsize);
+      buf = nbuf;
+      bufsize = amtread;
+    }
+ }
+      if (amtread < 0)
+ {
+  int e = errno;
+  munmap (buf, bufsize);
+  pthread_spin_unlock (&readlock);
+  send_read_reply (qr, NULL, 0, e);
+  free (qr);
+  return;
+ }
+      pthread_spin_unlock (&readlock);
+      send_read_reply (qr, buf, amtread, 0);
+      munmap (buf, bufsize);
     }

-  qr = qrhead;
-  qrhead = qr->next;
-  if (qr == qrtail)
-    qrtail = 0;
+  free (qr);
+}

-  pthread_spin_unlock (&queuelock);
+/* Queue an io_select request; satisfied by SELECT_THREAD.  */
+static kern_return_t
+queue_select (mach_port_t reply_port, mach_msg_type_name_t reply_type,
+      int type, int is_timeout, const struct timespec *ts)
+{
+  struct selq *sq;

-  if (qr->type == DEV_READ)
+  if (type == 0)
+    return 0;
+
+  sq = malloc (sizeof *sq);
+  if (! sq)
+    return ENOMEM;
+
+  sq->reply_port = reply_port;
+  sq->reply_type = reply_type;
+  sq->is_timeout = is_timeout;
+  sq->type = type;
+  sq->next = NULL;
+  if (is_timeout)
     {
-      buf = mmap (0, qr->amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
-      assert_backtrace (buf != MAP_FAILED);
+      if (clock_gettime (CLOCK_MONOTONIC, &sq->deadline) < 0)
+ {
+  free (sq);
+  return errno;
+ }
+      sq->deadline.tv_sec += ts->tv_sec;
+      sq->deadline.tv_nsec += ts->tv_nsec;
+      if (sq->deadline.tv_nsec >= 1000000000L)
+ {
+  sq->deadline.tv_nsec -= 1000000000L;
+  sq->deadline.tv_sec += 1;
+ }
     }
+
+  pthread_mutex_lock (&selq_lock);
+  if (selq_tail)
+    selq_tail->next = sq;
   else
-    buf = alloca (qr->amount);
-  amtread = read (0, buf, qr->amount);
+    selq_head = sq;
+  selq_tail = sq;
+  pthread_mutex_unlock (&selq_lock);

-  pthread_spin_unlock (&readlock);
+  if (write (select_pipe[1], "", 1) < 0 && errno != EAGAIN && errno !=
EINTR)
+    /* ignore */;

-  switch (qr->type)
+  return MIG_NO_REPLY;
+}
+
+static void *
+select_thread (void *arg)
+{
+  pthread_setname_np (pthread_self (), "select");
+
+  for (;;)
     {
-    case DEV_READ:
-      if (amtread >= 0)
- ds_device_read_reply (qr->reply_port, qr->reply_type, 0,
-      (io_buf_ptr_t) buf, amtread);
-      else
- ds_device_read_reply (qr->reply_port, qr->reply_type, errno, 0, 0);
-      break;
+      int want_r = 0, want_w = 0, want_x = 0;
+      int n, i, npfd = 0;
+      int stdin_ready, stdout_ready, urg_ready;
+      struct selq *sq, **psq, *done = NULL, **pdone = &done;
+      struct pollfd pfd[3];
+      int timeout_ms = -1;
+      struct timespec now;
+
+      pthread_mutex_lock (&selq_lock);
+      for (sq = selq_head; sq; sq = sq->next)
+ {
+  if (sq->type & (SELECT_READ | SELECT_URG))
+    want_r = 1;
+  if (sq->type & SELECT_WRITE)
+    want_w = 1;
+  if (sq->type & SELECT_URG)
+    want_x = 1;
+ }
+      if (selq_head)
+ clock_gettime (CLOCK_MONOTONIC, &now);
+      for (sq = selq_head; sq; sq = sq->next)
+ {
+  if (sq->is_timeout)
+    {
+      long long ms = (sq->deadline.tv_sec - now.tv_sec) * 1000LL
+     + (sq->deadline.tv_nsec - now.tv_nsec) / 1000000LL;
+      int m = ms <= 0 ? 0 : (ms > 0x7fffffffLL ? 0x7fffffff : (int) ms);
+      if (timeout_ms < 0 || m < timeout_ms)
+ timeout_ms = m;
+    }
+ }
+      pthread_mutex_unlock (&selq_lock);

-    case DEV_READI:
-      if (amtread >= 0)
- ds_device_read_reply_inband (qr->reply_port, qr->reply_type, 0,
-     buf, amtread);
-      else
- ds_device_read_reply_inband (qr->reply_port, qr->reply_type, errno,
-     0, 0);
-      break;
+      pfd[npfd].fd = select_pipe[0];
+      pfd[npfd].events = POLLIN;
+      npfd++;
+      if (want_r)
+ {
+  pfd[npfd].fd = 0;
+  pfd[npfd].events = POLLIN | (want_x ? POLLPRI : 0);
+  npfd++;
+ }
+      if (want_w)
+ {
+  pfd[npfd].fd = 1;
+  pfd[npfd].events = POLLOUT;
+  npfd++;
+ }

-    case IO_READ:
-      if (amtread >= 0)
- io_read_reply (qr->reply_port, qr->reply_type, 0,
-       buf, amtread);
-      else
- io_read_reply (qr->reply_port, qr->reply_type, errno, 0, 0);
-      break;
-    }
+      n = poll (pfd, npfd, timeout_ms);
+      if (n < 0)
+ {
+  if (errno == EINTR)
+    continue;
+  continue;
+ }

-  free (qr);
-}
+      if (pfd[0].revents & POLLIN)
+ {
+  char c[128];
+  read (select_pipe[0], c, sizeof c);
+ }

-/* Unlock READLOCK, and also service any new read requests that it was
-   blocking.  */
-static void
-unlock_readlock (void)
-{
-  pthread_spin_unlock (&readlock);
-  while (should_read)
-    read_reply ();
+      stdin_ready = 0, stdout_ready = 0, urg_ready = 0;
+      for (i = 1; i < npfd; i++)
+ {
+  if ((pfd[i].revents & (POLLIN | POLLHUP | POLLERR))
+      && (pfd[i].events & POLLIN))
+    stdin_ready = 1;
+  if ((pfd[i].revents & POLLOUT) && (pfd[i].events & POLLOUT))
+    stdout_ready = 1;
+  if ((pfd[i].revents & POLLPRI) && (pfd[i].events & POLLPRI))
+    urg_ready = 1;
+ }
+      if (atomic_load_explicit (&stdin_eof, memory_order_relaxed))
+ stdin_ready = 1;
+
+      clock_gettime (CLOCK_MONOTONIC, &now);
+
+      pthread_mutex_lock (&selq_lock);
+      for (psq = &selq_head; (sq = *psq); )
+ {
+  int result = 0, expired = 0;
+
+  if (sq->is_timeout
+      && (sq->deadline.tv_sec < now.tv_sec
+  || (sq->deadline.tv_sec == now.tv_sec
+      && sq->deadline.tv_nsec <= now.tv_nsec)))
+    expired = 1;
+
+  if (! expired)
+    {
+      if (stdin_ready && (sq->type & SELECT_READ))
+ result |= SELECT_READ;
+      if (stdout_ready && (sq->type & SELECT_WRITE))
+ result |= SELECT_WRITE;
+      if (urg_ready && (sq->type & SELECT_URG))
+ result |= SELECT_URG;
+    }
+
+  if (result || expired)
+    {
+      *psq = sq->next;
+      if (selq_tail == sq)
+ selq_tail = NULL;   /* recompute below if needed */
+      sq->type = result;
+      *pdone = sq;
+      pdone = &sq->next;
+      sq->next = NULL;
+    }
+  else
+    psq = &sq->next;
+ }
+      /* Fix up tail after removals.  */
+      if (! selq_head)
+ selq_tail = NULL;
+      else
+ {
+  for (sq = selq_head; sq->next; sq = sq->next)
+    ;
+  selq_tail = sq;
+ }
+      pthread_mutex_unlock (&selq_lock);
+
+      while ((sq = done))
+ {
+  done = sq->next;
+  if (sq->is_timeout)
+    io_select_timeout_reply (sq->reply_port, sq->reply_type, 0,
+     sq->type);
+  else
+    io_select_reply (sq->reply_port, sq->reply_type, 0, sq->type);
+  free (sq);
+ }
+    }
 }



@@ -1372,11 +1367,6 @@ ds_device_open (mach_port_t master_port,

   if (!strcmp (name, "console"))
     {
-#if 0
-      mach_port_insert_right (mach_task_self (), pseudo_console,
-      pseudo_console, MACH_MSG_TYPE_MAKE_SEND);
-      console_send_rights++;
-#endif
       console_mscount++;
       *device = pseudo_console;
       *devicetype = MACH_MSG_TYPE_MAKE_SEND;
@@ -1430,7 +1430,7 @@ ds_device_open_new (mach_port_t master_port,
 kern_return_t
 ds_device_close (device_t device)
 {
-  if (device != pseudo_console && device != pseudo_root)
+  if (device != pseudo_console && device != pseudo_root && device !=
pseudo_time)
     return D_NO_SUCH_DEVICE;
   return 0;
 }
@@ -1447,24 +1448,25 @@ ds_device_write (device_t device,
 {
   if (device == pseudo_console)
     {
-#if 0
-      if (console_send_rights)
+      *bytes_written = write (1, data, datalen);
+      if (*bytes_written == -1)
  {
-  mach_port_mod_refs (mach_task_self (), pseudo_console,
-      MACH_PORT_TYPE_SEND, -console_send_rights);
-  console_send_rights = 0;
+  if (verbose)
+    fprintf (stderr, "console write: %s\r\n", strerror (errno));
+  return D_IO_ERROR;
  }
-#endif

-      *bytes_written = write (1, data, datalen);
-
-      return (*bytes_written == -1 ? D_IO_ERROR : D_SUCCESS);
+      return D_SUCCESS;
     }
   else if (device == pseudo_root)
     {
       size_t wrote;
       if (store_write (root_store, recnum, data, datalen, &wrote) != 0)
- return D_IO_ERROR;
+ {
+  if (verbose)
+    fprintf (stderr, "store_write: %s\r\n", strerror (errno));
+  return D_IO_ERROR;
+ }
       *bytes_written = wrote;
       return D_SUCCESS;
     }
@@ -1485,24 +1486,25 @@ ds_device_write_inband (device_t device,
 {
   if (device == pseudo_console)
     {
-#if 0
-      if (console_send_rights)
+      *bytes_written = write (1, data, datalen);
+      if (*bytes_written == -1)
  {
-  mach_port_mod_refs (mach_task_self (), pseudo_console,
-      MACH_PORT_TYPE_SEND, -console_send_rights);
-  console_send_rights = 0;
+  if (verbose)
+    fprintf (stderr, "console write: %s\r\n", strerror (errno));
+  return D_IO_ERROR;
  }
-#endif
-
-      *bytes_written = write (1, data, datalen);

-      return (*bytes_written == -1 ? D_IO_ERROR : D_SUCCESS);
+      return D_SUCCESS;
     }
   else if (device == pseudo_root)
     {
       size_t wrote;
       if (store_write (root_store, recnum, data, datalen, &wrote) != 0)
- return D_IO_ERROR;
+ {
+  if (verbose)
+    fprintf (stderr, "store_write: %s\r\n", strerror (errno));
+  return D_IO_ERROR;
+ }
       *bytes_written = wrote;
       return D_SUCCESS;
     }
@@ -1522,42 +1532,52 @@ ds_device_read (device_t device,
  mach_msg_type_number_t *datalen)
 {
   error_t err;
+
+  /* Zero-length requests get an immediate empty answer.  */
+  if (bytes_wanted == 0)
+    {
+      *data = 0;
+      *datalen = 0;
+      return D_SUCCESS;
+    }
+
   if (device == pseudo_console)
     {
       int avail;

-#if 0
-      if (console_send_rights)
- {
-  mach_port_mod_refs (mach_task_self (), pseudo_console,
-      MACH_PORT_TYPE_SEND, -console_send_rights);
-  console_send_rights = 0;
- }
-#endif
+      if (bytes_wanted < 0)
+ return D_INVALID_SIZE;
+      if (bytes_wanted > CONSOLE_READ_MAX)
+ bytes_wanted = CONSOLE_READ_MAX;

       pthread_spin_lock (&readlock);
-      ioctl (0, FIONREAD, &avail);
+      if (ioctl (0, FIONREAD, &avail) < 0)
+ {
+  pthread_spin_unlock (&readlock);
+  return errno;
+ }
       if (avail)
  {
   void *new_data = mmap (0, bytes_wanted, PROT_READ|PROT_WRITE,
  MAP_ANON, 0, 0);
   if (new_data == MAP_FAILED)
     {
-      unlock_readlock ();
+      pthread_spin_unlock (&readlock);
       return errno;
     }
   *data = new_data;
   *datalen = read (0, *data, bytes_wanted);
-  unlock_readlock ();
+  if (*datalen == 0)
+    atomic_store_explicit (&stdin_eof, 1, memory_order_relaxed);
+  pthread_spin_unlock (&readlock);
   return (*datalen == -1 ? D_IO_ERROR : D_SUCCESS);
  }
       else
  {
-  unlock_readlock ();
-  err = queue_read (DEV_READ, reply_port, reply_type, bytes_wanted);
-  if (err)
-    return err;
-  return MIG_NO_REPLY;
+  pthread_spin_unlock (&readlock);
+  err = queue_read (DEV_READ, reply_port, reply_type,
+    (vm_size_t) bytes_wanted);
+  return err == D_SUCCESS ? MIG_NO_REPLY : err;
  }
     }
   else if (device == pseudo_root)
@@ -1575,7 +1579,11 @@ ds_device_read (device_t device,
       size_t data_size = 0;
       err = store_read (root_store, recnum, bytes_wanted, (void **)data,
&data_size);
       if (err)
-        return D_IO_ERROR;
+ {
+  if (verbose)
+    fprintf (stderr, "store_read: %s\r\n", strerror (err));
+  return D_IO_ERROR;
+ }
       *datalen = data_size;
       return D_SUCCESS;
     }
@@ -1597,36 +1602,41 @@ ds_device_read_inband (device_t device,
        io_buf_ptr_inband_t data,
        mach_msg_type_number_t *datalen)
 {
+  /* The buffer is a fixed MIG in-band array; bound the request.  */
+  if (bytes_wanted < 0 || bytes_wanted > IO_INBAND_MAX)
+    return D_INVALID_SIZE;
+  if (bytes_wanted == 0)
+    {
+      *datalen = 0;
+      return D_SUCCESS;
+    }
+
   if (device == pseudo_console)
     {
       int avail;

-#if 0
-      if (console_send_rights)
+      pthread_spin_lock (&readlock);
+      if (ioctl (0, FIONREAD, &avail) < 0)
  {
-  mach_port_mod_refs (mach_task_self (), pseudo_console,
-      MACH_PORT_TYPE_SEND, -console_send_rights);
-  console_send_rights = 0;
+  pthread_spin_unlock (&readlock);
+  return errno;
  }
-#endif
-
-      pthread_spin_lock (&readlock);
-      ioctl (0, FIONREAD, &avail);
       if (avail)
  {
   *datalen = read (0, data, bytes_wanted);
-  unlock_readlock ();
+  if (*datalen == 0)
+    atomic_store_explicit (&stdin_eof, 1, memory_order_relaxed);
+  pthread_spin_unlock (&readlock);
   return (*datalen == -1 ? D_IO_ERROR : D_SUCCESS);
  }
       else
  {
   kern_return_t err;

-  unlock_readlock ();
-  err = queue_read (DEV_READI, reply_port, reply_type, bytes_wanted);
-  if (err)
-    return err;
-  return MIG_NO_REPLY;
+  pthread_spin_unlock (&readlock);
+  err = queue_read (DEV_READI, reply_port, reply_type,
+    (vm_size_t) bytes_wanted);
+  return err == D_SUCCESS ? MIG_NO_REPLY : err;
  }
     }
   else if (device == pseudo_root)
@@ -1680,7 +1686,13 @@ ds_device_map (device_t device,
  return D_IO_ERROR;

       err = io_map (node, pager, &wr_memobj);
-      if (!err && MACH_PORT_VALID (wr_memobj))
+      if (err)
+ {
+  mach_port_deallocate (mach_task_self (), node);
+  *pager = MACH_PORT_NULL;
+  return D_IO_ERROR;
+ }
+      if (MACH_PORT_VALID (wr_memobj))
  mach_port_deallocate (mach_task_self (), wr_memobj);

       mach_port_deallocate (mach_task_self (), node);
@@ -1721,6 +1724,9 @@ ds_device_get_status (device_t device,
       case DEV_GET_SIZE:
         if (*statuslen < DEV_GET_SIZE_COUNT)
           return D_INVALID_SIZE;
+ if (root_store->size > UINT32_MAX
+    || root_store->block_size > UINT32_MAX)
+  return D_INVALID_SIZE;
         status[DEV_GET_SIZE_DEVICE_SIZE] = root_store->size;
         status[DEV_GET_SIZE_RECORD_SIZE] = root_store->block_size;
         *statuslen = DEV_GET_SIZE_COUNT;
@@ -1732,6 +1735,9 @@ ds_device_get_status (device_t device,
       case DEV_GET_RECORDS:
         if (*statuslen < DEV_GET_RECORDS_COUNT)
           return D_INVALID_SIZE;
+ if (root_store->blocks > UINT32_MAX
+    || root_store->block_size > UINT32_MAX)
+  return D_INVALID_SIZE;
         status[DEV_GET_RECORDS_DEVICE_RECORDS] = root_store->blocks;
         status[DEV_GET_RECORDS_RECORD_SIZE] = root_store->block_size;
         *statuslen = DEV_GET_RECORDS_COUNT;
@@ -1802,7 +1801,6 @@ kern_return_t
 do_mach_notify_no_senders (mach_port_t notify,
    mach_port_mscount_t mscount)
 {
-  ssize_t err;
   static int no_console;
   mach_port_t foo;
   if (notify == pseudo_master_device_port)
@@ -1818,8 +1817,7 @@ do_mach_notify_no_senders (mach_port_t notify,
  {
  bye:
   restore_termstate ();
-  err = write (2, "bye\n", 4);
-  assert_backtrace (err == 4);
+  write_diag ("bye\n", 4);
   host_exit (0);
  }
       else
@@ -1835,6 +1836,7 @@ do_mach_notify_no_senders (mach_port_t notify,
   if (foo != MACH_PORT_NULL)
     mach_port_deallocate (mach_task_self (), foo);
  }
+      return 0;
     }

   return EOPNOTSUPP;
@@ -1853,10 +1849,6 @@ kern_return_t
 do_mach_notify_dead_name (mach_port_t notify,
   mach_port_t name)
 {
-#if 0
-  if (name == child_task && notify == bootport)
-    host_exit (0);
-#endif
   if (notify != dead_task_notification_port)
     return EOPNOTSUPP;
   task_died (name);
@@ -1876,15 +1867,6 @@ S_io_write (mach_port_t object,
   if (object != pseudo_console)
     return EOPNOTSUPP;

-#if 0
-  if (console_send_rights)
-    {
-      mach_port_mod_refs (mach_task_self (), pseudo_console,
-  MACH_PORT_TYPE_SEND, -console_send_rights);
-      console_send_rights = 0;
-    }
-#endif
-
   *amtwritten = write (1, data, datalen);
   return *amtwritten == -1 ? errno : 0;
 }
@@ -1894,17 +1897,20 @@ S_io_read (mach_port_t object,
   if (object != pseudo_console)
     return EOPNOTSUPP;

-#if 0
-  if (console_send_rights)
+  if (amount > CONSOLE_READ_MAX)
+    amount = CONSOLE_READ_MAX;
+  if (amount == 0)
     {
-      mach_port_mod_refs (mach_task_self (), pseudo_console,
-  MACH_PORT_TYPE_SEND, -console_send_rights);
-      console_send_rights = 0;
+      *datalen = 0;
+      return 0;
     }
-#endif

   pthread_spin_lock (&readlock);
-  ioctl (0, FIONREAD, &avail);
+  if (ioctl (0, FIONREAD, &avail) < 0)
+    {
+      pthread_spin_unlock (&readlock);
+      return errno;
+    }
   if (avail)
     {
       data_t orig_data = *data;
@@ -1917,26 +1917,26 @@ S_io_read (mach_port_t object,
  MAP_ANON, 0, 0);
   if (new_data == MAP_FAILED)
     {
-      unlock_readlock();
+      pthread_spin_unlock (&readlock);
       return errno;
     }

   *data = new_data;
         }
       *datalen = read (0, *data, amount);
+      if (*datalen == 0)
+ atomic_store_explicit (&stdin_eof, 1, memory_order_relaxed);
       if (*datalen == -1 && *data != orig_data)
  munmap (*data, amount);
-      unlock_readlock ();
+      pthread_spin_unlock (&readlock);
       return *datalen == -1 ? errno : 0;
     }
   else
     {
       kern_return_t err;
-      unlock_readlock ();
+      pthread_spin_unlock (&readlock);
       err = queue_read (IO_READ, reply_port, reply_type, amount);
-      if (err)
- return err;
-      return MIG_NO_REPLY;
+      return err == D_SUCCESS ? MIG_NO_REPLY : err;
     }
 }

--
2.43.0

Reply via email to