Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F152512252
D51800.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
3 KB
Referenced Files
None
Subscribers
None
D51800.id.diff
View Options
diff --git a/sys/net/pfil.h b/sys/net/pfil.h
--- a/sys/net/pfil.h
+++ b/sys/net/pfil.h
@@ -136,6 +136,7 @@
/* Public functions for pfil hook management by packet filters. */
pfil_hook_t pfil_add_hook(struct pfil_hook_args *);
void pfil_remove_hook(pfil_hook_t);
+void pfil_mbuf_skip_hook(struct mbuf *, pfil_hook_t);
/* Argument structure used by ioctl() and packet filters to set filters. */
struct pfil_link_args {
@@ -192,5 +193,8 @@
#define PFIL_HOOKED_IN(p) (((struct _pfil_head *)(p))->head_nhooksin > 0)
#define PFIL_HOOKED_OUT(p) (((struct _pfil_head *)(p))->head_nhooksout > 0)
+#define MTAG_PFIL 0x7066696c /* hex for ascii pfil */
+#define MTAG_PFIL_NEXT_HOOK 0
+
#endif /* _KERNEL */
#endif /* _NET_PFIL_H_ */
diff --git a/sys/net/pfil.c b/sys/net/pfil.c
--- a/sys/net/pfil.c
+++ b/sys/net/pfil.c
@@ -193,12 +193,33 @@
return (pfil_mem_common(&head->head_out, mem, len, PFIL_OUT, ifp, m));
}
+static __always_inline struct pfil_hook**
+pfil_mbuf_get_skip_mtag(struct mbuf **m) {
+ struct m_tag *mtag;
+
+ mtag = m_tag_locate(*m, MTAG_PFIL, MTAG_PFIL_NEXT_HOOK, NULL);
+ if (mtag != NULL)
+ return (struct pfil_hook**)(mtag + 1);
+
+ mtag = m_tag_alloc(MTAG_PFIL, MTAG_PFIL_NEXT_HOOK, sizeof(void*),
+ M_ZERO | M_NOWAIT);
+ if (mtag == NULL) {
+ /* Drop the packet to prevent looping */
+ m_freem(*m);
+ *m = NULL;
+ return NULL;
+ }
+ m_tag_prepend(*m, mtag);
+ return (struct pfil_hook**)(mtag + 1);
+}
+
static __always_inline int
pfil_mbuf_common(pfil_chain_t *pch, struct mbuf **m, struct ifnet *ifp,
int flags, struct inpcb *inp)
{
- struct pfil_link *link;
- pfil_return_t rv;
+ struct pfil_hook **last_hook;
+ struct pfil_link *link;
+ pfil_return_t rv;
NET_EPOCH_ASSERT();
KASSERT((flags & ~(PFIL_IN|PFIL_OUT|PFIL_FWD)) == 0,
@@ -207,17 +228,45 @@
(flags & ~PFIL_FWD) == PFIL_OUT,
("%s: conflicting directions %#x", __func__, flags));
+ if ((last_hook = pfil_mbuf_get_skip_mtag(m)) == NULL)
+ return PFIL_DROPPED;
+
rv = PFIL_PASS;
CK_STAILQ_FOREACH(link, pch, link_chain) {
+ /*
+ * We can't use CK_STAILQ_FOREACH_FROM because list of pfil
+ * hooks could have been modified, so we can't trust that the
+ * pointer is still valid.
+ */
+ if (*last_hook != NULL) {
+ if (*last_hook == link->link_hook)
+ *last_hook = NULL;
+ continue;
+ }
+ /*
+ * Set the last_hook link before link_mbuf_chk() in case
+ * the hook consumes and then re-injects the packet, like
+ * for example dummynet does.
+ */
+ *last_hook = link->link_hook;
rv = link->link_mbuf_chk(m, ifp, flags, link->link_ruleset,
inp);
if (rv == PFIL_DROPPED || rv == PFIL_CONSUMED) {
MPASS(*m == NULL);
- break;
+ return (rv);
} else {
MPASS(*m != NULL);
}
+ /*
+ * Find the last_hook tag again, in case the pfil hook
+ * has changed *m, like for example happens for mbufs
+ * reassempled by pf.
+ */
+ if ((last_hook = pfil_mbuf_get_skip_mtag(m)) == NULL)
+ return PFIL_DROPPED;
+ *last_hook = NULL;
}
+ *last_hook = NULL;
return (rv);
}
@@ -508,6 +557,18 @@
free(hook, M_PFIL);
}
+/*
+ * Modify last hook tracking of pfil_mbuf_common to skip to after the given hook
+ */
+void pfil_mbuf_skip_hook(struct mbuf *m, pfil_hook_t hook)
+{
+ struct m_tag *pfil_mtag;
+
+ pfil_mtag = m_tag_locate(m, MTAG_PFIL, MTAG_PFIL_NEXT_HOOK, NULL);
+ MPASS(pfil_mtag != NULL);
+ *(pfil_hook_t *)(pfil_mtag + 1) = hook;
+}
+
/*
* Internal: Remove a pfil hook from a hook chain.
*/
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Apr 16, 10:30 AM (14 h, 3 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31596226
Default Alt Text
D51800.id.diff (3 KB)
Attached To
Mode
D51800: [pfil loop prevention experiment 4/5] pfil: Provide looping prevention mechanism
Attached
Detach File
Event Timeline
Log In to Comment