On 10/11/18 20:50, Samuel Thibault wrote:
> The data register port is 0xCFC + (reg & 3); so it could be as much as
> 0xCFF.
> 
> The x86 conf2 method also uses 0xC000 | dev << 8 | reg; so we need to
> also protect 0xc000 - 0xcfff.

See attached patch with corrections.

Thanks, Damien
>From b79f52db69000b0d4bdc75346a109aaf08ec45d8 Mon Sep 17 00:00:00 2001
From: Damien Zammit <dam...@zamaudio.com>
Date: Fri, 9 Nov 2018 22:17:46 -0500
Subject: [PATCH] Restrict access to PCI cfg io ports to one process

---
 i386/i386/io_perm.c                   | 27 ++++++++++++++++++++++-----
 i386/i386/io_perm.h                   |  2 --
 i386/include/mach/i386/mach_i386.defs |  2 --
 3 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/i386/i386/io_perm.c b/i386/i386/io_perm.c
index 3224fdd3..28ed526f 100644
--- a/i386/i386/io_perm.c
+++ b/i386/i386/io_perm.c
@@ -67,10 +67,22 @@
 #include "io_perm.h"
 #include "gdt.h"
 #include "pcb.h"
+
+#define PCI_CFG1_START	0xcf8
+#define PCI_CFG1_END	0xcff
+#define PCI_CFG2_START	0xc000
+#define PCI_CFG2_END	0xcfff
+
+#define IS_IN_PROTECTED_RANGE(from, to) \
+  ( ( ( from <= PCI_CFG1_START ) && ( to >= PCI_CFG1_END ) ) || \
+    ( ( from <= PCI_CFG2_START ) && ( to >= PCI_CFG2_END ) ) )
+
 
 /* Our device emulation ops.  See below, at the bottom of this file.  */
 static struct device_emulation_ops io_perm_device_emulation_ops;
 
+/* Flag to hold PCI io cfg access lock */
+static boolean_t taken_pci_cfg = FALSE;
 
 /* The outtran which allows MIG to convert an io_perm_t object to a port
    representing it.  */
@@ -107,17 +119,15 @@ convert_port_to_io_perm (ipc_port_t port)
   return io_perm;
 }
 
-#if TODO_REMOVE_ME
-/* TODO.  Fix this comment.  */
 /* The destructor which is called when the last send right to a port
    representing an io_perm_t object vanishes.  */
 void
 io_perm_deallocate (io_perm_t io_perm)
 {
-  /* TODO.  Is there anything to deallocate in here?  I don't think so, as we
-     don't allocate anything in `convert_port_to_io_perm'.  */
+  /* We need to check if the io_perm was a PCI cfg one and release it */
+  if (IS_IN_PROTECTED_RANGE(io_perm->from, io_perm->to))
+    taken_pci_cfg = FALSE;
 }
-#endif
 
 /* Our ``no senders'' handling routine.  Deallocate the object.  */
 static
@@ -185,6 +195,10 @@ i386_io_perm_create (const ipc_port_t master_port, io_port_t from, io_port_t to,
   if (from > to)
     return KERN_INVALID_ARGUMENT;
 
+  /* Only one process may take a range that includes PCI cfg registers */
+  if (taken_pci_cfg && IS_IN_PROTECTED_RANGE(from, to))
+    return KERN_PROTECTION_FAILURE;
+
   io_perm_t io_perm;
 
   io_perm = (io_perm_t) kalloc (sizeof *io_perm);
@@ -216,6 +230,9 @@ i386_io_perm_create (const ipc_port_t master_port, io_port_t from, io_port_t to,
 
   *new = io_perm;
 
+  if (IS_IN_PROTECTED_RANGE(from, to))
+    taken_pci_cfg = TRUE;
+
   return KERN_SUCCESS;
 }
 
diff --git a/i386/i386/io_perm.h b/i386/i386/io_perm.h
index a7f1f6fe..b97cf973 100644
--- a/i386/i386/io_perm.h
+++ b/i386/i386/io_perm.h
@@ -58,8 +58,6 @@ typedef struct io_perm *io_perm_t;
 
 extern io_perm_t convert_port_to_io_perm (ipc_port_t);
 extern ipc_port_t convert_io_perm_to_port (io_perm_t);
-#if TODO_REMOVE_ME
 extern void io_perm_deallocate (io_perm_t);
-#endif
 
 #endif /* _I386_IO_PERM_H_ */
diff --git a/i386/include/mach/i386/mach_i386.defs b/i386/include/mach/i386/mach_i386.defs
index 0703d59a..a8cb91ce 100644
--- a/i386/include/mach/i386/mach_i386.defs
+++ b/i386/include/mach/i386/mach_i386.defs
@@ -51,9 +51,7 @@ type	io_perm_t	=	mach_port_t
 #if	KERNEL_SERVER
 		intran: io_perm_t convert_port_to_io_perm(mach_port_t)
 		outtran: mach_port_t convert_io_perm_to_port(io_perm_t)
-#if TODO_REMOVE_ME
 		destructor: io_perm_deallocate(io_perm_t)
-#endif
 #endif	/* KERNEL_SERVER */
 		;
 
-- 
2.17.1

Reply via email to