]> Zhao Yanbai Git Server - minix.git/commitdiff
Store resource lists for drivers. Limited checks to enforce those lists.
authorPhilip Homburg <philip@cs.vu.nl>
Fri, 27 Jan 2006 13:21:12 +0000 (13:21 +0000)
committerPhilip Homburg <philip@cs.vu.nl>
Fri, 27 Jan 2006 13:21:12 +0000 (13:21 +0000)
kernel/priv.h
kernel/system/do_devio.c
kernel/system/do_irqctl.c
kernel/system/do_privctl.c
kernel/table.c

index db541b3ac72bb65bb82c8ea948bf790303bc2dd4..04adfbeba4599c1b9a6bc2047f71a161c092f145 100755 (executable)
 #include "protect.h"
 #include "const.h"
 #include "type.h"
+
+/* Max. number of I/O ranges that can be assigned to a process */
+#define NR_IO_RANGE    10
+
+/* Max. number of device memory ranges that can be assigned to a process */
+#define NR_MEM_RANGE   10
+
+/* Max. number of IRQs that can be assigned to a process */
+#define NR_IRQ 4
  
 struct priv {
   proc_nr_t s_proc_nr;         /* number of associated process */
@@ -33,6 +42,15 @@ struct priv {
   timer_t s_alarm_timer;       /* synchronous alarm timer */ 
   struct far_mem s_farmem[NR_REMOTE_SEGS];  /* remote memory map */
   reg_t *s_stack_guard;                /* stack guard word for kernel tasks */
+
+  int s_nr_io_range;
+  struct io_range s_io_tab[NR_IO_RANGE];
+
+  int s_nr_mem_range;
+  struct mem_range s_mem_tab[NR_MEM_RANGE];
+
+  int s_nr_irq;
+  int s_irq_tab[NR_IRQ];
 };
 
 /* Guard word for task stacks. */
@@ -43,6 +61,11 @@ struct priv {
 #define BILLABLE       0x04    /* some processes are not billable */
 #define SYS_PROC       0x10    /* system processes are privileged */
 #define SENDREC_BUSY   0x20    /* sendrec() in progress */
+#define CHECK_IO_PORT  0x40    /* Check whether an I/O request is allowed */
+#define CHECK_MEM      0x80    /* Check whether a (vm) memory map request is
+                                * allowed
+                                */
+#define CHECK_IRQ      0x100   /* Check whether an IRQ can be used */
 
 /* Magic system structure table addresses. */
 #define BEG_PRIV_ADDR (&priv[0])
index 36241523a7e89f3d41c988d9c761b126cd696b2e..a5e48dc9381eda1cd5b16607e167490a97314dc9 100644 (file)
 PUBLIC int do_devio(m_ptr)
 register message *m_ptr;       /* pointer to request message */
 {
+    struct proc *rp;
+    struct priv *privp;
+    port_t port;
+    struct io_range *iorp;
+    int i, size, nr_io_range;
+
+    rp= proc_addr(m_ptr->m_source);
+    privp= priv(rp);
+    if (!privp)
+    {
+       kprintf("no priv structure!\n");
+       goto doit;
+    }
+    if (privp->s_flags & CHECK_IO_PORT)
+    {
+       switch (m_ptr->DIO_TYPE)
+       {
+       case DIO_BYTE: size= 1; break;
+       case DIO_WORD: size= 2; break;
+       case DIO_LONG: size= 4; break;
+       default: size= 4; break;        /* Be conservative */
+       }
+       port= m_ptr->DIO_PORT;
+       nr_io_range= privp->s_nr_io_range;
+       for (i= 0, iorp= privp->s_io_tab; i<nr_io_range; i++, iorp++)
+       {
+               if (port >= iorp->ior_base && port+size-1 <= iorp->ior_limit)
+                       break;
+       }
+       if (i >= nr_io_range)
+       {
+               kprintf(
+               "do_devio: I/O port check failed for proc %d, port 0x%x\n",
+                       m_ptr->m_source, port);
+               return EPERM;
+       }
+    }
+
+doit:
+
 /* Process a single I/O request for byte, word, and long values. */
     if (m_ptr->DIO_REQUEST == DIO_INPUT) { 
       switch (m_ptr->DIO_TYPE) {
index 3998e6cf92c48b1f6f9cd3830182d3a2d9071d26..ec08aa3d5baa585bd23cd34c3dee3d9705bd8a5e 100644 (file)
@@ -26,7 +26,10 @@ register message *m_ptr;     /* pointer to request message */
   int irq_hook_id;
   int notify_id;
   int r = OK;
+  int i;
   irq_hook_t *hook_ptr;
+  struct proc *rp;
+  struct priv *privp;
 
   /* Hook identifiers start at 1 and end at NR_IRQ_HOOKS. */
   irq_hook_id = (unsigned) m_ptr->IRQ_HOOK_ID - 1;
@@ -55,6 +58,29 @@ register message *m_ptr;     /* pointer to request message */
       /* Check if IRQ line is acceptable. */
       if (irq_vec < 0 || irq_vec >= NR_IRQ_VECTORS) return(EINVAL);
 
+      rp= proc_addr(m_ptr->m_source);
+      privp= priv(rp);
+      if (!privp)
+      {
+       kprintf("no priv structure!\n");
+       return EPERM;
+      }
+      if (privp->s_flags & CHECK_IRQ)
+      {
+       for (i= 0; i<privp->s_nr_irq; i++)
+       {
+               if (irq_vec == privp->s_irq_tab[i])
+                       break;
+       }
+       if (i >= privp->s_nr_irq)
+       {
+               kprintf(
+               "do_irqctl: IRQ check failed for proc %d, IRQ %d\n",
+                       m_ptr->m_source, irq_vec);
+               return EPERM;
+       }
+    }
+
       /* Find a free IRQ hook for this mapping. */
       hook_ptr = NULL;
       for (irq_hook_id=0; irq_hook_id<NR_IRQ_HOOKS; irq_hook_id++) {
index b876192784476130f18daa41bd6eff707d9f3d1c..49df7322b517d72ece75aa92a0104c23b35949fd 100644 (file)
@@ -29,6 +29,9 @@ message *m_ptr;                       /* pointer to request message */
   int priv_id;
   int old_flags;
   int i;
+  phys_bytes caller_phys, kernel_phys;
+  struct io_range io_range;
+  struct mem_range mem_range;
 
   /* Check whether caller is allowed to make this call. Privileged proceses 
    * can only update the privileges of processes that are inhibited from 
@@ -40,44 +43,137 @@ message *m_ptr;                    /* pointer to request message */
   proc_nr = m_ptr->PR_PROC_NR;
   if (! isokprocn(proc_nr)) return(EINVAL);
   rp = proc_addr(proc_nr);
-  if (! (rp->p_rts_flags & NO_PRIV)) return(EPERM);
 
-  /* Make sure this process has its own privileges structure. This may fail, 
-   * since there are only a limited number of system processes. Then copy the
-   * privileges from the caller and restore some defaults.
-   */
-  if ((i=get_priv(rp, SYS_PROC)) != OK) return(i);
-  priv_id = priv(rp)->s_id;                    /* backup privilege id */
-  *priv(rp) = *priv(caller_ptr);               /* copy from caller */
-  priv(rp)->s_id = priv_id;                    /* restore privilege id */
-  priv(rp)->s_proc_nr = proc_nr;               /* reassociate process nr */
-
-  for (i=0; i< BITMAP_CHUNKS(NR_SYS_PROCS); i++)       /* remove pending: */
-      priv(rp)->s_notify_pending.chunk[i] = 0;         /* - notifications */
-  priv(rp)->s_int_pending = 0;                         /* - interrupts */
-  sigemptyset(&priv(rp)->s_sig_pending);               /* - signals */
-
-  /* Now update the process' privileges as requested. */
-  rp->p_priv->s_trap_mask = FILLED_MASK;
-  for (i=0; i<BITMAP_CHUNKS(NR_SYS_PROCS); i++) {
-       rp->p_priv->s_ipc_to.chunk[i] = FILLED_MASK;
-  }
-  unset_sys_bit(rp->p_priv->s_ipc_to, USER_PRIV_ID);
+  switch(m_ptr->CTL_REQUEST)
+  {
+  case SYS_PRIV_INIT:
+       if (! (rp->p_rts_flags & NO_PRIV)) return(EPERM);
 
-  /* All process that this process can send to must be able to reply. 
-   * Therefore, their send masks should be updated as well. 
-   */
-  for (i=0; i<NR_SYS_PROCS; i++) {
-      if (get_sys_bit(rp->p_priv->s_ipc_to, i)) {
-          set_sys_bit(priv_addr(i)->s_ipc_to, priv_id(rp));
-      }
-  }
+       /* Make sure this process has its own privileges structure. This may
+        * fail, since there are only a limited number of system processes.
+        * Then copy the privileges from the caller and restore some defaults.
+        */
+       if ((i=get_priv(rp, SYS_PROC)) != OK) return(i);
+       priv_id = priv(rp)->s_id;               /* backup privilege id */
+       *priv(rp) = *priv(caller_ptr);          /* copy from caller */
+       priv(rp)->s_id = priv_id;               /* restore privilege id */
+       priv(rp)->s_proc_nr = proc_nr;          /* reassociate process nr */
+
+       for (i=0; i< BITMAP_CHUNKS(NR_SYS_PROCS); i++)  /* remove pending: */
+             priv(rp)->s_notify_pending.chunk[i] = 0;  /* - notifications */
+       priv(rp)->s_int_pending = 0;                    /* - interrupts */
+       sigemptyset(&priv(rp)->s_sig_pending);          /* - signals */
+
+       /* Now update the process' privileges as requested. */
+       rp->p_priv->s_trap_mask = FILLED_MASK;
+       for (i=0; i<BITMAP_CHUNKS(NR_SYS_PROCS); i++) {
+               rp->p_priv->s_ipc_to.chunk[i] = FILLED_MASK;
+       }
+       unset_sys_bit(rp->p_priv->s_ipc_to, USER_PRIV_ID);
+
+       /* All process that this process can send to must be able to reply. 
+        * Therefore, their send masks should be updated as well. 
+        */
+       for (i=0; i<NR_SYS_PROCS; i++) {
+           if (get_sys_bit(rp->p_priv->s_ipc_to, i)) {
+                 set_sys_bit(priv_addr(i)->s_ipc_to, priv_id(rp));
+           }
+       }
+
+       /* No I/O resources, no memory resources, no IRQs */
+       priv(rp)->s_nr_io_range= 0;
+       priv(rp)->s_nr_mem_range= 0;
+       priv(rp)->s_nr_irq= 0;
+
+       /* Done. Privileges have been set. Allow process to run again. */
+       old_flags = rp->p_rts_flags;            /* save value of the flags */
+       rp->p_rts_flags &= ~NO_PRIV;            
+       if (old_flags != 0 && rp->p_rts_flags == 0) lock_enqueue(rp);
+       return(OK);
+  case SYS_PRIV_ADD_IO:
+       if (rp->p_rts_flags & NO_PRIV)
+               return(EPERM);
+
+       /* Only system processes get I/O resources? */
+       if (!(priv(rp)->s_flags & SYS_PROC))
+               return EPERM;
+
+       /* Get the I/O range */
+       caller_phys = umap_local(caller_ptr, D, (vir_bytes) m_ptr->CTL_ARG_PTR,
+               sizeof(io_range));
+       if (caller_phys == 0)
+               return EFAULT;
+       kernel_phys = vir2phys(&io_range);
+       phys_copy(caller_phys, kernel_phys, sizeof(io_range));
+       priv(rp)->s_flags |= CHECK_IO_PORT;     /* Check I/O accesses */
+       i= priv(rp)->s_nr_io_range;
+       if (i >= NR_IO_RANGE)
+               return ENOMEM;
+
+       priv(rp)->s_io_tab[i].ior_base= io_range.ior_base;
+       priv(rp)->s_io_tab[i].ior_limit= io_range.ior_limit;
+       priv(rp)->s_nr_io_range++;
+
+       kprintf("do_privctl: added I/O range [0x%x..0x%x]\n",
+               io_range.ior_base, io_range.ior_limit);
+
+       return OK;
 
-  /* Done. Privileges have been set. Allow process to run again. */
-  old_flags = rp->p_rts_flags;         /* save value of the flags */
-  rp->p_rts_flags &= ~NO_PRIV;                 
-  if (old_flags != 0 && rp->p_rts_flags == 0) lock_enqueue(rp);
-  return(OK);
+  case SYS_PRIV_ADD_MEM:
+       if (rp->p_rts_flags & NO_PRIV)
+               return(EPERM);
+
+       /* Only system processes get memory resources? */
+       if (!(priv(rp)->s_flags & SYS_PROC))
+               return EPERM;
+
+       /* Get the memory range */
+       caller_phys = umap_local(caller_ptr, D, (vir_bytes) m_ptr->CTL_ARG_PTR,
+               sizeof(mem_range));
+       if (caller_phys == 0)
+               return EFAULT;
+       kernel_phys = vir2phys(&mem_range);
+       phys_copy(caller_phys, kernel_phys, sizeof(mem_range));
+       priv(rp)->s_flags |= CHECK_MEM; /* Check I/O accesses */
+       i= priv(rp)->s_nr_mem_range;
+       if (i >= NR_MEM_RANGE)
+               return ENOMEM;
+
+#if 0
+       priv(rp)->s_mem_tab[i].mr_base= mem_range.mr_base;
+       priv(rp)->s_mem_tab[i].mr_limit= mem_range.mr_limit;
+       priv(rp)->s_nr_mem_range++;
+#endif
+
+       kprintf("do_privctl: should add memory range [0x%x..0x%x]\n",
+               mem_range.mr_base, mem_range.mr_limit);
+
+       return OK;
+
+  case SYS_PRIV_ADD_IRQ:
+       if (rp->p_rts_flags & NO_PRIV)
+               return(EPERM);
+
+       /* Only system processes get IRQs? */
+       if (!(priv(rp)->s_flags & SYS_PROC))
+               return EPERM;
+
+       priv(rp)->s_flags |= CHECK_IRQ; /* Check IRQs */
+
+       i= priv(rp)->s_nr_irq;
+       if (i >= NR_IRQ)
+               return ENOMEM;
+       priv(rp)->s_irq_tab[i]= m_ptr->CTL_MM_PRIV;
+       priv(rp)->s_nr_irq++;
+
+       kprintf("do_privctl: adding IRQ %d\n", m_ptr->CTL_MM_PRIV);
+
+       return OK;
+
+  default:
+       kprintf("do_privctl: bad request %d\n", m_ptr->CTL_REQUEST);
+       return EINVAL;
+  }
 }
 
 #endif /* USE_PRIVCTL */
index 13e0540aa7adc6df6c4e5919616db8386e99012e..5fc2fc8e1538b4526058ee32205a449900cbdf2e 100755 (executable)
@@ -82,6 +82,7 @@ PUBLIC char *t_stack[TOT_STACK_SPACE / sizeof(char *)];
 #define PM_C   ~(c(SYS_DEVIO) | c(SYS_SDEVIO) | c(SYS_VDEVIO) | c(SYS_IRQCTL) | c(SYS_INT86))
 #define FS_C   (c(SYS_KILL) | c(SYS_VIRCOPY) | c(SYS_VIRVCOPY) | c(SYS_UMAP) | c(SYS_GETINFO) | c(SYS_EXIT) | c(SYS_TIMES) | c(SYS_SETALARM))
 #define DRV_C  (FS_C | c(SYS_SEGCTL) | c(SYS_IRQCTL) | c(SYS_INT86) | c(SYS_DEVIO) | c(SYS_VDEVIO) | c(SYS_SDEVIO)) 
+#define PCI_C  (c(SYS_VIRCOPY) | c(SYS_DEVIO) | c(SYS_VDEVIO) | c(SYS_SDEVIO) | c(SYS_PRIVCTL)) 
 #define TTY_C (DRV_C | c(SYS_ABORT) | c(SYS_VM_MAP) | c(SYS_IOPENABLE))
 #define MEM_C  (DRV_C | c(SYS_PHYSCOPY) | c(SYS_PHYSVCOPY) | c(SYS_VM_MAP) | \
        c(SYS_IOPENABLE))
@@ -107,7 +108,7 @@ PUBLIC struct boot_image image[] = {
  { MEM_PROC_NR,   0, SRV_F,  4,      2, 0,     SRV_T, SYS_M, MEM_C, "memory"},
  { LOG_PROC_NR,   0, SRV_F,  4,      2, 0,     SRV_T, SYS_M, DRV_C, "log"   },
  { DRVR_PROC_NR,  0, SRV_F,  4,      2, 0,     SRV_T, SYS_M, DRV_C, "driver"},
- { PCI_PROC_NR,   0, SRV_F,  4,      2, 0,     SRV_T, SYS_M, DRV_C, "pci"},
+ { PCI_PROC_NR,   0, SRV_F,  4,      2, 0,     SRV_T, SYS_M, PCI_C, "pci"},
  { INIT_PROC_NR,  0, USR_F,  8, USER_Q, 0,     USR_T, USR_M,     0, "init"  },
 };