IPC privileges fixes

Kernel:
o Remove s_ipc_sendrec, instead using s_ipc_to for all send primitives
o Centralize s_ipc_to bit manipulation,
  - disallowing assignment of bits pointing to unused priv structs;
  - preventing send-to-self by not setting bit for own priv struct;
  - preserving send mask matrix symmetry in all cases
o Add IPC send mask checks to SENDA, which were missing entirely somehow
o Slightly improve IPC stats accounting for SENDA
o Remove SYSTEM from user processes' send mask
o Half-fix the dependency between boot image order and process numbers,
  - correcting the table order of the boot processes;
  - documenting the order requirement needed for proper send masks;
  - warning at boot time if the order is violated

RS:
o Add support in /etc/drivers.conf for servers that talk to user processes,
  - disallowing IPC to user processes if no "ipc" field is present
  - adding a special "USER" label to explicitly allow IPC to user processes
o Always apply IPC masks when specified; remove -i flag from service(8)
o Use kernel send mask symmetry to delay adding IPC permissions for labels
  that do not exist yet, adding them to that label's process upon creation
o Add VM to ipc permissions list for rtl8139 and fxp in drivers.conf

Left to future fixes:
o Removal of the table order vs process numbers dependency altogether,
  possibly using per-process send list structures as used for SYSTEM calls
o Proper assignment of send masks to boot processes;
  some of the assigned (~0) masks are much wider than necessary
o Proper assignment of IPC send masks for many more servers in drivers.conf
o Removal of the debugging warning about the now legitimate case where RS's
  add_forward_ipc cannot find the IPC destination's label yet
This commit is contained in:
David van Moolenbroek
2009-07-02 16:25:31 +00:00
parent aa84986819
commit b8b8f537bd
13 changed files with 297 additions and 170 deletions

View File

