Store resource lists for drivers. Limited checks to enforce those lists.
This commit is contained in:
parent
ee2253ec52
commit
38a16399f8
|
@ -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])
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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" },
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue