Hello,

This patch (4/5) fixes various bugs and refines the I/O server routines,
notification handlers and task numbering on the boot server.

Key Changes:

Selection and Readable Routines: The S_io_readable function has been made
to safely check ioctl return values. The `S_io_select` and
`S_io_select_timeout` functions have been redirected via the new
`queue_select` mechanism, which includes appropriate time validation
(EINVAL check).

`S_io_stat` and Character Devices: The `S_io_stat` function has been
updated to explicitly report a character device (`S_IFCHR | 0666`).

Authentication Clean-up: `S_io_reauthenticate` now checks for valid objects
and the authentication server. Memory deallocation errors in
`S_io_reauthenticate`, where incorrect array sizes and pointers were passed
to the `mig_deallocate` function, have been fixed.

Security and Port Checks: A pseudo_privileged_host_port validation has been
added to the S_host_reboot function. printf format strings for Mach ports
have been corrected (%lu).

Task Notification and Listing: Error handling in the
`S_mach_notify_new_task` function has been updated to correctly deallocate
memory for tasks and parent ports in the event of an error. The
`S_processor_set_tasks` function has been updated with overflow checks, and
it has been ensured that `pseudo_kernel` is listed correctly even if it is
not present in the hash table.


The patch is provided below for your reference:
---

>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 4/5] boot: fix io server routines, notifications and task
listing

Fix S_io_readable, route S_io_select/S_io_select_timeout through the
new select queue, report a character device from S_io_stat, make
S_io_reauthenticate check its arguments and fix the deallocation
of the auth arrays, validate S_host_reboot, fix printf formats for
mach ports, handle errors in S_mach_notify_new_task and list the
pseudo kernel task in S_processor_set_tasks.

---
 hurd/boot/boot.c | 133
+++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------
 1 file changed, 63 insertions(+), 70 deletions(-)

diff --git a/hurd/boot/boot.c b/hurd/boot/boot.c
--- a/hurd/boot/boot.c
+++ b/hurd/boot/boot.c
@@ -1957,9 +1961,13 @@ S_io_readable (mach_port_t object,
        mach_msg_type_name_t reply_type,
        vm_size_t *amt)
 {
+  int avail;
+
   if (object != pseudo_console)
     return EOPNOTSUPP;
-  ioctl (0, FIONREAD, amt);
+  if (ioctl (0, FIONREAD, &avail) < 0)
+    return errno;
+  *amt = avail;
   return 0;
 }

@@ -2043,60 +1999,16 @@ S_io_get_icky_async_id (mach_port_t object,
   return EOPNOTSUPP;
 }

-static kern_return_t
-io_select_common (mach_port_t object,
-  mach_port_t reply_port,
-  mach_msg_type_name_t reply_type,
-  struct timespec *tsp, int *type)
-{
-  struct timeval tv, *tvp;
-  fd_set r, w, x;
-  int n;
-
-  if (object != pseudo_console)
-    return EOPNOTSUPP;
-
-  FD_ZERO (&r);
-  FD_ZERO (&w);
-  FD_ZERO (&x);
-  FD_SET (0, &r);
-  FD_SET (0, &w);
-  FD_SET (0, &x);
-
-  if (tsp == NULL)
-    tvp = NULL;
-  else
-    {
-      tv.tv_sec = tsp->tv_sec;
-      tv.tv_usec = tsp->tv_nsec / 1000;
-      tvp = &tv;
-    }
-
-  n = select (1,
-      (*type & SELECT_READ) ? &r : 0,
-      (*type & SELECT_WRITE) ? &w : 0,
-      (*type & SELECT_URG) ? &x : 0,
-      tvp);
-  if (n < 0)
-    return errno;
-
-  if (! FD_ISSET (0, &r))
-    *type &= ~SELECT_READ;
-  if (! FD_ISSET (0, &w))
-    *type &= ~SELECT_WRITE;
-  if (! FD_ISSET (0, &x))
-    *type &= ~SELECT_URG;
-
-  return 0;
-}
-
 kern_return_t
 S_io_select (mach_port_t object,
      mach_port_t reply_port,
      mach_msg_type_name_t reply_type,
      int *type)
 {
-  return io_select_common (object, reply_port, reply_type, NULL, type);
+  if (object != pseudo_console)
+    return EOPNOTSUPP;
+
+  return queue_select (reply_port, reply_type, *type, 0, NULL);
 }

 kern_return_t
@@ -2062,7 +2068,13 @@ S_io_select_timeout (mach_port_t object,
      struct timespec ts,
      int *type)
 {
-  return io_select_common (object, reply_port, reply_type, &ts, type);
+  if (object != pseudo_console)
+    return EOPNOTSUPP;
+
+  if (ts.tv_sec < 0 || ts.tv_nsec < 0 || ts.tv_nsec >= 1000000000L)
+    return EINVAL;
+
+  return queue_select (reply_port, reply_type, *type, 1, &ts);
 }

 kern_return_t
@@ -2081,6 +2082,7 @@ S_io_stat (mach_port_t object,
     return EOPNOTSUPP;

   memset (st, 0, sizeof(struct stat));
+  st->st_mode = S_IFCHR | 0666;
   st->st_blksize = 1024;
   return 0;
 }
