Hello everyone once again,

I have just brought a series of five patches to your attention; please note
that a new copyright assignment agreement with the
 FSF has not been completed yet. I have attached the patches to this email.
The next set of patches will likely focus on hostmux or usermux.

Thank you for your attention,

Alperen ERKAN
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 2/5] boot: check errors in startup, option parsing and boot script reading

Check the mach_port_* return values in allocate_pseudo_ports, main
and the pseudo device setup, create the wake/select pipes, reject
reserved boot script variables from the kernel command line, report
boot script line numbers, and make read_boot_script handle EINTR and
exponential buffer growth.

---
 hurd/boot/boot.c | 296 ++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
 1 file changed, 184 insertions(+), 112 deletions(-)

diff --git a/hurd/boot/boot.c b/hurd/boot/boot.c
--- a/hurd/boot/boot.c
+++ b/hurd/boot/boot.c
@@ -388,6 +395,13 @@ add_dev_map (const char *dev_name, const char *dev_file)
 
   map->device_name = strdup (dev_name);
   map->file_name = strdup (dev_file);
+  if (! map->device_name || ! map->file_name)
+    {
+      free (map->device_name);
+      free (map->file_name);
+      free (map);
+      return NULL;
+    }
   map->next = dev_map_head;
   dev_map_head = map;
   return map;
@@ -444,7 +445,8 @@ parse_opt (int key, char *arg, struct argp_state *state)
       if (dev_file == NULL)
 	return ARGP_ERR_UNKNOWN;
       *dev_file = 0;
-      add_dev_map (arg, dev_file+1);
+      if (! add_dev_map (arg, dev_file + 1))
+	argp_error (state, "Not enough memory");
       break;
 
     case OPT_PRIVILEGED:
@@ -471,47 +494,70 @@ parse_opt (int key, char *arg, struct argp_state *state)
 static error_t
 allocate_pseudo_ports (void)
 {
+  error_t err;
   mach_port_t old;
 
   /* Allocate a port that we hand out as the privileged host port.  */
-  mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
-		      &pseudo_privileged_host_port);
-  mach_port_insert_right (mach_task_self (),
-			  pseudo_privileged_host_port,
-			  pseudo_privileged_host_port,
-			  MACH_MSG_TYPE_MAKE_SEND);
-  mach_port_move_member (mach_task_self (), pseudo_privileged_host_port,
-			 receive_set);
-  mach_port_request_notification (mach_task_self (),
-                                  pseudo_privileged_host_port,
-				  MACH_NOTIFY_NO_SENDERS, 1,
-				  pseudo_privileged_host_port,
-				  MACH_MSG_TYPE_MAKE_SEND_ONCE, &old);
+  err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+			    &pseudo_privileged_host_port);
+  if (err)
+    return err;
+  err = mach_port_insert_right (mach_task_self (),
+				pseudo_privileged_host_port,
+				pseudo_privileged_host_port,
+				MACH_MSG_TYPE_MAKE_SEND);
+  if (err)
+    return err;
+  err = mach_port_move_member (mach_task_self (), pseudo_privileged_host_port,
+			       receive_set);
+  if (err)
+    return err;
+  err = mach_port_request_notification (mach_task_self (),
+                                        pseudo_privileged_host_port,
+					MACH_NOTIFY_NO_SENDERS, 1,
+					pseudo_privileged_host_port,
+					MACH_MSG_TYPE_MAKE_SEND_ONCE, &old);
+  if (err)
+    return err;
   assert_backtrace (old == MACH_PORT_NULL);
 
   /* Allocate a port that we hand out as the privileged processor set
      port.  */
-  mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
-		      &pseudo_pset);
-  mach_port_move_member (mach_task_self (), pseudo_pset,
-			 receive_set);
+  err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+			    &pseudo_pset);
+  if (err)
+    return err;
+  err = mach_port_move_member (mach_task_self (), pseudo_pset,
+			       receive_set);
+  if (err)
+    return err;
   /* Make one send right that we copy when handing it out.  */
-  mach_port_insert_right (mach_task_self (),
-			  pseudo_pset,
-			  pseudo_pset,
-			  MACH_MSG_TYPE_MAKE_SEND);
+  err = mach_port_insert_right (mach_task_self (),
+				pseudo_pset,
+				pseudo_pset,
+				MACH_MSG_TYPE_MAKE_SEND);
+  if (err)
+    return err;
 
   /* We will receive new task notifications on this port.  */
-  mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
-		      &task_notification_port);
-  mach_port_move_member (mach_task_self (), task_notification_port,
-			 receive_set);
+  err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+			    &task_notification_port);
+  if (err)
+    return err;
+  err = mach_port_move_member (mach_task_self (), task_notification_port,
+			       receive_set);
+  if (err)
+    return err;
 
   /* And information about dying tasks here.  */
