From 5df3e934b96988b5accbf468d8fa3a6cb705eaef Mon Sep 17 00:00:00 2001 From: mav Date: Thu, 31 Jan 2008 08:51:48 +0000 Subject: Implement stack protection based on GET_STACK_USAGE() macro. This fixes system panics possible with complicated netgraph setups and allows to avoid unneded extra queueing for stack unwrapping. --- sys/netgraph/netgraph.h | 23 +++++++++++++++++++++++ sys/netgraph/ng_base.c | 30 ++++++++++++++++++++++-------- sys/netgraph/ng_iface.c | 1 + 3 files changed, 46 insertions(+), 8 deletions(-) (limited to 'sys') diff --git a/sys/netgraph/netgraph.h b/sys/netgraph/netgraph.h index 792814c..69559ce 100644 --- a/sys/netgraph/netgraph.h +++ b/sys/netgraph/netgraph.h @@ -127,6 +127,7 @@ struct ng_hook { #define HK_QUEUE 0x0002 /* queue for later delivery */ #define HK_FORCE_WRITER 0x0004 /* Incoming data queued as a writer */ #define HK_DEAD 0x0008 /* This is the dead hook.. don't free */ +#define HK_HI_STACK 0x0010 /* Hook has hi stack usage */ /* * Public Methods for hook @@ -147,6 +148,7 @@ void ng_unref_hook(hook_p hook); /* don't move this */ #define _NG_HOOK_FORCE_WRITER(hook) \ do { hook->hk_flags |= HK_FORCE_WRITER; } while (0) #define _NG_HOOK_FORCE_QUEUE(hook) do { hook->hk_flags |= HK_QUEUE; } while (0) +#define _NG_HOOK_HI_STACK(hook) do { hook->hk_flags |= HK_HI_STACK; } while (0) /* Some shortcuts */ #define NG_PEER_NODE(hook) NG_HOOK_NODE(NG_HOOK_PEER(hook)) @@ -277,6 +279,13 @@ _ng_hook_force_queue(hook_p hook, char * file, int line) _NG_HOOK_FORCE_QUEUE(hook); } +static __inline void +_ng_hook_hi_stack(hook_p hook, char * file, int line) +{ + _chkhook(hook, file, line); + _NG_HOOK_HI_STACK(hook); +} + #define NG_HOOK_REF(hook) _ng_hook_ref(hook, _NN_) #define NG_HOOK_NAME(hook) _ng_hook_name(hook, _NN_) @@ -291,6 +300,7 @@ _ng_hook_force_queue(hook_p hook, char * file, int line) #define NG_HOOK_PEER(hook) _ng_hook_peer(hook, _NN_) #define NG_HOOK_FORCE_WRITER(hook) _ng_hook_force_writer(hook, _NN_) #define NG_HOOK_FORCE_QUEUE(hook) _ng_hook_force_queue(hook, _NN_) +#define NG_HOOK_HI_STACK(hook) _ng_hook_hi_stack(hook, _NN_) #else /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ @@ -307,6 +317,7 @@ _ng_hook_force_queue(hook_p hook, char * file, int line) #define NG_HOOK_PEER(hook) _NG_HOOK_PEER(hook) #define NG_HOOK_FORCE_WRITER(hook) _NG_HOOK_FORCE_WRITER(hook) #define NG_HOOK_FORCE_QUEUE(hook) _NG_HOOK_FORCE_QUEUE(hook) +#define NG_HOOK_HI_STACK(hook) _NG_HOOK_HI_STACK(hook) #endif /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ @@ -360,6 +371,7 @@ struct ng_node { #define NG_CLOSING NGF_CLOSING /* compat for old code */ #define NGF_REALLY_DIE 0x00000010 /* "persistent" node is unloading */ #define NG_REALLY_DIE NGF_REALLY_DIE /* compat for old code */ +#define NGF_HI_STACK 0x00000020 /* node has hi stack usage */ #define NGF_TYPE1 0x10000000 /* reserved for type specific storage */ #define NGF_TYPE2 0x20000000 /* reserved for type specific storage */ #define NGF_TYPE3 0x40000000 /* reserved for type specific storage */ @@ -382,6 +394,8 @@ int ng_unref_node(node_p node); /* don't move this */ #define _NG_NODE_NUMHOOKS(node) ((node)->nd_numhooks + 0) /* rvalue */ #define _NG_NODE_FORCE_WRITER(node) \ do{ node->nd_flags |= NGF_FORCE_WRITER; }while (0) +#define _NG_NODE_HI_STACK(node) \ + do{ node->nd_flags |= NGF_HI_STACK; }while (0) #define _NG_NODE_REALLY_DIE(node) \ do{ node->nd_flags |= (NGF_REALLY_DIE|NGF_INVALID); }while (0) #define _NG_NODE_REVIVE(node) \ @@ -513,6 +527,13 @@ _ng_node_force_writer(node_p node, char *file, int line) } static __inline void +_ng_node_hi_stack(node_p node, char *file, int line) +{ + _chknode(node, file, line); + _NG_NODE_HI_STACK(node); +} + +static __inline void _ng_node_really_die(node_p node, char *file, int line) { _chknode(node, file, line); @@ -546,6 +567,7 @@ _ng_node_foreach_hook(node_p node, ng_fn_eachhook *fn, void *arg, #define NG_NODE_IS_VALID(node) _ng_node_is_valid(node, _NN_) #define NG_NODE_NOT_VALID(node) _ng_node_not_valid(node, _NN_) #define NG_NODE_FORCE_WRITER(node) _ng_node_force_writer(node, _NN_) +#define NG_NODE_HI_STACK(node) _ng_node_hi_stack(node, _NN_) #define NG_NODE_REALLY_DIE(node) _ng_node_really_die(node, _NN_) #define NG_NODE_NUMHOOKS(node) _ng_node_numhooks(node, _NN_) #define NG_NODE_REVIVE(node) _ng_node_revive(node, _NN_) @@ -566,6 +588,7 @@ _ng_node_foreach_hook(node_p node, ng_fn_eachhook *fn, void *arg, #define NG_NODE_IS_VALID(node) _NG_NODE_IS_VALID(node) #define NG_NODE_NOT_VALID(node) _NG_NODE_NOT_VALID(node) #define NG_NODE_FORCE_WRITER(node) _NG_NODE_FORCE_WRITER(node) +#define NG_NODE_HI_STACK(node) _NG_NODE_HI_STACK(node) #define NG_NODE_REALLY_DIE(node) _NG_NODE_REALLY_DIE(node) #define NG_NODE_NUMHOOKS(node) _NG_NODE_NUMHOOKS(node) #define NG_NODE_REVIVE(node) _NG_NODE_REVIVE(node) diff --git a/sys/netgraph/ng_base.c b/sys/netgraph/ng_base.c index 47fde60..f61d2fd 100644 --- a/sys/netgraph/ng_base.c +++ b/sys/netgraph/ng_base.c @@ -60,6 +60,7 @@ #include #include #include +#include #include @@ -2300,8 +2301,6 @@ ng_snd_item(item_p item, int flags) ERROUT(EINVAL); /* No address */ } - queue = (flags & NG_QUEUE) ? 1 : 0; - switch(item->el_flags & NGQF_TYPE) { case NGQF_DATA: /* @@ -2327,9 +2326,6 @@ ng_snd_item(item_p item, int flags) || (NG_NODE_NOT_VALID(NG_HOOK_NODE(hook)))) { ERROUT(ENOTCONN); } - if ((hook->hk_flags & HK_QUEUE)) { - queue = 1; - } break; case NGQF_MESG: /* @@ -2339,9 +2335,6 @@ ng_snd_item(item_p item, int flags) * References are held by the item on the node and * the hook if it is present. */ - if (hook && (hook->hk_flags & HK_QUEUE)) { - queue = 1; - } break; case NGQF_FN: case NGQF_FN2: @@ -2370,6 +2363,27 @@ ng_snd_item(item_p item, int flags) || (hook && (hook->hk_flags & HK_FORCE_WRITER))) rw = NGQRW_W; + /* + * If sender or receiver requests queued delivery or stack usage + * level is dangerous - enqueue message. + */ + queue = 0; + if ((flags & NG_QUEUE) || (hook && (hook->hk_flags & HK_QUEUE))) { + queue = 1; + } +#ifdef GET_STACK_USAGE + else { + size_t st, su; + GET_STACK_USAGE(st, su); + su = (su * 128) / st; + if ((su > 100) || + ((su > 64) && ((node->nd_flags & NGF_HI_STACK) || + (hook && (hook->hk_flags & HK_HI_STACK))))) { + queue = 1; + } + } +#endif + if (queue) { /* Put it on the queue for that node*/ #ifdef NETGRAPH_DEBUG diff --git a/sys/netgraph/ng_iface.c b/sys/netgraph/ng_iface.c index b3c177a..fec2432 100644 --- a/sys/netgraph/ng_iface.c +++ b/sys/netgraph/ng_iface.c @@ -573,6 +573,7 @@ ng_iface_newhook(node_p node, hook_p hook, const char *name) if (*hookptr != NULL) return (EISCONN); *hookptr = hook; + NG_HOOK_HI_STACK(hook); return (0); } -- cgit v1.1