From: Tomas Hruby Date: Mon, 29 Mar 2010 11:25:01 +0000 (+0000) Subject: A reliable way for userspace to check if a msg is from kernel X-Git-Tag: v3.1.7~196 X-Git-Url: http://zhaoyanbai.com/repos/?a=commitdiff_plain;h=5b52c5aa0202d8794798b9748050bbda180d125c;p=minix.git A reliable way for userspace to check if a msg is from kernel - IPC_FLG_MSG_FROM_KERNEL status flag is returned to userspace if the receive was satisfied by s message which was sent by the kernel on behalf of a process. This perfectly reliale information. - MF_SENDING_FROM_KERNEL flag added to processes to be able to set IPC_FLG_MSG_FROM_KERNEL when finishing receive if the receiver wasn't ready to receive immediately. - PM is changed to use this information to confirm that the scheduling messages are indeed from the kernel and not faked by a process. PM uses sef_receive_status() - get_work() is removed from PM to make the changes simpler --- diff --git a/include/minix/ipcconst.h b/include/minix/ipcconst.h index 04aca7954..c077b2c9e 100644 --- a/include/minix/ipcconst.h +++ b/include/minix/ipcconst.h @@ -17,4 +17,12 @@ #define IPC_STATUS_CALL_TO(call) \ (((call) & IPC_STATUS_CALL_MASK) << IPC_STATUS_CALL_SHIFT) +#define IPC_FLG_MSG_FROM_KERNEL 1 /* this message originated in the kernel on + behalf of a process, this is a trusted + message, never reply to the sender + */ +#define IPC_STATUS_FLAGS_SHIFT 16 +#define IPC_STATUS_FLAGS(flgs) ((flgs) << IPC_STATUS_FLAGS_SHIFT) +#define IPC_STATUS_FLAGS_TEST(status, flgs) \ + (((status) >> IPC_STATUS_FLAGS_SHIFT) & (flgs)) #endif /* IPC_CONST_H */ diff --git a/kernel/proc.c b/kernel/proc.c index 65d3125d1..ae07acfcb 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -540,8 +540,12 @@ const int flags; if (!(flags & FROM_KERNEL)) { if(copy_msg_from_user(caller_ptr, m_ptr, &dst_ptr->p_delivermsg)) return EFAULT; - } else + } else { dst_ptr->p_delivermsg = *m_ptr; + IPC_STATUS_ADD(dst_ptr, + IPC_STATUS_FLAGS(IPC_FLG_MSG_FROM_KERNEL)); + } + dst_ptr->p_delivermsg.m_source = caller_ptr->p_endpoint; dst_ptr->p_misc_flags |= MF_DELIVERMSG; @@ -563,8 +567,15 @@ const int flags; if (!(flags & FROM_KERNEL)) { if(copy_msg_from_user(caller_ptr, m_ptr, &caller_ptr->p_sendmsg)) return EFAULT; - } else + } else { caller_ptr->p_sendmsg = *m_ptr; + /* + * we need to remember that this message is from kernel so we + * can set the delivery status flags when the message is + * actually delivered + */ + caller_ptr->p_misc_flags |= MF_SENDING_FROM_KERNEL; + } RTS_SET(caller_ptr, RTS_SENDING); caller_ptr->p_sendto_e = dst_e; @@ -693,6 +704,17 @@ const int flags; call = ((*xpp)->p_misc_flags & MF_REPLY_PEND ? SENDREC : SEND); IPC_STATUS_ADD(caller_ptr, IPC_STATUS_CALL_TO(call)); + + /* + * if the message is originaly from the kernel on behalf of this + * process, we must send the status flags accordingly + */ + if ((*xpp)->p_misc_flags & MF_SENDING_FROM_KERNEL) { + IPC_STATUS_ADD(caller_ptr, + IPC_STATUS_FLAGS(IPC_FLG_MSG_FROM_KERNEL)); + /* we can clean the flag now, not need anymore */ + (*xpp)->p_misc_flags &= ~MF_SENDING_FROM_KERNEL; + } if ((*xpp)->p_misc_flags & MF_SIG_DELAY) sig_delay_done(*xpp); diff --git a/kernel/proc.h b/kernel/proc.h index 3de178269..b4b38155a 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -221,6 +221,7 @@ struct proc { #define MF_USED_FPU 0x800 /* process used fpu during last execution run */ #define MF_FPU_INITIALIZED 0x1000 /* process already used math, so fpu * regs are significant (initialized)*/ +#define MF_SENDING_FROM_KERNEL 0x2000 /* message of this process is from kernel */ /* Scheduling priorities for p_priority. Values must start at zero (highest * priority) and increment. Priorities of the processes in the boot image diff --git a/servers/pm/main.c b/servers/pm/main.c index 2f7a6c84a..0a0212e2a 100644 --- a/servers/pm/main.c +++ b/servers/pm/main.c @@ -40,7 +40,6 @@ EXTERN unsigned long calls_stats[NCALLS]; #endif FORWARD _PROTOTYPE( void sendreply, (void) ); -FORWARD _PROTOTYPE( void get_work, (void) ); FORWARD _PROTOTYPE( int get_nice_value, (int queue) ); FORWARD _PROTOTYPE( void handle_fs_reply, (void) ); @@ -70,14 +69,32 @@ PUBLIC int main() /* This is PM's main loop- get work and do it, forever and forever. */ while (TRUE) { - get_work(); /* wait for an PM system call */ + int ipc_status; + + /* Wait for the next message and extract useful information from it. */ + if (sef_receive_status(ANY, &m_in, &ipc_status) != OK) + panic("PM sef_receive error"); + who_e = m_in.m_source; /* who sent the message */ + if(pm_isokendpt(who_e, &who_p) != OK) + panic("PM got message from invalid endpoint: %d", who_e); + call_nr = m_in.m_type; /* system call number */ + + /* Process slot of caller. Misuse PM's own process slot if the kernel is + * calling. This can happen in case of synchronous alarms (CLOCK) or or + * event like pending kernel signals (SYSTEM). + */ + mp = &mproc[who_p < 0 ? PM_PROC_NR : who_p]; + if(who_p >= 0 && mp->mp_endpoint != who_e) { + panic("PM endpoint number out of sync with source: %d", + mp->mp_endpoint); + } /* Drop delayed calls from exiting processes. */ if (mp->mp_flags & EXITING) continue; /* Check for system notifications first. Special cases. */ - if (is_notify(call_nr)) { + if (is_ipc_notify(ipc_status)) { switch(who_p) { case CLOCK: pm_expire_timers(m_in.NOTIFY_TIMESTAMP); @@ -116,7 +133,13 @@ PUBLIC int main() break; case SCHEDULING_NO_QUANTUM: /* This message was sent from the kernel, don't reply */ - do_noquantum(); + if (IPC_STATUS_FLAGS_TEST(ipc_status, IPC_FLG_MSG_FROM_KERNEL)) { + do_noquantum(); + } else { + printf("PM: process %s/%d faked SCHEDULING_NO_QUANTUM " + "message!\n", + mp->mp_name, mp->mp_endpoint); + } continue; default: /* Else, if the system call number is valid, perform the @@ -314,29 +337,6 @@ PRIVATE int sef_cb_signal_manager(endpoint_t target, int signo) return r; } -/*===========================================================================* - * get_work * - *===========================================================================*/ -PRIVATE void get_work() -{ -/* Wait for the next message and extract useful information from it. */ - if (sef_receive(ANY, &m_in) != OK) - panic("PM sef_receive error"); - who_e = m_in.m_source; /* who sent the message */ - if(pm_isokendpt(who_e, &who_p) != OK) - panic("PM got message from invalid endpoint: %d", who_e); - call_nr = m_in.m_type; /* system call number */ - - /* Process slot of caller. Misuse PM's own process slot if the kernel is - * calling. This can happen in case of synchronous alarms (CLOCK) or or - * event like pending kernel signals (SYSTEM). - */ - mp = &mproc[who_p < 0 ? PM_PROC_NR : who_p]; - if(who_p >= 0 && mp->mp_endpoint != who_e) { - panic("PM endpoint number out of sync with source: %d", mp->mp_endpoint); - } -} - /*===========================================================================* * setreply * *===========================================================================*/