-  mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
-		      &dead_task_notification_port);
-  mach_port_move_member (mach_task_self (), dead_task_notification_port,
-			 receive_set);
+  err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+			    &dead_task_notification_port);
+  if (err)
+    return err;
+  err = mach_port_move_member (mach_task_self (), dead_task_notification_port,
+			       receive_set);
+  if (err)
+    return err;
 
   return 0;
 }
@@ -547,20 +544,17 @@ read_boot_script (char **buffer, size_t *length)
   static const char memmsg[] = "Not enough memory\n";
   int i, fd;
   size_t amt, len;
-  ssize_t err;
 
   fd = open (bootscript, O_RDONLY, 0);
   if (fd < 0)
     {
-      err = write (2, filemsg, sizeof (filemsg));
-      assert_backtrace (err == (sizeof (filemsg)));
+      write_diag (filemsg, sizeof filemsg - 1);
       host_exit (1);
     }
   p = buf = malloc (500);
   if (!buf)
     {
-      err = write (2, memmsg, sizeof (memmsg));
-      assert_backtrace (err == (sizeof (memmsg)));
+      write_diag (memmsg, sizeof memmsg - 1);
       host_exit (1);
     }
   len = 500;
@@ -565,20 +572,27 @@ read_boot_script (char **buffer, size_t *length)
   while (1)
     {
       i = read (fd, p, len - (p - buf));
-      if (i <= 0)
+      if (i == 0)
         break;
+      if (i < 0)
+        {
+          if (errno == EINTR)
+            continue;
+          error (1, errno, "%s", bootscript);
+        }
       p += i;
       amt += i;
       if (p == buf + len)
         {
           char *newbuf;
-          size_t newlen = len + 500;
+          size_t newlen = len * 2;
 
+          if (newlen < len)
+            error (1, ENOMEM, "%s", bootscript);
           newbuf = realloc (buf, newlen);
           if (!newbuf)
             {
-              err = write (2, memmsg, sizeof (memmsg));
-              assert_backtrace (err == (sizeof (memmsg)));
+              write_diag (memmsg, sizeof memmsg - 1);
               host_exit (1);
             }
           p = newbuf + len;
@@ -616,12 +613,9 @@ const char *default_boot_script =
   " -T device ${root-device} $(task-create) $(task-resume)"
   "\n"
 
-  /* Now the exec server; to load the dynamically-linked exec server
-     program, we have the boot loader in fact load and run ld.so,
-     which in turn loads and runs /hurd/exec.  This task is created,
-     and its task port saved in ${exec-task} to be passed to the fs
-     above, but it is left suspended; the fs will resume the exec task
-     once it is ready.  */
+  /* Now the exec server.  It is created suspended; the bootstrap
+     filesystem resumes it once it is ready.  Its task port is saved
+     in ${exec-task} to be passed to the fs above.  */
   "/hurd/exec.static $(exec-task=task-create)"
   "\n";
 
@@ -658,8 +664,14 @@ main (int argc, char **argv, char **envp)
   if (privileged)
     strcat (bootstrap_args, "f");
 
-  mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_PORT_SET,
-		      &receive_set);
+  err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_PORT_SET,
+			    &receive_set);
+  if (err)
+    error (12, err, "mach_port_allocate");
+
+  if (pipe2 (wake_pipe, O_NONBLOCK | O_CLOEXEC) < 0
+      || pipe2 (select_pipe, O_NONBLOCK | O_CLOEXEC) < 0)
+    error (13, errno, "pipe2");
 
   if (root_store->class == &store_device_class && root_store->name
       && (root_store->flags & STORE_ENFORCED)
@@ -678,41 +703,66 @@ main (int argc, char **argv, char **envp)
     /* Pass a magic value that we can use to do I/O to ROOT_STORE.  */
     {
       bootdevice = "pseudo-root";
-      mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
-			  &pseudo_root);
-      mach_port_move_member (mach_task_self (), pseudo_root, receive_set);
+      err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+				&pseudo_root);
+      if (err)
+	error (14, err, "mach_port_allocate");
+      err = mach_port_move_member (mach_task_self (), pseudo_root, receive_set);
+      if (err)
+	error (14, err, "mach_port_move_member");
     }
 
-  mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
-		      &pseudo_master_device_port);
-  mach_port_insert_right (mach_task_self (),
-			  pseudo_master_device_port,
-			  pseudo_master_device_port,
-			  MACH_MSG_TYPE_MAKE_SEND);
-  mach_port_move_member (mach_task_self (), pseudo_master_device_port,
-			 receive_set);
-  mach_port_request_notification (mach_task_self (), pseudo_master_device_port,
-				  MACH_NOTIFY_NO_SENDERS, 1,
-				  pseudo_master_device_port,
-				  MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo);
+  err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+			    &pseudo_master_device_port);
+  if (err)
+    error (15, err, "mach_port_allocate");
+  err = mach_port_insert_right (mach_task_self (),
+				pseudo_master_device_port,
+				pseudo_master_device_port,
+				MACH_MSG_TYPE_MAKE_SEND);
+  if (err)
+    error (15, err, "mach_port_insert_right");
+  err = mach_port_move_member (mach_task_self (), pseudo_master_device_port,
+			       receive_set);
+  if (err)
+    error (15, err, "mach_port_move_member");
+  err = mach_port_request_notification (mach_task_self (),
+					pseudo_master_device_port,
+					MACH_NOTIFY_NO_SENDERS, 1,
+					pseudo_master_device_port,
+					MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo);
+  if (err)
+    error (15, err, "mach_port_request_notification");
   if (foo != MACH_PORT_NULL)
     mach_port_deallocate (mach_task_self (), foo);
 
