kernel: Add support for IPC filters.
Edited by David van Moolenbroek. Change-Id: Ia0052c42a0f218d011dd2da1e3db6c5b2107adc7
This commit is contained in:
		
							parent
							
								
									6fc5006250
								
							
						
					
					
						commit
						c8a9900b0c
					
				@ -1414,6 +1414,7 @@
 | 
			
		||||
./usr/include/minix/ioctl.h		minix-sys
 | 
			
		||||
./usr/include/minix/ipcconst.h		minix-sys
 | 
			
		||||
./usr/include/minix/ipc.h		minix-sys
 | 
			
		||||
./usr/include/minix/ipc_filter.h	minix-sys
 | 
			
		||||
./usr/include/minix/keymap.h		minix-sys
 | 
			
		||||
./usr/include/minix/libminixfs.h	minix-sys
 | 
			
		||||
./usr/include/minix/log.h		minix-sys
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@ INCS+=	acpi.h audio_fw.h bitmap.h \
 | 
			
		||||
	driver.h drivers.h drvlib.h ds.h \
 | 
			
		||||
	endpoint.h fb.h fsdriver.h fslib.h gpio.h gcov.h hash.h \
 | 
			
		||||
	hgfs.h i2c.h i2cdriver.h ioctl.h input.h \
 | 
			
		||||
	inputdriver.h ipc.h ipcconst.h \
 | 
			
		||||
	inputdriver.h ipc.h ipc_filter.h ipcconst.h \
 | 
			
		||||
	keymap.h log.h mmio.h mthread.h minlib.h \
 | 
			
		||||
	netdriver.h optset.h padconf.h partition.h portio.h \
 | 
			
		||||
	priv.h procfs.h profile.h queryparam.h \
 | 
			
		||||
 | 
			
		||||
@ -437,6 +437,9 @@
 | 
			
		||||
/* Subfunctions for SYS_STATECTL */
 | 
			
		||||
#define SYS_STATE_CLEAR_IPC_REFS    1	/* clear IPC references */
 | 
			
		||||
#define SYS_STATE_SET_STATE_TABLE   2	/* set state map */
 | 
			
		||||
#define SYS_STATE_ADD_IPC_BL_FILTER 3	/* set IPC blacklist filter */
 | 
			
		||||
#define SYS_STATE_ADD_IPC_WL_FILTER 4	/* set IPC whitelist filter */
 | 
			
		||||
#define SYS_STATE_CLEAR_IPC_FILTERS 5	/* clear IPC filters */
 | 
			
		||||
 | 
			
		||||
/* Subfunctions for SYS_SCHEDCTL */
 | 
			
		||||
#  define SCHEDCTL_FLAG_KERNEL	1	/* mark kernel scheduler and remove 
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										30
									
								
								minix/include/minix/ipc_filter.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								minix/include/minix/ipc_filter.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
			
		||||
/* IPC filter definitions. */
 | 
			
		||||
 | 
			
		||||
#ifndef _MINIX_IPC_FILTER_H
 | 
			
		||||
#define _MINIX_IPC_FILTER_H
 | 
			
		||||
 | 
			
		||||
#include <minix/com.h>
 | 
			
		||||
#include <minix/config.h>
 | 
			
		||||
 | 
			
		||||
/* Special message sources, allowed in IPC filters only. */
 | 
			
		||||
#define ANY_USR		_ENDPOINT(1, _ENDPOINT_P(ANY))
 | 
			
		||||
#define ANY_SYS		_ENDPOINT(2, _ENDPOINT_P(ANY))
 | 
			
		||||
#define ANY_TSK		_ENDPOINT(3, _ENDPOINT_P(ANY))
 | 
			
		||||
 | 
			
		||||
/* IPC filter constants. */
 | 
			
		||||
#define IPCF_MAX_ELEMENTS       NR_SYS_PROCS
 | 
			
		||||
 | 
			
		||||
/* IPC filter flags. */
 | 
			
		||||
#define IPCF_MATCH_M_SOURCE    0x1
 | 
			
		||||
#define IPCF_MATCH_M_TYPE      0x2
 | 
			
		||||
#define IPCF_EL_BLACKLIST      0x4
 | 
			
		||||
#define IPCF_EL_WHITELIST      0x8
 | 
			
		||||
 | 
			
		||||
struct ipc_filter_el_s {
 | 
			
		||||
    int flags;
 | 
			
		||||
    endpoint_t m_source;
 | 
			
		||||
    int m_type;
 | 
			
		||||
};
 | 
			
		||||
typedef struct ipc_filter_el_s ipc_filter_el_t;
 | 
			
		||||
 | 
			
		||||
#endif /* _MINIX_IPC_FILTER_H */
 | 
			
		||||
@ -312,7 +312,7 @@ void print_proc_recursive(struct proc *pp)
 | 
			
		||||
	print_proc_depends(pp, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if DEBUG_DUMPIPC
 | 
			
		||||
#if DEBUG_DUMPIPC || DEBUG_DUMPIPCF
 | 
			
		||||
static const char *mtypename(int mtype, int *possible_callname)
 | 
			
		||||
{
 | 
			
		||||
	char *callname = NULL, *errname = NULL;
 | 
			
		||||
@ -384,7 +384,7 @@ static int namematch(char **names, int nnames, char *name)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void printmsg(message *msg, struct proc *src, struct proc *dst, 
 | 
			
		||||
void printmsg(message *msg, struct proc *src, struct proc *dst,
 | 
			
		||||
	char operation, int printparams)
 | 
			
		||||
{
 | 
			
		||||
	const char *name;
 | 
			
		||||
 | 
			
		||||
@ -46,6 +46,10 @@
 | 
			
		||||
 */
 | 
			
		||||
#define DEBUG_DUMPIPC			0
 | 
			
		||||
 | 
			
		||||
/* DEBUG_DUMPIPCF dumps filtered IPC to serial.
 | 
			
		||||
 */
 | 
			
		||||
#define DEBUG_DUMPIPCF			0
 | 
			
		||||
 | 
			
		||||
/* If defined, restrict DEBUG_DUMPIPC to particular process names */
 | 
			
		||||
/* #define DEBUG_DUMPIPC_NAMES		{ "tty", "inet" } */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -11,9 +11,15 @@
 | 
			
		||||
#define NON_BLOCKING    0x0080  /* do not block if target not ready */
 | 
			
		||||
#define FROM_KERNEL     0x0100  /* message from kernel on behalf of a process */
 | 
			
		||||
 | 
			
		||||
#define WILLRECEIVE(target, source_ep) \
 | 
			
		||||
  ((RTS_ISSET(target, RTS_RECEIVING) && !RTS_ISSET(target, RTS_SENDING)) &&	\
 | 
			
		||||
    (target->p_getfrom_e == ANY || target->p_getfrom_e == source_ep))
 | 
			
		||||
#define WILLRECEIVE(src_e,dst_ptr,m_src_v,m_src_p) \
 | 
			
		||||
	((RTS_ISSET(dst_ptr, RTS_RECEIVING) && \
 | 
			
		||||
	!RTS_ISSET(dst_ptr, RTS_SENDING)) && \
 | 
			
		||||
	CANRECEIVE(dst_ptr->p_getfrom_e,src_e,dst_ptr,m_src_v,m_src_p))
 | 
			
		||||
 | 
			
		||||
#define CANRECEIVE(receive_e,src_e,dst_ptr,m_src_v,m_src_p) \
 | 
			
		||||
	(((receive_e) == ANY || (receive_e) == (src_e)) && \
 | 
			
		||||
	(priv(dst_ptr)->s_ipcf == NULL || \
 | 
			
		||||
	allow_ipc_filtered_msg(dst_ptr,src_e,m_src_v,m_src_p)))
 | 
			
		||||
 | 
			
		||||
/* IPC status code macros. */
 | 
			
		||||
#define IPC_STATUS_GET(p)	((p)->p_reg.IPC_STATUS_REG)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										73
									
								
								minix/kernel/ipc_filter.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								minix/kernel/ipc_filter.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,73 @@
 | 
			
		||||
#ifndef IPC_FILTER_H
 | 
			
		||||
#define IPC_FILTER_H
 | 
			
		||||
 | 
			
		||||
/* Declaration of the ipc filter structure. It provides a framework to
 | 
			
		||||
 * selectively allow/disallow ipc messages a process agrees to receive. To this
 | 
			
		||||
 * end, a single ipc filter can be specified at a given time for any recipient
 | 
			
		||||
 * to blacklist/whitelist a set of ipc messages identified by sender or message
 | 
			
		||||
 * type.
 | 
			
		||||
 */
 | 
			
		||||
#include <minix/ipc_filter.h>
 | 
			
		||||
 | 
			
		||||
/* IPC filter types. */
 | 
			
		||||
#define IPCF_NONE        0	/* no ipc filter */
 | 
			
		||||
#define IPCF_BLACKLIST   1	/* blacklist filter type */
 | 
			
		||||
#define IPCF_WHITELIST   2	/* whitelist filter type */
 | 
			
		||||
 | 
			
		||||
/* IPC filter element macros. */
 | 
			
		||||
EXTERN int _ipcf_nr;
 | 
			
		||||
#define IPCF_EL_CHECK(E) \
 | 
			
		||||
	((((E)->flags & IPCF_MATCH_M_TYPE) || \
 | 
			
		||||
	((E)->flags & IPCF_MATCH_M_SOURCE)) && \
 | 
			
		||||
	(!((E)->flags & IPCF_MATCH_M_SOURCE) || \
 | 
			
		||||
	IPCF_IS_ANY_EP((E)->m_source) || isokendpt((E)->m_source, &_ipcf_nr)))
 | 
			
		||||
#define IPCF_IS_USR_EP(EP) \
 | 
			
		||||
	(!(priv(proc_addr(_ENDPOINT_P((EP))))->s_flags & SYS_PROC))
 | 
			
		||||
#define IPCF_IS_TSK_EP(EP) (iskerneln(_ENDPOINT_P((EP))))
 | 
			
		||||
#define IPCF_IS_SYS_EP(EP) (!IPCF_IS_USR_EP(EP) && !IPCF_IS_TSK_EP(EP))
 | 
			
		||||
#define IPCF_IS_ANY_EP(EP) \
 | 
			
		||||
	((EP) == ANY_USR || (EP) == ANY_SYS || (EP) == ANY_TSK)
 | 
			
		||||
#define IPCF_EL_MATCH_M_TYPE(E,M) \
 | 
			
		||||
	(!((E)->flags & IPCF_MATCH_M_TYPE) || (E)->m_type == (M)->m_type)
 | 
			
		||||
#define IPCF_EL_MATCH_M_SOURCE(E,M) \
 | 
			
		||||
	(!((E)->flags & IPCF_MATCH_M_SOURCE) || \
 | 
			
		||||
	(E)->m_source == (M)->m_source || \
 | 
			
		||||
	IPCF_EL_MATCH_M_SOURCE_ANY_EP((E)->m_source,(M)->m_source))
 | 
			
		||||
#define IPCF_EL_MATCH_M_SOURCE_ANY_EP(ES,MS) \
 | 
			
		||||
	(((ES) == ANY_USR && IPCF_IS_USR_EP(MS)) || \
 | 
			
		||||
	((ES) == ANY_SYS && IPCF_IS_SYS_EP(MS)) || \
 | 
			
		||||
	((ES) == ANY_TSK && IPCF_IS_TSK_EP(MS)))
 | 
			
		||||
#define IPCF_EL_MATCH(E,M) \
 | 
			
		||||
	(IPCF_EL_MATCH_M_TYPE(E,M) && IPCF_EL_MATCH_M_SOURCE(E,M))
 | 
			
		||||
 | 
			
		||||
struct ipc_filter_s {
 | 
			
		||||
  int type;
 | 
			
		||||
  int num_elements;
 | 
			
		||||
  int flags;
 | 
			
		||||
  struct ipc_filter_s *next;
 | 
			
		||||
  ipc_filter_el_t elements[IPCF_MAX_ELEMENTS];
 | 
			
		||||
};
 | 
			
		||||
typedef struct ipc_filter_s ipc_filter_t;
 | 
			
		||||
 | 
			
		||||
/* IPC filter pool. */
 | 
			
		||||
#define IPCF_POOL_SIZE          (2*NR_SYS_PROCS)
 | 
			
		||||
EXTERN ipc_filter_t ipc_filter_pool[IPCF_POOL_SIZE];
 | 
			
		||||
 | 
			
		||||
/* IPC filter pool macros. */
 | 
			
		||||
#define IPCF_POOL_FREE_SLOT(S) ((S)->type = IPCF_NONE)
 | 
			
		||||
#define IPCF_POOL_IS_FREE_SLOT(S) ((S)->type == IPCF_NONE)
 | 
			
		||||
#define IPCF_POOL_ALLOCATE_SLOT(T,S) \
 | 
			
		||||
	do { \
 | 
			
		||||
		int i; \
 | 
			
		||||
		*(S) = NULL; \
 | 
			
		||||
		for (i = 0; i < IPCF_POOL_SIZE; i++) { \
 | 
			
		||||
			if (IPCF_POOL_IS_FREE_SLOT(&ipc_filter_pool[i])) { \
 | 
			
		||||
				*(S) = &ipc_filter_pool[i]; \
 | 
			
		||||
				(*(S))->type = T; \
 | 
			
		||||
				break; \
 | 
			
		||||
			} \
 | 
			
		||||
		} \
 | 
			
		||||
	} while(0)
 | 
			
		||||
#define IPCF_POOL_INIT(S) memset(&ipc_filter_pool,0,sizeof(ipc_filter_pool))
 | 
			
		||||
 | 
			
		||||
#endif /* !IPC_FILTER_H */
 | 
			
		||||
@ -154,7 +154,12 @@ void kmain(kinfo_t *local_cbi)
 | 
			
		||||
 
 | 
			
		||||
   DEBUGEXTRA(("main()\n"));
 | 
			
		||||
 | 
			
		||||
   proc_init();
 | 
			
		||||
  /* Clear the process table. Anounce each slot as empty and set up mappings
 | 
			
		||||
   * for proc_addr() and proc_nr() macros. Do the same for the table with
 | 
			
		||||
   * privilege structures for the system processes and the ipc filter pool.
 | 
			
		||||
   */
 | 
			
		||||
  proc_init();
 | 
			
		||||
  IPCF_POOL_INIT();
 | 
			
		||||
 | 
			
		||||
   if(NR_BOOT_MODULES != kinfo.mbi.mi_mods_count)
 | 
			
		||||
   	panic("expecting %d boot processes/modules, found %d",
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,7 @@
 | 
			
		||||
#include <minix/priv.h>
 | 
			
		||||
#include "kernel/const.h"
 | 
			
		||||
#include "kernel/type.h"
 | 
			
		||||
#include "kernel/ipc_filter.h"
 | 
			
		||||
 | 
			
		||||
struct priv {
 | 
			
		||||
  proc_nr_t s_proc_nr;		/* number of associated process */
 | 
			
		||||
@ -42,6 +43,7 @@ struct priv {
 | 
			
		||||
  sys_map_t s_asyn_pending;	/* bit map with pending asyn messages */
 | 
			
		||||
  irq_id_t s_int_pending;	/* pending hardware interrupts */
 | 
			
		||||
  sigset_t s_sig_pending;	/* pending signals */
 | 
			
		||||
  ipc_filter_t *s_ipcf;         /* ipc filter (NULL when no filter is set) */
 | 
			
		||||
 | 
			
		||||
  minix_timer_t s_alarm_timer;	/* synchronous alarm timer */
 | 
			
		||||
  reg_t *s_stack_guard;		/* stack guard word for kernel tasks */
 | 
			
		||||
@ -81,6 +83,7 @@ struct priv {
 | 
			
		||||
#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)))
 | 
			
		||||
#define may_asynsend_to(rp, nr) (may_send_to(rp, nr) || (rp)->p_nr == 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 
 | 
			
		||||
 | 
			
		||||
@ -52,13 +52,14 @@ static int mini_send(struct proc *caller_ptr, endpoint_t dst_e, message
 | 
			
		||||
	*m_ptr, int flags);
 | 
			
		||||
*/
 | 
			
		||||
static int mini_receive(struct proc *caller_ptr, endpoint_t src,
 | 
			
		||||
	message *m_ptr, int flags);
 | 
			
		||||
	message *m_buff_usr, int flags);
 | 
			
		||||
static int mini_senda(struct proc *caller_ptr, asynmsg_t *table, size_t
 | 
			
		||||
	size);
 | 
			
		||||
static int deadlock(int function, register struct proc *caller,
 | 
			
		||||
	endpoint_t src_dst_e);
 | 
			
		||||
static int try_async(struct proc *caller_ptr);
 | 
			
		||||
static int try_one(struct proc *src_ptr, struct proc *dst_ptr);
 | 
			
		||||
static int try_one(endpoint_t receive_e, struct proc *src_ptr,
 | 
			
		||||
	struct proc *dst_ptr);
 | 
			
		||||
static struct proc * pick_proc(void);
 | 
			
		||||
static void enqueue_head(struct proc *rp);
 | 
			
		||||
 | 
			
		||||
@ -116,6 +117,8 @@ static void set_idle_name(char * name, int n)
 | 
			
		||||
		break;							\
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
static message m_notify_buff = { 0, NOTIFY_MESSAGE };
 | 
			
		||||
 | 
			
		||||
void proc_init(void)
 | 
			
		||||
{
 | 
			
		||||
	struct proc * rp;
 | 
			
		||||
@ -826,7 +829,7 @@ int mini_send(
 | 
			
		||||
  /* Check if 'dst' is blocked waiting for this message. The destination's 
 | 
			
		||||
   * RTS_SENDING flag may be set when its SENDREC call blocked while sending.  
 | 
			
		||||
   */
 | 
			
		||||
  if (WILLRECEIVE(dst_ptr, caller_ptr->p_endpoint)) {
 | 
			
		||||
  if (WILLRECEIVE(caller_ptr->p_endpoint, dst_ptr, (vir_bytes)m_ptr, NULL)) {
 | 
			
		||||
	int call;
 | 
			
		||||
	/* Destination is indeed waiting for this message. */
 | 
			
		||||
	assert(!(dst_ptr->p_misc_flags & MF_DELIVERMSG));	
 | 
			
		||||
@ -908,7 +911,8 @@ static int mini_receive(struct proc * caller_ptr,
 | 
			
		||||
 * is available block the caller.
 | 
			
		||||
 */
 | 
			
		||||
  register struct proc **xpp;
 | 
			
		||||
  int r, src_id, src_proc_nr, src_p;
 | 
			
		||||
  int r, src_id, found, src_proc_nr, src_p;
 | 
			
		||||
  endpoint_t sender_e;
 | 
			
		||||
 | 
			
		||||
  assert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG));
 | 
			
		||||
 | 
			
		||||
@ -936,10 +940,16 @@ static int mini_receive(struct proc * caller_ptr,
 | 
			
		||||
    if (! (caller_ptr->p_misc_flags & MF_REPLY_PEND)) {
 | 
			
		||||
 | 
			
		||||
	/* Check for pending notifications */
 | 
			
		||||
        if ((src_id = has_pending_notify(caller_ptr, src_p)) != NULL_PRIV_ID) {
 | 
			
		||||
            endpoint_t hisep;
 | 
			
		||||
 | 
			
		||||
        src_id = has_pending_notify(caller_ptr, src_p);
 | 
			
		||||
        found = src_id != NULL_PRIV_ID;
 | 
			
		||||
        if(found) {
 | 
			
		||||
            src_proc_nr = id_to_nr(src_id);		/* get source proc */
 | 
			
		||||
            sender_e = proc_addr(src_proc_nr)->p_endpoint;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (found && CANRECEIVE(src_e, sender_e, caller_ptr, 0,
 | 
			
		||||
          &m_notify_buff)) {
 | 
			
		||||
 | 
			
		||||
#if DEBUG_ENABLE_IPC_WARNINGS
 | 
			
		||||
	    if(src_proc_nr == NONE) {
 | 
			
		||||
		printf("mini_receive: sending notify from NONE\n");
 | 
			
		||||
@ -949,13 +959,12 @@ static int mini_receive(struct proc * caller_ptr,
 | 
			
		||||
            unset_notify_pending(caller_ptr, src_id);	/* no longer pending */
 | 
			
		||||
 | 
			
		||||
            /* Found a suitable source, deliver the notification message. */
 | 
			
		||||
	    hisep = proc_addr(src_proc_nr)->p_endpoint;
 | 
			
		||||
	    assert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG));	
 | 
			
		||||
	    assert(src_e == ANY || hisep == src_e);
 | 
			
		||||
	    assert(src_e == ANY || sender_e == src_e);
 | 
			
		||||
 | 
			
		||||
	    /* assemble message */
 | 
			
		||||
	    BuildNotifyMessage(&caller_ptr->p_delivermsg, src_proc_nr, caller_ptr);
 | 
			
		||||
	    caller_ptr->p_delivermsg.m_source = hisep;
 | 
			
		||||
	    caller_ptr->p_delivermsg.m_source = sender_e;
 | 
			
		||||
	    caller_ptr->p_misc_flags |= MF_DELIVERMSG;
 | 
			
		||||
 | 
			
		||||
	    IPC_STATUS_ADD_CALL(caller_ptr, NOTIFY);
 | 
			
		||||
@ -967,7 +976,7 @@ static int mini_receive(struct proc * caller_ptr,
 | 
			
		||||
    /* Check for pending asynchronous messages */
 | 
			
		||||
    if (has_pending_asend(caller_ptr, src_p) != NULL_PRIV_ID) {
 | 
			
		||||
        if (src_p != ANY)
 | 
			
		||||
        	r = try_one(proc_addr(src_p), caller_ptr);
 | 
			
		||||
		r = try_one(src_e, proc_addr(src_p), caller_ptr);
 | 
			
		||||
        else
 | 
			
		||||
        	r = try_async(caller_ptr);
 | 
			
		||||
 | 
			
		||||
@ -981,8 +990,9 @@ static int mini_receive(struct proc * caller_ptr,
 | 
			
		||||
    xpp = &caller_ptr->p_caller_q;
 | 
			
		||||
    while (*xpp) {
 | 
			
		||||
	struct proc * sender = *xpp;
 | 
			
		||||
	endpoint_t sender_e = sender->p_endpoint;
 | 
			
		||||
 | 
			
		||||
        if (src_e == ANY || src_p == proc_nr(sender)) {
 | 
			
		||||
        if (CANRECEIVE(src_e, sender_e, caller_ptr, 0, &sender->p_sendmsg)) {
 | 
			
		||||
            int call;
 | 
			
		||||
	    assert(!RTS_ISSET(sender, RTS_SLOT_FREE));
 | 
			
		||||
	    assert(!RTS_ISSET(sender, RTS_NO_ENDPOINT));
 | 
			
		||||
@ -1066,8 +1076,8 @@ int mini_notify(
 | 
			
		||||
  /* Check to see if target is blocked waiting for this message. A process 
 | 
			
		||||
   * can be both sending and receiving during a SENDREC system call.
 | 
			
		||||
   */
 | 
			
		||||
    if (WILLRECEIVE(dst_ptr, caller_ptr->p_endpoint) &&
 | 
			
		||||
      ! (dst_ptr->p_misc_flags & MF_REPLY_PEND)) {
 | 
			
		||||
  if (WILLRECEIVE(caller_ptr->p_endpoint, dst_ptr, 0, &m_notify_buff) &&
 | 
			
		||||
    !(dst_ptr->p_misc_flags & MF_REPLY_PEND)) {
 | 
			
		||||
      /* Destination is indeed waiting for a message. Assemble a notification 
 | 
			
		||||
       * message and deliver it. Copy from pseudo-source HARDWARE, since the
 | 
			
		||||
       * message is in the kernel's address space.
 | 
			
		||||
@ -1107,6 +1117,9 @@ field, caller->p_name, entry, priv(caller)->s_asynsize, priv(caller)->s_asyntab)
 | 
			
		||||
  			r = EFAULT;		\
 | 
			
		||||
	                goto asyn_error; \
 | 
			
		||||
  }						\
 | 
			
		||||
  else if(tabent.dst == SELF) { \
 | 
			
		||||
      tabent.dst = caller_ptr->p_endpoint; \
 | 
			
		||||
  } \
 | 
			
		||||
  			 } while(0)
 | 
			
		||||
 | 
			
		||||
#define A_INSRT(entry) do {			\
 | 
			
		||||
@ -1133,6 +1146,7 @@ int try_deliver_senda(struct proc *caller_ptr,
 | 
			
		||||
  struct priv *privp;
 | 
			
		||||
  asynmsg_t tabent;
 | 
			
		||||
  const vir_bytes table_v = (vir_bytes) table;
 | 
			
		||||
  message *m_ptr = NULL;
 | 
			
		||||
 | 
			
		||||
  privp = priv(caller_ptr);
 | 
			
		||||
 | 
			
		||||
@ -1185,7 +1199,7 @@ int try_deliver_senda(struct proc *caller_ptr,
 | 
			
		||||
		r = EDEADSRCDST; /* Bad destination, report the error */
 | 
			
		||||
	else if (iskerneln(dst_p)) 
 | 
			
		||||
		r = ECALLDENIED; /* Asyn sends to the kernel are not allowed */
 | 
			
		||||
	else if (!may_send_to(caller_ptr, dst_p)) 
 | 
			
		||||
	else if (!may_asynsend_to(caller_ptr, dst_p))
 | 
			
		||||
		r = ECALLDENIED; /* Send denied by IPC mask */
 | 
			
		||||
	else 	/* r == OK */
 | 
			
		||||
		dst_ptr = proc_addr(dst_p);
 | 
			
		||||
@ -1199,7 +1213,8 @@ int try_deliver_senda(struct proc *caller_ptr,
 | 
			
		||||
	 * If AMF_NOREPLY is set, do not satisfy the receiving part of
 | 
			
		||||
	 * a SENDREC.
 | 
			
		||||
	 */
 | 
			
		||||
	if (r == OK && WILLRECEIVE(dst_ptr, caller_ptr->p_endpoint) &&
 | 
			
		||||
	if (r == OK && WILLRECEIVE(caller_ptr->p_endpoint, dst_ptr,
 | 
			
		||||
	    (vir_bytes)&table[i].msg, NULL) &&
 | 
			
		||||
	    (!(flags&AMF_NOREPLY) || !(dst_ptr->p_misc_flags&MF_REPLY_PEND))) {
 | 
			
		||||
		/* Destination is indeed waiting for this message. */
 | 
			
		||||
		dst_ptr->p_delivermsg = tabent.msg;
 | 
			
		||||
@ -1298,7 +1313,7 @@ struct proc *caller_ptr;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	assert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG));
 | 
			
		||||
	if ((r = try_one(src_ptr, caller_ptr)) == OK)
 | 
			
		||||
	if ((r = try_one(ANY, src_ptr, caller_ptr)) == OK)
 | 
			
		||||
		return(r);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -1309,13 +1324,14 @@ struct proc *caller_ptr;
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *				try_one					     *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
static int try_one(struct proc *src_ptr, struct proc *dst_ptr)
 | 
			
		||||
static int try_one(endpoint_t receive_e, struct proc *src_ptr,
 | 
			
		||||
    struct proc *dst_ptr)
 | 
			
		||||
{
 | 
			
		||||
/* Try to receive an asynchronous message from 'src_ptr' */
 | 
			
		||||
  int r = EAGAIN, done, do_notify;
 | 
			
		||||
  unsigned int flags, i;
 | 
			
		||||
  size_t size;
 | 
			
		||||
  endpoint_t dst;
 | 
			
		||||
  endpoint_t dst, src_e;
 | 
			
		||||
  struct proc *caller_ptr;
 | 
			
		||||
  struct priv *privp;
 | 
			
		||||
  asynmsg_t tabent;
 | 
			
		||||
@ -1330,9 +1346,10 @@ static int try_one(struct proc *src_ptr, struct proc *dst_ptr)
 | 
			
		||||
  unset_sys_bit(priv(dst_ptr)->s_asyn_pending, privp->s_id);
 | 
			
		||||
 | 
			
		||||
  if (size == 0) return(EAGAIN);
 | 
			
		||||
  if (!may_send_to(src_ptr, proc_nr(dst_ptr))) return(ECALLDENIED);
 | 
			
		||||
  if (!may_asynsend_to(src_ptr, proc_nr(dst_ptr))) return (ECALLDENIED);
 | 
			
		||||
 | 
			
		||||
  caller_ptr = src_ptr;	/* Needed for A_ macros later on */
 | 
			
		||||
  src_e = src_ptr->p_endpoint;
 | 
			
		||||
 | 
			
		||||
  /* Scan the table */
 | 
			
		||||
  do_notify = FALSE;
 | 
			
		||||
@ -1373,6 +1390,12 @@ static int try_one(struct proc *src_ptr, struct proc *dst_ptr)
 | 
			
		||||
	/* Message must be directed at receiving end */
 | 
			
		||||
	if (dst != dst_ptr->p_endpoint) continue;
 | 
			
		||||
 | 
			
		||||
	if (!CANRECEIVE(receive_e, src_e, dst_ptr,
 | 
			
		||||
		table_v + i*sizeof(asynmsg_t) + offsetof(struct asynmsg,msg),
 | 
			
		||||
		NULL)) {
 | 
			
		||||
		continue;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* If AMF_NOREPLY is set, then this message is not a reply to a
 | 
			
		||||
	 * SENDREC and thus should not satisfy the receiving part of the
 | 
			
		||||
	 * SENDREC. This message is to be delivered later.
 | 
			
		||||
 | 
			
		||||
@ -13,6 +13,7 @@
 | 
			
		||||
 | 
			
		||||
/* Struct declarations. */
 | 
			
		||||
struct proc;
 | 
			
		||||
struct ipc_filter_s;
 | 
			
		||||
 | 
			
		||||
/* clock.c */
 | 
			
		||||
clock_t get_realtime(void);
 | 
			
		||||
@ -100,6 +101,12 @@ void clear_endpoint(struct proc *rc);
 | 
			
		||||
void clear_ipc_refs(struct proc *rc, int caller_ret);
 | 
			
		||||
void kernel_call_resume(struct proc *p);
 | 
			
		||||
int sched_proc(struct proc *rp, int priority, int quantum, int cpu);
 | 
			
		||||
int add_ipc_filter(struct proc *rp, int type,
 | 
			
		||||
    vir_bytes address, size_t length);
 | 
			
		||||
void clear_ipc_filters(struct proc *rp);
 | 
			
		||||
int check_ipc_filter(struct ipc_filter_s *ipcf, int fill_flags);
 | 
			
		||||
int allow_ipc_filtered_msg(struct proc *rp, endpoint_t src_e,
 | 
			
		||||
    vir_bytes m_src_v, message *m_src_p);
 | 
			
		||||
 | 
			
		||||
/* system/do_vtimer.c */
 | 
			
		||||
void vtimer_check(struct proc *rp);
 | 
			
		||||
@ -128,6 +135,8 @@ char *schedulerstr(struct proc *scheduler);
 | 
			
		||||
void print_proc(struct proc *pp);
 | 
			
		||||
/* prints the given process and recursively all processes it depends on */
 | 
			
		||||
void print_proc_recursive(struct proc *pp);
 | 
			
		||||
void printmsg(message *msg, struct proc *src, struct proc *dst,
 | 
			
		||||
    char operation, int printparams);
 | 
			
		||||
#if DEBUG_IPC_HOOK
 | 
			
		||||
void hook_ipc_msgrecv(message *msg, struct proc *src, struct proc *dst);
 | 
			
		||||
void hook_ipc_msgsend(message *msg, struct proc *src, struct proc *dst);
 | 
			
		||||
 | 
			
		||||
@ -37,6 +37,7 @@
 | 
			
		||||
#include "kernel/vm.h"
 | 
			
		||||
#include "kernel/clock.h"
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
@ -674,3 +675,169 @@ int sched_proc(struct proc *p,
 | 
			
		||||
	return OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *				add_ipc_filter				     *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
int add_ipc_filter(struct proc *rp, int type, vir_bytes address,
 | 
			
		||||
	size_t length)
 | 
			
		||||
{
 | 
			
		||||
	int num_elements, r;
 | 
			
		||||
	ipc_filter_t *ipcf, **ipcfp;
 | 
			
		||||
 | 
			
		||||
	/* Validate arguments. */
 | 
			
		||||
	if (type != IPCF_BLACKLIST && type != IPCF_WHITELIST)
 | 
			
		||||
		return EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (length % sizeof(ipc_filter_el_t) != 0)
 | 
			
		||||
		return EINVAL;
 | 
			
		||||
 | 
			
		||||
	num_elements = length / sizeof(ipc_filter_el_t);
 | 
			
		||||
	if (num_elements <= 0 || num_elements > IPCF_MAX_ELEMENTS)
 | 
			
		||||
		return E2BIG;
 | 
			
		||||
 | 
			
		||||
	/* Allocate a new IPC filter slot. */
 | 
			
		||||
	IPCF_POOL_ALLOCATE_SLOT(type, &ipcf);
 | 
			
		||||
	if (ipcf == NULL)
 | 
			
		||||
		return ENOMEM;
 | 
			
		||||
 | 
			
		||||
	/* Fill details. */
 | 
			
		||||
	ipcf->num_elements = num_elements;
 | 
			
		||||
	ipcf->next = NULL;
 | 
			
		||||
	r = data_copy(rp->p_endpoint, address,
 | 
			
		||||
		KERNEL, (vir_bytes)ipcf->elements, length);
 | 
			
		||||
	if (r == OK)
 | 
			
		||||
		r = check_ipc_filter(ipcf, TRUE /*fill_flags*/);
 | 
			
		||||
	if (r != OK) {
 | 
			
		||||
		IPCF_POOL_FREE_SLOT(ipcf);
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Add the new filter at the end of the IPC filter chain. */
 | 
			
		||||
	for (ipcfp = &priv(rp)->s_ipcf; *ipcfp != NULL;
 | 
			
		||||
	    ipcfp = &(*ipcfp)->next)
 | 
			
		||||
		;
 | 
			
		||||
	*ipcfp = ipcf;
 | 
			
		||||
 | 
			
		||||
	return OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *				clear_ipc_filters			     *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
void clear_ipc_filters(struct proc *rp)
 | 
			
		||||
{
 | 
			
		||||
	ipc_filter_t *curr_ipcf, *ipcf;
 | 
			
		||||
 | 
			
		||||
	ipcf = priv(rp)->s_ipcf;
 | 
			
		||||
	while (ipcf != NULL) {
 | 
			
		||||
		curr_ipcf = ipcf;
 | 
			
		||||
		ipcf = ipcf->next;
 | 
			
		||||
		IPCF_POOL_FREE_SLOT(curr_ipcf);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	priv(rp)->s_ipcf = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *				check_ipc_filter			     *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
int check_ipc_filter(ipc_filter_t *ipcf, int fill_flags)
 | 
			
		||||
{
 | 
			
		||||
	ipc_filter_el_t *ipcf_el;
 | 
			
		||||
	int i, num_elements, flags;
 | 
			
		||||
 | 
			
		||||
	if (ipcf == NULL)
 | 
			
		||||
		return OK;
 | 
			
		||||
 | 
			
		||||
	num_elements = ipcf->num_elements;
 | 
			
		||||
	flags = 0;
 | 
			
		||||
	for (i = 0; i < num_elements; i++) {
 | 
			
		||||
		ipcf_el = &ipcf->elements[i];
 | 
			
		||||
		if (!IPCF_EL_CHECK(ipcf_el))
 | 
			
		||||
			return EINVAL;
 | 
			
		||||
		flags |= ipcf_el->flags;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (fill_flags)
 | 
			
		||||
		ipcf->flags = flags;
 | 
			
		||||
	else if (ipcf->flags != flags)
 | 
			
		||||
		return EINVAL;
 | 
			
		||||
	return OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *				allow_ipc_filtered_msg			     *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
int allow_ipc_filtered_msg(struct proc *rp, endpoint_t src_e,
 | 
			
		||||
	vir_bytes m_src_v, message *m_src_p)
 | 
			
		||||
{
 | 
			
		||||
	int i, r, num_elements, get_mtype, allow;
 | 
			
		||||
	ipc_filter_t *ipcf;
 | 
			
		||||
	ipc_filter_el_t *ipcf_el;
 | 
			
		||||
	message m_buff;
 | 
			
		||||
 | 
			
		||||
	ipcf = priv(rp)->s_ipcf;
 | 
			
		||||
	if (ipcf == NULL)
 | 
			
		||||
		return TRUE; /* no IPC filters, always allow */
 | 
			
		||||
 | 
			
		||||
	if (m_src_p == NULL) {
 | 
			
		||||
		assert(m_src_v != 0);
 | 
			
		||||
 | 
			
		||||
		/* Should we copy in the message type? */
 | 
			
		||||
		get_mtype = FALSE;
 | 
			
		||||
		do {
 | 
			
		||||
#if DEBUG_DUMPIPCF
 | 
			
		||||
			if (TRUE) {
 | 
			
		||||
#else
 | 
			
		||||
			if (ipcf->flags & IPCF_MATCH_M_TYPE) {
 | 
			
		||||
#endif
 | 
			
		||||
				get_mtype = TRUE;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			ipcf = ipcf->next;
 | 
			
		||||
		} while (ipcf);
 | 
			
		||||
		ipcf = priv(rp)->s_ipcf; /* reset to start */
 | 
			
		||||
 | 
			
		||||
		/* If so, copy it in from the process. */
 | 
			
		||||
		if (get_mtype) {
 | 
			
		||||
			r = data_copy(src_e,
 | 
			
		||||
			    m_src_v + offsetof(message, m_type), KERNEL,
 | 
			
		||||
			    (vir_bytes)&m_buff.m_type, sizeof(m_buff.m_type));
 | 
			
		||||
			if (r != OK) {
 | 
			
		||||
				/* allow for now, this will fail later anyway */
 | 
			
		||||
#if DEBUG_DUMPIPCF
 | 
			
		||||
				printf("KERNEL: allow_ipc_filtered_msg: data "
 | 
			
		||||
				    "copy error %d, allowing message...\n", r);
 | 
			
		||||
#endif
 | 
			
		||||
				return TRUE;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		m_src_p = &m_buff;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m_src_p->m_source = src_e;
 | 
			
		||||
 | 
			
		||||
	/* See if the message is allowed. */
 | 
			
		||||
	allow = (ipcf->type == IPCF_BLACKLIST);
 | 
			
		||||
	do {
 | 
			
		||||
		if (allow != (ipcf->type == IPCF_WHITELIST)) {
 | 
			
		||||
			num_elements = ipcf->num_elements;
 | 
			
		||||
			for (i = 0; i < num_elements; i++) {
 | 
			
		||||
				ipcf_el = &ipcf->elements[i];
 | 
			
		||||
				if (IPCF_EL_MATCH(ipcf_el, m_src_p)) {
 | 
			
		||||
					allow = (ipcf->type == IPCF_WHITELIST);
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		ipcf = ipcf->next;
 | 
			
		||||
	} while (ipcf);
 | 
			
		||||
 | 
			
		||||
#if DEBUG_DUMPIPCF
 | 
			
		||||
	printmsg(m_src_p, proc_addr(_ENDPOINT_P(src_e)), rp, allow ? '+' : '-',
 | 
			
		||||
	    TRUE /*printparams*/);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return allow;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -149,7 +149,7 @@ int do_privctl(struct proc * caller, message * m_ptr)
 | 
			
		||||
	priv(rp)->s_bak_sig_mgr = NONE;
 | 
			
		||||
 | 
			
		||||
	/* Set defaults for resources: no I/O resources, no memory resources,
 | 
			
		||||
	 * no IRQs, no grant table
 | 
			
		||||
	 * no IRQs, no grant table, no ipc filter
 | 
			
		||||
	 */
 | 
			
		||||
	priv(rp)->s_nr_io_range= 0;
 | 
			
		||||
	priv(rp)->s_nr_mem_range= 0;
 | 
			
		||||
@ -158,6 +158,7 @@ int do_privctl(struct proc * caller, message * m_ptr)
 | 
			
		||||
	priv(rp)->s_grant_entries= 0;
 | 
			
		||||
	priv(rp)->s_state_table= 0;
 | 
			
		||||
	priv(rp)->s_state_entries= 0;
 | 
			
		||||
	priv(rp)->s_ipcf= 0;
 | 
			
		||||
 | 
			
		||||
	/* Override defaults if the caller has supplied a privilege structure. */
 | 
			
		||||
	if (m_ptr->m_lsys_krn_sys_privctl.arg_ptr)
 | 
			
		||||
 | 
			
		||||
@ -29,6 +29,20 @@ int do_statectl(struct proc * caller, message * m_ptr)
 | 
			
		||||
	priv(caller)->s_state_table = (vir_bytes) m_ptr->m_lsys_krn_sys_statectl.address;
 | 
			
		||||
	priv(caller)->s_state_entries = m_ptr->m_lsys_krn_sys_statectl.length;
 | 
			
		||||
	return(OK);
 | 
			
		||||
  case SYS_STATE_ADD_IPC_BL_FILTER:
 | 
			
		||||
	/* Add an IPC blacklist filter for the caller. */
 | 
			
		||||
	return add_ipc_filter(caller, IPCF_BLACKLIST,
 | 
			
		||||
	    (vir_bytes) m_ptr->m_lsys_krn_sys_statectl.address,
 | 
			
		||||
	    m_ptr->m_lsys_krn_sys_statectl.length);
 | 
			
		||||
  case SYS_STATE_ADD_IPC_WL_FILTER:
 | 
			
		||||
	/* Add an IPC whitelist filter for the caller. */
 | 
			
		||||
	return add_ipc_filter(caller, IPCF_WHITELIST,
 | 
			
		||||
	    (vir_bytes) m_ptr->m_lsys_krn_sys_statectl.address,
 | 
			
		||||
	    m_ptr->m_lsys_krn_sys_statectl.length);
 | 
			
		||||
  case SYS_STATE_CLEAR_IPC_FILTERS:
 | 
			
		||||
	/* Clear any IPC filter for the caller. */
 | 
			
		||||
	clear_ipc_filters(caller);
 | 
			
		||||
	return OK;
 | 
			
		||||
  default:
 | 
			
		||||
	printf("do_statectl: bad request %d\n",
 | 
			
		||||
		m_ptr->m_lsys_krn_sys_statectl.request);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user