@@ -83,6 +83,10 @@ PUBLIC void main()
priv(rp)->s_flags = ip->flags; /* process flags */
priv(rp)->s_trap_mask = ip->trap_mask; /* allowed traps */
/* Warn about violations of the boot image table order consistency. */
if (priv_id(rp) != s_nr_to_id(ip->proc_nr))
kprintf("Warning: boot image table has wrong process order\n");
/* Initialize call mask bitmap from unordered set.
* A single SYS_ALL_CALLS is a special case - it
* means all calls are allowed.
@@ -99,12 +103,9 @@ PUBLIC void main()
SET_BIT(priv(rp)->s_k_call_mask,
ip->k_calls[ci]-KERNEL_CALL);
priv(rp)->s_ipc_to.chunk[0] = ip->ipc_to; /* restrict targets */
for (j=0; j<BITMAP_CHUNKS(NR_SYS_PROCS); j++) {
rp->p_priv->s_ipc_sendrec.chunk[j] = ~0L;
}
unset_sys_bit(rp->p_priv->s_ipc_sendrec, USER_PRIV_ID);
for (j = 0; j < NR_SYS_PROCS && j < BITCHUNK_BITS; j++)
if (ip->ipc_to & (1 << j))
set_sendto_bit(rp, j); /* restrict targets */
if (iskerneln(proc_nr(rp))) { /* part of the kernel? */
if (ip->stksize > 0) { /* HARDWARE stack size is 0 */

View File

@@ -36,9 +36,7 @@ struct priv {
*/
short s_trap_mask; /* allowed system call traps */
sys_map_t s_ipc_from; /* allowed callers to receive from */
sys_map_t s_ipc_to; /* allowed destination processes */
sys_map_t s_ipc_sendrec; /* allowed sendrec processes */
/* allowed kernel calls */
#define CALL_MASK_SIZE BITMAP_CHUNKS(NR_SYS_CALLS)
@@ -78,6 +76,8 @@ struct priv {
#define id_to_nr(id) priv_addr(id)->s_proc_nr
#define nr_to_id(nr) priv(proc_addr(nr))->s_id
#define may_send_to(rp, nr) (get_sys_bit(priv(rp)->s_ipc_to, nr_to_id(nr)))
/* The system structures table and pointers to individual table slots. The
* pointers allow faster access because now a process entry can be found by
* indexing the psys_addr array, while accessing an element i requires a

View File

@@ -178,8 +178,7 @@ long bit_map; /* notification event set or flags */
* addition to a real endpoint). The other calls (SEND, SENDREC,
* and NOTIFY) require an endpoint to corresponds to a process. In addition,
* it is necessary to check whether a process is allowed to send to a given
* destination. For SENDREC we check s_ipc_sendrec, and for SEND,
* and NOTIFY we check s_ipc_to.
* destination.
*/
if (call_nr == SENDA)
{
@@ -201,13 +200,6 @@ long bit_map; /* notification event set or flags */
}
else
{
if(caller_ptr->p_endpoint == src_dst_e) {
#if DEBUG_ENABLE_IPC_WARNINGS
kprintf("sys_call: trap %d by %d with self %d\n",
call_nr, proc_nr(caller_ptr), src_dst_e);
#endif
return EINVAL;
}
/* Require a valid source and/or destination process. */
if(!isokendpt(src_dst_e, &src_dst_p)) {
#if DEBUG_ENABLE_IPC_WARNINGS
@@ -219,29 +211,13 @@ long bit_map; /* notification event set or flags */
return EDEADSRCDST;
}
/* If the call is to send to a process, i.e., for SEND,
/* If the call is to send to a process, i.e., for SEND, SENDNB,
* SENDREC or NOTIFY, verify that the caller is allowed to send to
* the given destination.
*/
if (call_nr == SENDREC)
if (call_nr != RECEIVE)
{
if (! get_sys_bit(priv(caller_ptr)->s_ipc_sendrec,
nr_to_id(src_dst_p))) {
#if DEBUG_ENABLE_IPC_WARNINGS
kprintf(
"sys_call: ipc sendrec mask denied trap %d from %d ('%s') to %d\n",
call_nr, proc_nr(caller_ptr),
caller_ptr->p_name, src_dst_p);
#endif
if (caller_ptr->p_endpoint == ipc_stats_target)
ipc_stats.dst_not_allowed++;
return(ECALLDENIED); /* call denied by ipc mask */
}
}
else if (call_nr == SEND || call_nr == SENDNB || call_nr == NOTIFY)
{
if (! get_sys_bit(priv(caller_ptr)->s_ipc_to,
nr_to_id(src_dst_p))) {
if (!may_send_to(caller_ptr, src_dst_p)) {
#if DEBUG_ENABLE_IPC_WARNINGS
kprintf(
"sys_call: ipc mask denied trap %d from %d to %d\n",
@@ -823,6 +799,9 @@ size_t size;
if (!isokendpt(tabent.dst, &dst_p))
{
/* Bad destination, report the error */
if (caller_ptr->p_endpoint == ipc_stats_target)
ipc_stats.bad_endpoint++;
tabent.result= EDEADSRCDST;
A_INSERT(i, result);
tabent.flags= flags | AMF_DONE;
@@ -833,6 +812,22 @@ size_t size;
continue;
}
if (!may_send_to(caller_ptr, dst_p))
{
/* Send denied by IPC mask */
if (caller_ptr->p_endpoint == ipc_stats_target)
ipc_stats.dst_not_allowed++;
tabent.result= ECALLDENIED;
A_INSERT(i, result);
tabent.flags= flags | AMF_DONE;
A_INSERT(i, flags);
if (flags & AMF_NOTIFY)
do_notify= 1;
continue;
}
#if 0
kprintf("mini_senda: entry[%d]: flags 0x%x dst %d/%d\n",
i, tabent.flags, tabent.dst, dst_p);
@@ -843,6 +838,9 @@ size_t size;
/* NO_ENDPOINT should be removed */
if (dst_ptr->p_rts_flags & NO_ENDPOINT)
{
if (caller_ptr->p_endpoint == ipc_stats_target)
ipc_stats.dst_died++;
tabent.result= EDSTDIED;
A_INSERT(i, result);
tabent.flags= flags | AMF_DONE;
@@ -928,6 +926,8 @@ struct proc *caller_ptr;
privp->s_proc_nr);
#endif
src_ptr= proc_addr(privp->s_proc_nr);
if (!may_send_to(src_ptr, proc_nr(caller_ptr)))
continue;
r= try_one(src_ptr, caller_ptr);
if (r == OK)
return r;

View File

@@ -55,6 +55,8 @@ _PROTOTYPE( void cstart, (U16_t cs, U16_t ds, U16_t mds,
/* system.c */
_PROTOTYPE( int get_priv, (register struct proc *rc, int proc_type) );
_PROTOTYPE( void set_sendto_bit, (struct proc *rc, int id) );
_PROTOTYPE( void unset_sendto_bit, (struct proc *rc, int id) );
_PROTOTYPE( void send_sig, (int proc_nr, int sig_nr) );
_PROTOTYPE( void cause_sig, (int proc_nr, int sig_nr) );
_PROTOTYPE( void sys_task, (void) );

View File

@@ -12,6 +12,8 @@
* In addition to the main sys_task() entry point, which starts the main loop,
* there are several other minor entry points:
* get_priv: assign privilege structure to user or system process
* set_sendto_bit: allow a process to send messages to a new target
* unset_sendto_bit: disallow a process from sending messages to a target
* send_sig: send a signal directly to a system process
* cause_sig: take action to cause a signal to occur via PM
* umap_bios: map virtual address in BIOS_SEG to physical
@@ -290,6 +292,46 @@ int proc_type; /* system or user process flag */
return(OK);
}
/*===========================================================================*
* set_sendto_bit *
*===========================================================================*/
PUBLIC void set_sendto_bit(struct proc *rp, int id)
{
/* Allow a process to send messages to the process(es) associated with the
* system privilege structure with the given ID.
*/
struct proc *rrp; /* receiver process */
/* Disallow the process from sending to a system privilege structure with no
* associated process, and disallow the process from sending to itself.
*/
if (id_to_nr(id) == NONE || priv_id(rp) == id)
return;
set_sys_bit(priv(rp)->s_ipc_to, id);
/* The process that this process can now send to, must be able to reply.
* Therefore, its send mask should be updated as well.
*/
rrp = proc_addr(id_to_nr(id));
if (!iskernelp(rrp))
set_sys_bit(priv(rrp)->s_ipc_to, priv_id(rp));
}
/*===========================================================================*
* unset_sendto_bit *
*===========================================================================*/
PUBLIC void unset_sendto_bit(struct proc *rp, int id)
{
/* Prevent a process from sending to another process. Retain the send mask
* symmetry by also unsetting the bit for the other direction.
*/
unset_sys_bit(priv(rp)->s_ipc_to, id);
unset_sys_bit(priv_addr(id)->s_ipc_to, priv_id(rp));
}
/*===========================================================================*
* send_sig *
*===========================================================================*/

View File

@@ -70,25 +70,15 @@ message *m_ptr; /* pointer to request message */
/* 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));
}
/* Set a default send mask. */
for (i=0; i < NR_SYS_PROCS; i++) {
if (i != USER_PRIV_ID)
set_sendto_bit(rp, i);
else
unset_sendto_bit(rp, i);
}
for (i=0; i<BITMAP_CHUNKS(NR_SYS_PROCS); i++) {
rp->p_priv->s_ipc_sendrec.chunk[i] = FILLED_MASK;
}
unset_sys_bit(rp->p_priv->s_ipc_sendrec, USER_PRIV_ID);
/* No I/O resources, no memory resources, no IRQs, no grant table */
priv(rp)->s_nr_io_range= 0;
priv(rp)->s_nr_mem_range= 0;
@@ -142,10 +132,14 @@ message *m_ptr; /* pointer to request message */
memcpy(priv(rp)->s_k_call_mask, priv.s_k_call_mask,
sizeof(priv(rp)->s_k_call_mask));
memcpy(&priv(rp)->s_ipc_to, &priv.s_ipc_to,
sizeof(priv(rp)->s_ipc_to));
memcpy(&priv(rp)->s_ipc_sendrec, &priv.s_ipc_sendrec,
sizeof(priv(rp)->s_ipc_sendrec));
/* Set a custom send mask. */
for (i=0; i < NR_SYS_PROCS; i++) {
if (get_sys_bit(priv.s_ipc_to, i))
set_sendto_bit(rp, i);
else
unset_sendto_bit(rp, i);
}
}
/* Done. Privileges have been set. Allow process to run again. */

View File

@@ -60,18 +60,15 @@ PUBLIC char *t_stack[TOT_STACK_SPACE / sizeof(char *)];
/* Send masks determine to whom processes can send messages or notifications.
* The values here are used for the processes in the boot image. We rely on
* the initialization code in main() to match the s_nr_to_id() mapping for the
* processes in the boot image, so that the send mask that is defined here
* can be directly copied onto map[0] of the actual send mask. Privilege
* structure 0 is shared by user processes.
* the boot image table itself to match the order of the process numbers, so
* that the send mask that is defined here can be interpreted properly.
* Privilege structure 0 is shared by user processes.
*/
#define s(n) (1 << (s_nr_to_id(n)))
#define NUL_M 0
#define SRV_M (~0)
#define SYS_M (~0)
#define USR_M (s(PM_PROC_NR) | s(FS_PROC_NR) | s(RS_PROC_NR) | s(SYSTEM) | \
s(VM_PROC_NR))
#define DRV_M (USR_M | s(SYSTEM) | s(CLOCK) | s(DS_PROC_NR) | s(LOG_PROC_NR) | s(TTY_PROC_NR))
#define USR_M (s(PM_PROC_NR) | s(FS_PROC_NR) | s(RS_PROC_NR) | s(VM_PROC_NR))
#define DRV_M (USR_M | s(SYSTEM) | s(DS_PROC_NR) | s(LOG_PROC_NR) | s(TTY_PROC_NR))
/* Define kernel calls that processes are allowed to make. This is not looking
* very nice, but we need to define the access rights on a per call basis.
@@ -100,7 +97,8 @@ PRIVATE int
/* The system image table lists all programs that are part of the boot image.
* The order of the entries here MUST agree with the order of the programs
* in the boot image and all kernel tasks must come first.
* in the boot image and all kernel tasks must come first. Furthermore, the
* order of the entries MUST agree with their process numbers. See above.
*
* Each entry provides the process number, flags, quantum size, scheduling
* queue, allowed traps, ipc mask, and a name for the process table. The
@@ -120,10 +118,10 @@ PUBLIC struct boot_image image[] = {
{PM_PROC_NR, 0,SVM_F, 32, 4, 0, SRV_T, SRV_M, c(pm_c),"pm" },
{FS_PROC_NR, 0,SVM_F, 32, 5, 0, SRV_T, SRV_M, c(fs_c),"vfs" },
{RS_PROC_NR, 0,SVM_F, 4, 4, 0, SRV_T, SYS_M, c(rs_c),"rs" },
{DS_PROC_NR, 0,SVM_F, 4, 4, 0, SRV_T, SYS_M, c(ds_c),"ds" },
{TTY_PROC_NR, 0,SVM_F, 4, 1, 0, SRV_T, SYS_M,c(tty_c),"tty" },
{MEM_PROC_NR, 0,SVM_F, 4, 3, 0, SRV_T, SYS_M,c(mem_c),"memory"},
{LOG_PROC_NR, 0,SVM_F, 4, 2, 0, SRV_T, SYS_M,c(drv_c),"log" },
{TTY_PROC_NR, 0,SVM_F, 4, 1, 0, SRV_T, SYS_M,c(tty_c),"tty" },
{DS_PROC_NR, 0,SVM_F, 4, 4, 0, SRV_T, SYS_M, c(ds_c),"ds" },
{MFS_PROC_NR, 0,SVM_F, 32, 5, 0, SRV_T, SRV_M, c(fs_c),"mfs" },
{VM_PROC_NR, 0,SRV_F, 32, 2, 0, SRV_T, SRV_M, c(vm_c),"vm" },
{INIT_PROC_NR, 0,USR_F, 8, USER_Q, 0, USR_T, USR_M, no_c,"init" },