-  mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
-		      &pseudo_console);
-  mach_port_move_member (mach_task_self (), pseudo_console, receive_set);
-  mach_port_request_notification (mach_task_self (), pseudo_console,
-				  MACH_NOTIFY_NO_SENDERS, 1, pseudo_console,
-				  MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo);
+  err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+			    &pseudo_console);
+  if (err)
+    error (16, err, "mach_port_allocate");
+  err = mach_port_move_member (mach_task_self (), pseudo_console, receive_set);
+  if (err)
+    error (16, err, "mach_port_move_member");
+  err = mach_port_request_notification (mach_task_self (), pseudo_console,
+					MACH_NOTIFY_NO_SENDERS, 1, pseudo_console,
+					MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo);
+  if (err)
+    error (16, err, "mach_port_request_notification");
   if (foo != MACH_PORT_NULL)
     mach_port_deallocate (mach_task_self (), foo);
 
-  mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
-		      &pseudo_time);
-  mach_port_move_member (mach_task_self (), pseudo_time, receive_set);
-  mach_port_request_notification (mach_task_self (), pseudo_time,
-				  MACH_NOTIFY_NO_SENDERS, 1, pseudo_time,
-				  MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo);
+  err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+			    &pseudo_time);
+  if (err)
+    error (17, err, "mach_port_allocate");
+  err = mach_port_move_member (mach_task_self (), pseudo_time, receive_set);
+  if (err)
+    error (17, err, "mach_port_move_member");
+  err = mach_port_request_notification (mach_task_self (), pseudo_time,
+					MACH_NOTIFY_NO_SENDERS, 1, pseudo_time,
+					MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo);
+  if (err)
+    error (17, err, "mach_port_request_notification");
   if (foo != MACH_PORT_NULL)
     mach_port_deallocate (mach_task_self (), foo);
 
@@ -759,7 +761,9 @@ main (int argc, char **argv, char **envp)
         error (1, err, "task_create");
 
       /* Give it a name so it's easy to spot it from the real kernel.  */
-      task_set_name (pseudo_kernel, "pseudo_kernel");
+      err = task_set_name (pseudo_kernel, "pseudo_kernel");
+      if (err)
+	error (1, err, "task_set_name");
     }
 
   if (kernel_command_line == 0)
@@ -788,49 +805,66 @@ main (int argc, char **argv, char **envp)
 				   VAL_STR, (intptr_t) bootstrap_args))
     {
       static const char msg[] = "error setting variable";
-      size_t len = strlen (msg);
-      ssize_t err2 = write (2, msg, len);
-      assert_backtrace (err2 == len);
+      write_diag (msg, sizeof msg - 1);
       host_exit (1);
     }
 
   /* Turn each `FOO=BAR' word in the command line into a boot script
      variable ${FOO} with value BAR.  */
   {
-    int len = strlen (kernel_command_line) + 1;
-    char *s = memcpy (alloca (len), kernel_command_line, len);
+    char *s = strdup (kernel_command_line);
     char *word;
 
+    if (! s)
+      error (1, ENOMEM, "strdup");
+
     while ((word = strsep (&s, " \t")) != 0)
       {
        char *eq = strchr (word, '=');
        if (eq == 0)
          continue;
        *eq++ = '\0';
+       if (! strcmp (word, "host-port")
+           || ! strcmp (word, "device-port")
+           || ! strcmp (word, "kernel-task")
+           || ! strcmp (word, "kernel-command-line")
+           || ! strcmp (word, "root-device")
+           || ! strcmp (word, "boot-args"))
+         {
+           fprintf (stderr, "ignoring reserved boot variable %s\n", word);
+           continue;
+         }
        err = boot_script_set_variable (word, VAL_STR, (intptr_t) eq);
        if (err)
          {
            char *msg;
-           ssize_t err2 = asprintf (&msg, "cannot set boot-script variable %s: %s\n",
-				    word, boot_script_error_string (err));
-           assert_backtrace (err2 != -1);
-           len = strlen (msg);
-           err2 = write (2, msg, len);
-           assert_backtrace (err2 == len);
-           free (msg);
+           if (asprintf (&msg, "cannot set boot-script variable %s: %s\n",
+                         word, boot_script_error_string (err)) >= 0)
+             {
+               write_diag (msg, strlen (msg));
+               free (msg);
+             }
            host_exit (1);
          }
       }
+    free (s);
   }
 
   /* Parse the boot script.  */
   {
     char *p, *line;
     size_t amt;
+    int lineno = 1;
+
     if (bootscript)
       read_boot_script (&buf, &amt);
     else
-      buf = strdup (default_boot_script), amt = strlen (default_boot_script);
+      {
+	buf = strdup (default_boot_script);
+	if (! buf)
+	  error (1, ENOMEM, "strdup");
+	amt = strlen (default_boot_script);
+      }
 
     line = p = buf;
     while (1)
@@ -858,39 +852,33 @@ main (int argc, char **argv, char **envp)
 	err = boot_script_parse_line (0, line);
 	if (err)
 	  {
-	    ssize_t err2;
 	    char *str;
-	    int i;
 
 	    str = boot_script_error_string (err);
-	    i = strlen (str);
-	    err2 = write (2, str, i);
-	    assert_backtrace (err2 == i);
-	    err2 = write (2, " in `", 5);
-	    assert_backtrace (err2 == 5);
-	    i = strlen (line);
-	    err2 = write (2, line, i);
-	    assert_backtrace (err2 == i);
-	    err2 = write (2, "'\n", 2);
-	    assert_backtrace (err2 == 2);
+	    fprintf (stderr, "line %d: ", lineno);
+	    write_diag (str, strlen (str));
+	    write_diag (" in `", 5);
+	    write_diag (line, strlen (line));
+	    write_diag ("'\n", 2);
 	    host_exit (1);
 	  }
 	if (p == buf + amt)
 	  break;
 	line = ++p;
+	lineno++;
       }
   }
 
   if (index (bootstrap_args, 'd'))
     {
       static const char msg[] = "Pausing. . .";
-      size_t msg_len = sizeof (msg) - 1;
       char c;
-      ssize_t err2;
-      err2 = write (2, msg, msg_len);
-      assert_backtrace (err2 == msg_len);
-      err2 = read (0, &c, 1);
-      assert_backtrace (err2 == 1);
+      ssize_t r;
+
+      write_diag (msg, sizeof msg - 1);
+      do
+	r = read (0, &c, 1);
+      while (r < 0 && errno == EINTR);
     }
 
   init_termstate ();
@@ -895,14 +891,10 @@ main (int argc, char **argv, char **envp)
     err = boot_script_exec ();
     if (err)
       {
-	ssize_t err2;
 	char *str = boot_script_error_string (err);
-	int i = strlen (str);
 
-	err2 = write (2, str, i);
-	assert_backtrace (err2 == i);
-	err2 = write (2, "\n",  1);
-	assert_backtrace (err2 == 1);
+	write_diag (str, strlen (str));
+	write_diag ("\n",  1);
 	host_exit (1);
       }
     free (buf);
-- 
2.43.0
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 1/5] boot: fix terminal state handling and add diagnostic helpers

Add copyright header, new includes, and rework the terminal state
management: track initialization, restore the tty on exit, and handle
SIGCONT/SIGTSTP so raw mode survives stop/continue.  Add the
write_diag helper, drop unused globals, and declare the console
input event infrastructure (wake/select pipes, stdin_eof flag).

---
 hurd/boot/boot.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 76 insertions(+), 17 deletions(-)

diff --git a/hurd/boot/boot.c b/hurd/boot/boot.c
--- a/hurd/boot/boot.c
+++ b/hurd/boot/boot.c
@@ -2,6 +3,7 @@
    as if we were the kernel.
    Copyright (C) 1993,94,95,96,97,98,99,2000,01,02,2006,14,16
      Free Software Foundation, Inc.
+   Copyright (C) 2026 Alperen ERKAN
 
    This file is part of the GNU Hurd.
 
@@ -60,8 +64,12 @@
 #include <hurd/auth.h>
 
 #include <unistd.h>
-#include <fcntl.h>
 #include <signal.h>
+#include <poll.h>
+#include <stdatomic.h>
+#include <time.h>
+#include <limits.h>
+#include <stdint.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <termios.h>
@@ -84,9 +125,50 @@ static int privileged;
 static int want_privileged;
 
 static struct termios orig_tty_state;
+static int termstate_initialized;
 static int isig;
 static char *kernel_command_line;
 
+static void
+restore_termstate (void)
+{
+  if (! termstate_initialized)
+    return;
+  tcsetattr (0, 0, &orig_tty_state);
+  termstate_initialized = 0;
+}
+
+static void
+sig_handler (int sig)
+{
+  switch (sig)
+    {
+    case SIGCONT:
+      /* Re-enter raw mode after being stopped.  */
+      if (termstate_initialized)
+	{
+	  struct termios tty_state = orig_tty_state;
+	  cfmakeraw (&tty_state);
+	  if (isig)
+	    tty_state.c_lflag |= ISIG;
+	  tcsetattr (0, 0, &tty_state);
+	}
+      break;
+
+    case SIGTSTP:
+      restore_termstate ();
+      signal (SIGTSTP, SIG_DFL);
+      raise (SIGTSTP);
+      break;
+
+    default:
+      restore_termstate ();
+      signal (sig, SIG_DFL);
+      raise (sig);
+      break;
+    }
+}
+
 static void
 init_termstate (void)
 {
@@ -143,12 +145,14 @@ init_termstate (void)
 
   if (tcsetattr (0, 0, &tty_state) < 0)
     error (11, errno, "tcsetattr");
-}
 
