bug-hurd
[Top][All Lists]
Advanced

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

[PATCH 3/3] Use reverse authenticating ioctl-handler protocal


From: Carl Fredrik Hammar
Subject: [PATCH 3/3] Use reverse authenticating ioctl-handler protocal
Date: Wed, 26 Aug 2009 16:45:39 +0200

* hurd/Makefile (interfaces): Add `ioctl_handler_reply'.
* hurd/fd-ioctl-call.c: Check that handlers are provided by the same user.
---
 hurd/Makefile        |    3 +-
 hurd/fd-ioctl-call.c |  157 +++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 158 insertions(+), 2 deletions(-)

diff --git a/hurd/Makefile b/hurd/Makefile
index 768f93a..1286142 100644
--- a/hurd/Makefile
+++ b/hurd/Makefile
@@ -40,7 +40,8 @@ user-interfaces               := $(addprefix hurd/,\
                                       msg msg_reply msg_request \
                                       exec exec_startup crash interrupt \
                                       fs fsys io term tioctl socket ifsock \
-                                      login password pfinet ioctl_handler \
+                                      login password pfinet \
+                                      ioctl_handler ioctl_handler_reply \
                                       )
 server-interfaces      := hurd/msg faultexc
 
diff --git a/hurd/fd-ioctl-call.c b/hurd/fd-ioctl-call.c
index 873a5ca..9b727a6 100644
--- a/hurd/fd-ioctl-call.c
+++ b/hurd/fd-ioctl-call.c
@@ -24,6 +24,158 @@
 #include <dlfcn.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <mach/notify.h>
+#include <sys/mman.h>
+
+
+/* Implement the client-side of the protocol described in
+   <hurd/ioctl_handler.defs>.  The resulting ioctl-handler module is
+   returned in FILE, and the ID block is returned in EUIDS, AUIDS, EGIDS,
+   and AGIDS.  */
+static error_t
+ioctl_handler_get (io_t io,
+                  auth_t auth,
+                  mach_port_t rendezvous,
+                  mach_msg_type_name_t rendezvous_type,
+                  file_t *file,
+                  uid_t **euids, size_t *euids_len,
+                  uid_t **auids, size_t *auids_len,
+                  uid_t **egids, size_t *egids_len,
+                  uid_t **agids, size_t *agids_len)
+{
+  struct {
+    mach_msg_header_t head;
+    mach_msg_type_t error_type;
+    kern_return_t error;
+    mach_msg_type_t file_type;
+    file_t file;
+  } reply;
+  mach_port_t reply_port;
+  error_t err, msg_err;
+
+  reply_port = __mach_reply_port ();
+  if (reply_port == MACH_PORT_NULL)
+    return KERN_RESOURCE_SHORTAGE;
+
+  err = __ioctl_handler_request (io, rendezvous, MACH_MSG_TYPE_MAKE_SEND);
+  if (!err)
+    do
+      err = __auth_server_authenticate (auth,
+                                       rendezvous, rendezvous_type,
+                                       reply_port, MACH_MSG_TYPE_MAKE_SEND,
+                                       euids, euids_len,
+                                       auids, auids_len,
+                                       egids, egids_len,
+                                       agids, agids_len);
+    while (err == EINTR);
+  if (err)
+    {
+      __mach_port_destroy (__mach_task_self (), reply_port);
+      return err;
+    }
+
+  if (!err)
+    msg_err = __mach_msg (&reply.head, MACH_RCV_MSG | MACH_RCV_INTERRUPT,
+                         0, sizeof (reply), reply_port,
+                         MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+
+  __mach_port_destroy (__mach_task_self (), reply_port);
+  if (err)
+    return err;
+  else
+    err = msg_err;
+
+  if (!err && reply.head.msgh_id == MACH_NOTIFY_SEND_ONCE)
+    err = MIG_SERVER_DIED;
+
+  if (!err && reply.head.msgh_id != 39101)
+    {
+      err = MIG_REPLY_MISMATCH;
+      __mach_msg_destroy (&reply.head);
+    }
+
+  if (!err)
+    {
+      if (reply.head.msgh_size != sizeof (reply)
+         || !(reply.head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
+
+         || reply.error_type.msgt_name != MACH_MSG_TYPE_INTEGER_32
+         || reply.error_type.msgt_size != 32
+         || reply.error_type.msgt_number != 1
+         || reply.error_type.msgt_inline != TRUE
+         || reply.error_type.msgt_longform != FALSE
+         || reply.error_type.msgt_deallocate != FALSE
+
+         || reply.file_type.msgt_name != MACH_MSG_TYPE_PORT_SEND
+         || reply.file_type.msgt_size != 32
+         || reply.file_type.msgt_number != 1
+         || reply.file_type.msgt_inline != TRUE
+         || reply.file_type.msgt_longform != FALSE
+         || reply.file_type.msgt_deallocate != FALSE)
+       {
+         err = MIG_TYPE_ERROR;
+         __mach_msg_destroy (&reply.head);
+       }
+      else
+       {
+         err = reply.error;
+         *file = reply.file;
+       }
+    }
+
+  if (err)
+    {
+      __munmap (*euids, *euids_len * sizeof (uid_t));
+      __munmap (*auids, *auids_len * sizeof (uid_t));
+      __munmap (*egids, *egids_len * sizeof (uid_t));
+      __munmap (*agids, *agids_len * sizeof (uid_t));
+    }
+
+  return err;
+}
+
+
+/* Get the ioctl-handler module from IO, and check that the provider
+   is the same user or root, otherwise return EACCES.  */
+static error_t
+ioctl_handler_checked_get (io_t io, file_t *file)
+{
+  auth_t auth;
+  mach_port_t rendezvous;
+  uid_t euid, *euids, *auids, *egids, *agids;
+  size_t euids_len, auids_len, egids_len, agids_len;
+  error_t err;
+  int i;
+
+  rendezvous = __mach_reply_port ();
+  if (rendezvous == MACH_PORT_NULL)
+    return KERN_RESOURCE_SHORTAGE;
+
+  auth = getauth ();
+
+  euids_len = auids_len = egids_len = agids_len = 0;
+  euids = auids = egids = agids = NULL;
+  err = ioctl_handler_get (io, auth, rendezvous, MACH_MSG_TYPE_MAKE_SEND,
+                          file, &euids, &euids_len, &auids, &auids_len,
+                          &egids, &egids_len, &agids, &agids_len);
+  __mach_port_deallocate (__mach_task_self (), auth);
+  __mach_port_destroy (__mach_task_self (), rendezvous);
+  if (err)
+    return err;
+
+  err = EACCES;
+  euid = geteuid ();
+  for (i = 0; i < euids_len; i++)
+    if (euids[i] == euid || euids[i] == 0)
+      err = 0;
+
+  __munmap (euids, euids_len * sizeof (uid_t));
+  __munmap (auids, auids_len * sizeof (uid_t));
+  __munmap (egids, egids_len * sizeof (uid_t));
+  __munmap (agids, agids_len * sizeof (uid_t));
+
+  return err;
+}
 
 
 /* Get PORT's ioctl handler module and load it, returning the linker map
@@ -35,7 +187,10 @@ load_ioctl_handler (io_t port, void **map)
   io_t handler;
   error_t err;
 
-  err = __ioctl_handler_get (port, &handler);
+  /* Avoid spurious "may be used uninitialized" warning.  */
+  handler = MACH_PORT_NULL;
+
+  err = ioctl_handler_checked_get (port, &handler);
   if (!err)
     {
       int fd = _hurd_intern_fd (handler, 0, 1);  /* Consumes HANDLER.  */
-- 
1.6.3.3





reply via email to

[Prev in Thread] Current Thread [Next in Thread]