]> Zhao Yanbai Git Server - minix.git/commitdiff
kernel: Add support for IPC filters. 80/3080/2
authorCristiano Giuffrida <giuffrida@cs.vu.nl>
Wed, 12 Mar 2014 18:34:52 +0000 (19:34 +0100)
committerDavid van Moolenbroek <david@minix3.org>
Wed, 16 Sep 2015 11:02:24 +0000 (11:02 +0000)
Edited by David van Moolenbroek.

Change-Id: Ia0052c42a0f218d011dd2da1e3db6c5b2107adc7

15 files changed:
distrib/sets/lists/minix/mi
minix/include/minix/Makefile
minix/include/minix/com.h
minix/include/minix/ipc_filter.h [new file with mode: 0644]
minix/kernel/debug.c
minix/kernel/debug.h
minix/kernel/ipc.h
minix/kernel/ipc_filter.h [new file with mode: 0644]
minix/kernel/main.c
minix/kernel/priv.h
minix/kernel/proc.c
minix/kernel/proto.h
minix/kernel/system.c
minix/kernel/system/do_privctl.c
minix/kernel/system/do_statectl.c

index ea23bc671ff9db6cfcbf18c64b52fe13cd673aee..573647fc44ce67e7eb12abcc63e13b420f4b7388 100644 (file)
 ./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
index bb255599f4891fddc0c6472495f907bef8c96d4d..65406db335d1038a9fabdfacbf98f3e0fc69abea 100644 (file)
@@ -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 \
index f2474f9263718ca6b07757d12a400fbc5bbdcd45..5010cb3af805f5c6c7178578fef0a13f6bf6bc8b 100644 (file)
 /* 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 
diff --git a/minix/include/minix/ipc_filter.h b/minix/include/minix/ipc_filter.h
new file mode 100644 (file)
index 0000000..62d787a
--- /dev/null
@@ -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 */
index 793749e9ec8d36d319d96eecb570beb8296f354a..4463512e6810cdf6305920016a6b82e8267732c6 100644 (file)
@@ -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;
index a41dd77f03a559972a4da67d1342e40f0ee310ab..446904102311f916f4aa57f4581ee934c63ab0fc 100644 (file)
  */
 #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" } */
 
index a62919eb94542f58c660803cf44dce0b4e8e7160..fe00ac16d4867cfb1f6b484e202189dfee0b17f5 100644 (file)
 #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)
diff --git a/minix/kernel/ipc_filter.h b/minix/kernel/ipc_filter.h
new file mode 100644 (file)
index 0000000..a8b290d
--- /dev/null
@@ -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 */
index 8786f48ecc7c4bd892dd1574edf9db99f5633b3d..f351a06a20c66bf8e8c3944afc209b62ee0dda32 100644 (file)
@@ -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",
index 31cf215d68b7b453dece709502032396a9e5c3c2..06e4c091e7a65b164cb60a250cd4b9d11816c0f3 100644 (file)
@@ -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 
index 51920648c450355b2bfc0b26db815e18080c3bfe..1629b3ca697d9d55dd5985b342234c4e43d16dee 100644 (file)
@@ -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.
index 0400d6772a8c4cd6fc22c1ad0efdc95c9b138822..fd1f6f08127e2e240b21e5d30b3bf05010e052f7 100644 (file)
@@ -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);
index ea9c924569a80857773cf991cb88e4d97bbdf7b9..4cf9fdcea0ef0605bce96ed339116771e0e42fe6 100644 (file)
@@ -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;
+}
+
index ef2b9ffae649e12756187e4311800743c1121500..41eee88c77309743a20631c79431d4110a213a5f 100644 (file)
@@ -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)
index d9c9d5296c6d39644ae02dba7687fe08672c350e..e2cdc85dcdd8475b872be1c2d1967de50d0ac98c 100644 (file)
@@ -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);