Store resource lists for drivers. Limited checks to enforce those lists.

This commit is contained in:
Philip Homburg 2006-01-27 13:21:12 +00:00
parent ee2253ec52
commit 38a16399f8
5 changed files with 221 additions and 35 deletions

View file

@ -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])

View file

@ -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<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) {

View 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++) {

View 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 */
switch(m_ptr->CTL_REQUEST)
{
case SYS_PRIV_INIT:
if (! (rp->p_rts_flags & NO_PRIV)) return(EPERM);
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 */
/* 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 */
/* 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;
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;
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;
}
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));
}
}
/* 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);
}
#endif /* USE_PRIVCTL */

View file

@ -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" },
};