-static void
-restore_termstate (void)
-{
-  tcsetattr (0, 0, &orig_tty_state);
+  termstate_initialized = 1;
+
+  atexit (restore_termstate);
+  signal (SIGINT, sig_handler);
+  signal (SIGTERM, sig_handler);
+  signal (SIGTSTP, sig_handler);
+  signal (SIGCONT, sig_handler);
 }
 
 #define host_fstat fstat
@@ -163,6 +173,16 @@ host_exit (int status)
   exit (status);
 }
 
+/* Best-effort write of a diagnostic message to stderr.  */
+static void
+write_diag (const char *msg, size_t len)
+{
+  ssize_t err;
+  do
+    err = write (2, msg, len);
+  while (err < 0 && errno == EINTR);
+}
+
 int verbose;
 
 mach_port_t privileged_host_port, master_device_port;
@@ -195,17 +185,7 @@ struct store *root_store;
 pthread_spinlock_t queuelock = PTHREAD_SPINLOCK_INITIALIZER;
 pthread_spinlock_t readlock = PTHREAD_SPINLOCK_INITIALIZER;
 
-mach_port_t php_child_name, psmdp_child_name, taskname;
-
-task_t child_task;
-mach_port_t bootport;
-
-int console_mscount;
-
-vm_address_t fs_stack_base;
-vm_size_t fs_stack_size;
-
-char *fsname;
+mach_port_mscount_t console_mscount;
 
 char bootstrap_args[100] = "-";
 char *bootdevice = 0;
@@ -315,6 +326,17 @@ boot_demuxer (mach_msg_header_t *inp,
 
 static void read_reply (void);
 static void * msg_thread (void *);
+static void * select_thread (void *);
+
+/* Console input event handling.  The main thread polls the host stdin
+   only while console read requests are queued; the message threads
+   wake it via WAKE_PIPE.  */
+static int wake_pipe[2];
+static int select_pipe[2];
+static _Atomic int stdin_eof;
+
+/* Maximum size of a single console read request (out-of-line).  */
+#define CONSOLE_READ_MAX (16 * 1024 * 1024)
 
 const char *argp_program_version = STANDARD_HURD_VERSION (boot);
 
-- 
2.43.0
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
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 5/5] boot: harden boot script parser and userland loader

In boot_script.c, propagate parse errors correctly and guard against
symbol reference cycles while resolving symbol values.  In
userland-boot.c, read files fully, validate ELF program headers and
segment bounds before loading, bound the synthesized port name, and
check the vm/thread operations in boot_script_exec_cmd.

---
 hurd/boot/boot_script.c   | 18 ++++-
 hurd/boot/userland-boot.c | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++---------------
 2 files changed, 215 insertions(+), 64 deletions(-)

diff --git a/hurd/boot/boot_script.c b/hurd/boot/boot_script.c
--- a/hurd/boot/boot_script.c
+++ b/hurd/boot/boot_script.c
@@ -1,6 +2,7 @@
 /* Boot script parser for Mach.  */
 
 /* Written by Shantanu Goel ([email protected]).  */
+/* Copyright (C) 2026 Alperen ERKAN */
 
 #include <mach/mach_types.h>
 #if !KERNEL || OSKIT_MACH
@@ -340,7 +343,10 @@ boot_script_parse_line (void *hook, char *cmdline)
 
 	      /* Only values are allowed in ${...} constructs.  */
 	      if (end_char == '}' && s->type == VAL_FUNC)
-		return BOOT_SCRIPT_INVALID_SYM;
+		{
+		  error = BOOT_SCRIPT_INVALID_SYM;
+		  goto bad;
+		}
 
 	      /* Check that assignment is valid.  */
 	      if (c == '=' && s->type == VAL_FUNC)
