From: Philip Homburg Date: Fri, 27 Jan 2006 13:21:12 +0000 (+0000) Subject: Store resource lists for drivers. Limited checks to enforce those lists. X-Git-Tag: v3.1.2a~407 X-Git-Url: http://zhaoyanbai.com/repos/icons/jhe061.png?a=commitdiff_plain;h=38a16399f852a14996caae3f3535967046163bfe;p=minix.git Store resource lists for drivers. Limited checks to enforce those lists. --- diff --git a/kernel/priv.h b/kernel/priv.h index db541b3ac..04adfbeba 100755 --- a/kernel/priv.h +++ b/kernel/priv.h @@ -15,6 +15,15 @@ #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]) diff --git a/kernel/system/do_devio.c b/kernel/system/do_devio.c index 36241523a..a5e48dc93 100644 --- a/kernel/system/do_devio.c +++ b/kernel/system/do_devio.c @@ -19,6 +19,46 @@ 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= 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) { diff --git a/kernel/system/do_irqctl.c b/kernel/system/do_irqctl.c index 3998e6cf9..ec08aa3d5 100644 --- a/kernel/system/do_irqctl.c +++ b/kernel/system/do_irqctl.c @@ -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; is_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_idPR_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; ip_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; ip_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; ip_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; ip_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 */ diff --git a/kernel/table.c b/kernel/table.c index 13e0540aa..5fc2fc8e1 100755 --- a/kernel/table.c +++ b/kernel/table.c @@ -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" }, };