@@ -2097,11 +2104,18 @@ S_io_reauthenticate (mach_port_t object,
   mach_msg_type_number_t gulen = 0, aulen = 0, gglen = 0, aglen = 0;
   error_t err;

-  /* XXX: This cannot possibly work, authserver is 0.  */
+  if (object != pseudo_console)
+    return EOPNOTSUPP;
+
+  /* Without an auth server there is nobody to reauthenticate
+     against.  */
+  if (authserver == MACH_PORT_NULL)
+    return EOPNOTSUPP;

   err = mach_port_insert_right (mach_task_self (), object, object,
  MACH_MSG_TYPE_MAKE_SEND);
-  assert_perror_backtrace (err);
+  if (err)
+    return err;

   do
     err = auth_server_authenticate (authserver,
@@ -2120,17 +2120,17 @@ S_io_reauthenticate (mach_port_t object,
   &ag, &aglen);
   while (err == EINTR);

-  if (!err)
+  if (! err)
     {
       mig_deallocate ((vm_address_t) gu, gulen * sizeof *gu);
-      mig_deallocate ((vm_address_t) au, aulen * sizeof *gu);
-      mig_deallocate ((vm_address_t) gg, gglen * sizeof *gu);
-      mig_deallocate ((vm_address_t) au, aulen * sizeof *gu);
+      mig_deallocate ((vm_address_t) au, aulen * sizeof *au);
+      mig_deallocate ((vm_address_t) gg, gglen * sizeof *gg);
+      mig_deallocate ((vm_address_t) ag, aglen * sizeof *ag);
     }
   mach_port_deallocate (mach_task_self (), rend);
   mach_port_deallocate (mach_task_self (), object);

-  return 0;
+  return err;
 }

 kern_return_t
@@ -2419,6 +2422,9 @@ kern_return_t
 S_host_reboot (mach_port_t host_priv,
                int flags)
 {
+  if (host_priv != pseudo_privileged_host_port)
+    return KERN_INVALID_HOST;
+
   fprintf (stderr, "Would %s the system.  Bye.\r\n",
            flags & RB_HALT? "halt": "reboot");
   host_exit (0);
@@ -2475,7 +2475,7 @@ static void
 task_died (mach_port_t name)
 {
   if (verbose > 1)
-    fprintf (stderr, "Task '%u' died.\r\n", name);
+    fprintf (stderr, "Task '%lu' died.\r\n", (unsigned long) name);

   hurd_ihash_remove (&task_ihash, (hurd_ihash_key_t) name);
 }
@@ -2493,7 +2494,8 @@ S_mach_notify_new_task (mach_port_t notify,
     return EOPNOTSUPP;

   if (verbose > 1)
-    fprintf (stderr, "Task '%u' created by task '%u'.\r\n", task, parent);
+    fprintf (stderr, "Task '%lu' created by task '%lu'.\r\n",
+     (unsigned long) task, (unsigned long) parent);

   err = mach_port_request_notification (mach_task_self (), task,
                                         MACH_NOTIFY_DEAD_NAME, 0,
@@ -2505,15 +2505,15 @@ S_mach_notify_new_task (mach_port_t notify,
     goto fail;
   assert_backtrace (! MACH_PORT_VALID (previous));

-  mach_port_mod_refs (mach_task_self (), task, MACH_PORT_RIGHT_SEND, +1);
+  err = mach_port_mod_refs (mach_task_self (), task, MACH_PORT_RIGHT_SEND,
+    +1);
+  if (err)
+    goto fail;
   err = hurd_ihash_add (&task_ihash,
                         (hurd_ihash_key_t) task,
  (hurd_ihash_value_t)(uintptr_t) task);
   if (err)
-    {
-      mach_port_deallocate (mach_task_self (), task);
-      goto fail;
-    }
+    goto fail;

   if (MACH_PORT_VALID (new_task_notification))
     /* Relay the notification.  This consumes task and parent.  */
@@ -2525,6 +2527,8 @@ S_mach_notify_new_task (mach_port_t notify,

  fail:
   task_terminate (task);
+  mach_port_deallocate (mach_task_self (), task);
+  mach_port_deallocate (mach_task_self (), parent);
   return err;
 }

@@ -2536,16 +2549,29 @@ S_processor_set_tasks(mach_port_t processor_set,
       mach_msg_type_number_t *task_listCnt)
 {
   error_t err;
-  size_t i;
+  size_t i, count;
+  int kernel_in_hash = 0;
+  hurd_ihash_value_t value;

-  if (!task_ihash.nr_items)
+  if (processor_set != pseudo_pset)
+    return KERN_INVALID_ARGUMENT;
+
+  if (! MACH_PORT_VALID (pseudo_kernel))
     {
       *task_listCnt = 0;
       return 0;
     }

+  HURD_IHASH_ITERATE (&task_ihash, value)
+    if ((task_t) (uintptr_t) value == pseudo_kernel)
+      kernel_in_hash = 1;
+
+  count = task_ihash.nr_items + (kernel_in_hash ? 0 : 1);
+  if (count > SIZE_MAX / sizeof **task_list)
+    return KERN_RESOURCE_SHORTAGE;
+
   err = vm_allocate (mach_task_self (), (vm_address_t *) task_list,
-     task_ihash.nr_items * sizeof **task_list, 1);
+     count * sizeof **task_list, 1);
   if (err)
     return err;

@@ -2568,14 +2568,14 @@ S_processor_set_tasks(mach_port_t processor_set,
   i = 1;
   HURD_IHASH_ITERATE (&task_ihash, value)
     {
-      task_t task = (task_t)(uintptr_t) value;
+      task_t task = (task_t) (uintptr_t) value;
       if (task == pseudo_kernel)
-        continue;
+ continue;

       (*task_list)[i] = task;
       i += 1;
     }

-  *task_listCnt = task_ihash.nr_items;
+  *task_listCnt = i;
   return 0;
 }
--
2.43.0

Reply via email to