@@ -559,9 +567,17 @@ boot_script_exec (void)
 		{
 		  struct sym *sym = (struct sym *) arg->val;
 
-		  /* Resolve symbol value.  */
-		  while (sym->type == VAL_SYM)
+		  /* Resolve symbol value.  Guard against reference
+		     cycles.  */
+		  unsigned int depth = 0;
+		  while (sym->type == VAL_SYM
+			 && depth++ <= (unsigned int) symtab_index)
 		    sym = (struct sym *) sym->val;
+		  if (sym->type == VAL_SYM)
+		    {
+		      error = BOOT_SCRIPT_SYNTAX_ERROR;
+		      goto done;
+		    }
 		  if (sym->type == VAL_NONE)
 		    {
 		      error = BOOT_SCRIPT_UNDEF_SYM;
diff --git a/hurd/boot/userland-boot.c b/hurd/boot/userland-boot.c
--- a/hurd/boot/userland-boot.c
+++ b/hurd/boot/userland-boot.c
@@ -1,5 +2,6 @@
 /* boot_script.c support functions for running in a Mach user task.
    Copyright (C) 2001 Free Software Foundation, Inc.
+   Copyright (C) 2026 Alperen ERKAN
 
    This file is part of the GNU Hurd.
 
@@ -25,9 +27,11 @@
 #include <mach/machine/vm_param.h> /* For VM_XXX_ADDRESS */
 #include <mach/gnumach.h> /* For task_set_name */
 #include <stdlib.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/mman.h>
+#include <sys/stat.h>
 #include <unistd.h>
 #include <errno.h>
 #include <error.h>
@@ -39,6 +77,44 @@
 #include "boot_script.h"
 #include "private.h"
 
+/* Read exactly LEN bytes from FD, returning 0 on success.  */
+static int
+read_full (int fd, void *buf, size_t len)
+{
+  char *p = buf;
+  while (len > 0)
+    {
+      ssize_t n = read (fd, p, len);
+      if (n == 0)
+	return -1;
+      if (n < 0)
+	{
+	  if (errno == EINTR)
+	    continue;
+	  return -1;
+	}
+      p += n;
+      len -= n;
+    }
+  return 0;
+}
+
+static void __attribute__ ((__noreturn__))
+load_fail (task_t t, const char *file)
+{
+  char msg[] = ": truncated or unreadable bootstrap file\n";
+  size_t len = strlen (file);
+  ssize_t err;
+  do
+    err = write (2, file, len);
+  while (err < 0 && errno == EINTR);
+  do
+    err = write (2, msg, sizeof msg - 1);
+  while (err < 0 && errno == EINTR);
+  task_terminate (t);
+  exit (1);
+}
+
 void *
 boot_script_malloc (unsigned int size)
 {
@@ -163,9 +168,14 @@ boot_script_insert_right (struct cmd *cmd, mach_port_t port, mach_port_t *name)
   *name = MACH_PORT_NULL;
   do
     {
+      if (*name >= (1 << 20))
+	{
+	  error (0, ENOMEM, "%s: mach_port_insert_right", cmd->path);
+	  return BOOT_SCRIPT_MACH_ERROR;
+	}
       *name += 1;
       err = mach_port_insert_right (cmd->task,
-                                    *name, port, MACH_MSG_TYPE_COPY_SEND);
+				    *name, port, MACH_MSG_TYPE_COPY_SEND);
     }
   while (err == KERN_NAME_EXISTS);
 
@@ -239,44 +300,105 @@ load_image (task_t t,
       exit (1);
     }
 
-  err = read (fd, &hdr, sizeof hdr);
-  assert_backtrace (err == (sizeof hdr));
+  if (read_full (fd, &hdr, sizeof hdr) < 0)
+    {
+      close (fd);
+      load_fail (t, file);
+    }
   /* File must have magic ELF number.  */
   if (hdr.e.e_ident[0] == 0177 && hdr.e.e_ident[1] == 'E' &&
       hdr.e.e_ident[2] == 'L' && hdr.e.e_ident[3] == 'F')
     {
-      ElfW(Phdr) phdrs[hdr.e.e_phnum], *ph;
-      lseek (fd, hdr.e.e_phoff, SEEK_SET);
-      err = read (fd, phdrs, sizeof phdrs);
-      assert_backtrace (err == (sizeof phdrs));
-      for (ph = phdrs; ph < &phdrs[sizeof phdrs/sizeof phdrs[0]]; ++ph)
-	if (ph->p_type == PT_LOAD)
+      /* Refuse pathological or extended program-header counts;
+	 we do not support PN_XNUM.  */
+      if (hdr.e.e_phnum == 0 || hdr.e.e_phnum >= PN_XNUM)
+	{
+	  close (fd);
+	  load_fail (t, file);
+	}
+
+      {
+	struct stat st;
+	ElfW(Phdr) *phdrs, *ph;
+
+	if (fstat (fd, &st) < 0
+	    || hdr.e.e_phoff > (uintmax_t) st.st_size
+	    || (uintmax_t) hdr.e.e_phnum * sizeof (ElfW(Phdr))
+	       > (uintmax_t) st.st_size - hdr.e.e_phoff)
+	  {
+	    close (fd);
+	    load_fail (t, file);
+	  }
+
+	phdrs = malloc (hdr.e.e_phnum * sizeof (ElfW(Phdr)));
+	if (! phdrs)
+	  {
+	    close (fd);
+	    load_fail (t, file);
+	  }
+	if (lseek (fd, hdr.e.e_phoff, SEEK_SET) < 0
+	    || read_full (fd, phdrs,
+			  hdr.e.e_phnum * sizeof (ElfW(Phdr))) < 0)
 	  {
-	    vm_address_t buf;
-	    vm_size_t offs = ph->p_offset & (ph->p_align - 1);
-	    vm_size_t bufsz = round_page (ph->p_filesz + offs);
-
-	    buf = (vm_address_t) mmap (0, bufsz,
-				       PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
-	    assert_backtrace (buf != MAP_FAILED);
-
-	    lseek (fd, ph->p_offset, SEEK_SET);
-	    err = read (fd, (void *)(buf + offs), ph->p_filesz);
-	    assert_backtrace (err == (ph->p_filesz));
-
-	    ph->p_memsz = ((ph->p_vaddr + ph->p_memsz + ph->p_align - 1)
-			   & ~(ph->p_align - 1));
-	    ph->p_vaddr &= ~(ph->p_align - 1);
-	    ph->p_memsz -= ph->p_vaddr;
-
-	    vm_allocate (t, (vm_address_t*)&ph->p_vaddr, ph->p_memsz, 0);
-	    vm_write (t, ph->p_vaddr, buf, bufsz);
-	    munmap ((caddr_t) buf, bufsz);
-	    vm_protect (t, ph->p_vaddr, ph->p_memsz, 0,
-			((ph->p_flags & PF_R) ? VM_PROT_READ : 0) |
-			((ph->p_flags & PF_W) ? VM_PROT_WRITE : 0) |
-			((ph->p_flags & PF_X) ? VM_PROT_EXECUTE : 0));
+	    free (phdrs);
+	    close (fd);
+	    load_fail (t, file);
 	  }
+	for (ph = phdrs; ph < &phdrs[hdr.e.e_phnum]; ++ph)
+	  if (ph->p_type == PT_LOAD)
+	    {
+	      /* A segment must lie within the file and have a
+		 valid, power-of-two alignment.  */
+	      if (ph->p_align == 0
+		  || (ph->p_align & (ph->p_align - 1)) != 0
+		  || ph->p_offset > (uintmax_t) st.st_size
+		  || (uintmax_t) ph->p_filesz
+		     > (uintmax_t) st.st_size - ph->p_offset
+		  || ph->p_memsz < ph->p_filesz)
+		continue;
+
+	      {
+		vm_address_t buf;
+		vm_size_t offs = ph->p_offset & (ph->p_align - 1);
+		vm_size_t bufsz = round_page (ph->p_filesz + offs);
+
+		buf = (vm_address_t) mmap (0, bufsz, PROT_READ|PROT_WRITE,
+					   MAP_ANON, 0, 0);
+		if (buf == MAP_FAILED
+		    || lseek (fd, ph->p_offset, SEEK_SET) < 0
+		    || read_full (fd, (void *) (buf + offs), ph->p_filesz) < 0)
+		  {
+		    if (buf != MAP_FAILED)
+		      munmap ((caddr_t) buf, bufsz);
+		    free (phdrs);
+		    close (fd);
+		    load_fail (t, file);
+		  }
+
+		ph->p_memsz = ((ph->p_vaddr + ph->p_memsz + ph->p_align - 1)
+			       & ~(ph->p_align - 1));
+		ph->p_vaddr &= ~(ph->p_align - 1);
+		ph->p_memsz -= ph->p_vaddr;
+
+		if (vm_allocate (t, (vm_address_t *) &ph->p_vaddr, ph->p_memsz,
+				 0)
+		    || vm_write (t, ph->p_vaddr, buf, bufsz))
+		  {
+		    munmap ((caddr_t) buf, bufsz);
+		    free (phdrs);
+		    close (fd);
+		    load_fail (t, file);
+		  }
+		munmap ((caddr_t) buf, bufsz);
+		vm_protect (t, ph->p_vaddr, ph->p_memsz, 0,
+			    ((ph->p_flags & PF_R) ? VM_PROT_READ : 0) |
+			    ((ph->p_flags & PF_W) ? VM_PROT_WRITE : 0) |
+			    ((ph->p_flags & PF_X) ? VM_PROT_EXECUTE : 0));
+	      }
+	    }
+	free (phdrs);
+      }
+      close (fd);
       return hdr.e.e_entry;
     }
   else
@@ -357,8 +361,12 @@ load_image (task_t t,
       buf = mmap (0, rndamount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
       assert_backtrace (buf != MAP_FAILED);
       lseek (fd, sizeof hdr.a - headercruft, SEEK_SET);
-      err = read (fd, buf, amount);
-      assert_backtrace (err == amount);
+      if (read_full (fd, buf, amount) < 0)
+	{
+	  munmap ((caddr_t) buf, rndamount);
+	  close (fd);
+	  load_fail (t, file);
+	}
       vm_allocate (t, &base, rndamount, 0);
       vm_write (t, base, (vm_address_t) buf, rndamount);
       if (magic != OMAGIC)
@@ -372,59 +382,69 @@ load_image (task_t t,
 
       bssstart = base + hdr.a.a_text + hdr.a.a_data + headercruft;
       bsspagestart = round_page (bssstart);
-      vm_allocate (t, &bsspagestart,
-		   hdr.a.a_bss - (bsspagestart - bssstart), 0);
+      if (hdr.a.a_bss > bsspagestart - bssstart)
+	vm_allocate (t, &bsspagestart,
+		     hdr.a.a_bss - (bsspagestart - bssstart), 0);
 
+      close (fd);
       return hdr.a.a_entry;
     }
 }
 
+static void
+write_str (const char *msg, size_t len)
+{
+  ssize_t err;
+  do
+    err = write (2, msg, len);
+  while (err < 0 && errno == EINTR);
+}
+
 int
 boot_script_exec_cmd (void *hook,
 		      mach_port_t task, char *path, int argc,
 		      char **argv, char *strings, int stringlen)
 {
   char *args, *p;
-  int arg_len, i;
+  int i;
+  size_t arg_len, len;
   mach_msg_type_number_t reg_size;
   void *arg_pos;
   vm_offset_t stack_start, stack_end;
   vm_address_t startpc, str_start;
   thread_t thread;
-  ssize_t err;
-  size_t len;
+  error_t err;
 
   len = strlen (path);
-  err = write (2, path, len);
-  assert_backtrace (err == len);
+  write_str (path, len);
   for (i = 1; i < argc; ++i)
     {
       int quote = !! index (argv[i], ' ') || !! index (argv[i], '\t');
-      err = write (2, " ", 1);
-      assert_backtrace (err == 1);
+      write_str (" ", 1);
       if (quote)
-	{
-	  err = write (2, "\"", 1);
-	  assert_backtrace (err == 1);
-	}
+	write_str ("\"", 1);
       len = strlen (argv[i]);
-      err = write (2, argv[i], len);
-      assert_backtrace (err == len);
+      write_str (argv[i], len);
       if (quote)
-	{
-	  err = write (2, "\"", 1);
-	  assert_backtrace (err == 1);
-	}
+	write_str ("\"", 1);
     }
-  err = write (2, "\r\n", 2);
-  assert_backtrace (err == 2);
+  write_str ("\r\n", 2);
 
   startpc = load_image (task, path);
   arg_len = stringlen + (argc + 2) * sizeof (char *) + sizeof (intptr_t);
   arg_len += 5 * sizeof (intptr_t);
+  if (arg_len > 16 * 1024 * 1024)
+    {
+      error (0, ENOMEM, "%s: argument list too long", path);
+      return BOOT_SCRIPT_EXEC_ERROR;
+    }
   stack_end = VM_MAX_ADDRESS;
   stack_start = VM_MAX_ADDRESS - 16 * 1024 * 1024;
-  vm_allocate (task, &stack_start, stack_end - stack_start, FALSE);
+  if (vm_allocate (task, &stack_start, stack_end - stack_start, FALSE))
+    {
+      error (0, ENOMEM, "%s: vm_allocate", path);
+      return BOOT_SCRIPT_EXEC_ERROR;
+    }
   arg_pos = (void *) ((stack_end - arg_len) & ~(sizeof (intptr_t) - 1));
   args = mmap (0, stack_end - trunc_page ((vm_offset_t) arg_pos),
 	       PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
@@ -455,12 +467,24 @@ boot_script_exec_cmd (void *hook,
   p = (void *) p + sizeof (char *);
   memcpy (p, strings, stringlen);
   memset (args, 0, (vm_offset_t)arg_pos & (vm_page_size - 1));
-  vm_write (task, trunc_page ((vm_offset_t) arg_pos), (vm_address_t) args,
-	    stack_end - trunc_page ((vm_offset_t) arg_pos));
+  if (vm_write (task, trunc_page ((vm_offset_t) arg_pos),
+		(vm_address_t) args,
+		stack_end - trunc_page ((vm_offset_t) arg_pos)))
+    {
+      error (0, ENOMEM, "%s: vm_write", path);
+      munmap ((caddr_t) args,
+	      stack_end - trunc_page ((vm_offset_t) arg_pos));
+      return BOOT_SCRIPT_EXEC_ERROR;
+    }
   munmap ((caddr_t) args,
 	  stack_end - trunc_page ((vm_offset_t) arg_pos));
 
-  thread_create (task, &thread);
+  err = thread_create (task, &thread);
+  if (err)
+    {
+      error (0, err, "%s: thread_create", path);
+      return BOOT_SCRIPT_EXEC_ERROR;
+    }
 #ifdef i386_THREAD_STATE_COUNT
   {
     struct i386_thread_state regs;
@@ -515,7 +521,13 @@ boot_script_exec_cmd (void *hook,
 # error needs to be ported
 #endif
 
-  thread_resume (thread);
+  err = thread_resume (thread);
+  if (err)
+    {
+      error (0, err, "%s: thread_resume", path);
+      mach_port_deallocate (mach_task_self (), thread);
+      return BOOT_SCRIPT_EXEC_ERROR;
+    }
   mach_port_deallocate (mach_task_self (), thread);
   return 0;
 }
-- 
2.43.0
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