From b65eae4c193f1c3c9580e5ac2bad5585034743f2 Mon Sep 17 00:00:00 2001 From: mlaier Date: Wed, 29 Sep 2004 04:54:33 +0000 Subject: Add an additional struct inpcb * argument to pfil(9) in order to enable passing along socket information. This is required to work around a LOR with the socket code which results in an easy reproducible hard lockup with debug.mpsafenet=1. This commit does *not* fix the LOR, but enables us to do so later. The missing piece is to turn the filter locking into a leaf lock and will follow in a seperate (later) commit. This will hopefully be MT5'ed in order to fix the problem for RELENG_5 in forseeable future. Suggested by: rwatson A lot of work by: csjp (he'd be even more helpful w/o mentor-reviews ;) Reviewed by: rwatson, csjp Tested by: -pf, -ipfw, LINT, csjp and myself MFC after: 3 days LOR IDs: 14 - 17 (not fixed yet) --- sys/contrib/ipfilter/netinet/ip_fil.c | 27 ++++++++++- sys/contrib/pf/net/pf.c | 87 ++++++++++++++++++++++++++++++++++- sys/contrib/pf/net/pf_ioctl.c | 28 ++++++----- sys/contrib/pf/net/pfvar.h | 11 +++++ sys/net/bridge.c | 2 +- sys/net/pfil.c | 12 ++--- sys/net/pfil.h | 9 ++-- sys/netinet/ip_fastfwd.c | 4 +- sys/netinet/ip_fw.h | 5 +- sys/netinet/ip_fw2.c | 43 ++++++++++++----- sys/netinet/ip_fw_pfil.c | 8 +++- sys/netinet/ip_input.c | 2 +- sys/netinet/ip_output.c | 2 +- sys/netinet6/ip6_forward.c | 2 +- sys/netinet6/ip6_input.c | 2 +- sys/netinet6/ip6_output.c | 2 +- sys/sys/param.h | 2 +- 17 files changed, 198 insertions(+), 50 deletions(-) (limited to 'sys') diff --git a/sys/contrib/ipfilter/netinet/ip_fil.c b/sys/contrib/ipfilter/netinet/ip_fil.c index 9ac3fb2..954f540 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil.c +++ b/sys/contrib/ipfilter/netinet/ip_fil.c @@ -312,7 +312,8 @@ int dir; } # endif #endif /* __NetBSD_Version >= 105110000 && _KERNEL */ -#if (__FreeBSD_version >= 501108) && defined(_KERNEL) +#if (__FreeBSD_version >= 501108) && (__FreeBSD_version < 600004) && \ + defined(_KERNEL) static int fr_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) @@ -331,7 +332,29 @@ fr_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) ifp, (dir == PFIL_OUT), mp)); } # endif -#endif /* __FreeBSD_version >= 501108 */ + +#elif (__FreeBSD_version >= 600004) && defined(_KERNEL) + +static int +fr_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir, + struct inpcb *inp) +{ + struct ip *ip = mtod(*mp, struct ip *); + return fr_check(ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), mp); +} + +# ifdef USE_INET6 +# include + +static int +fr_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir, + struct inpcb *inp) +{ + return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr), + ifp, (dir == PFIL_OUT), mp)); +} +# endif +#endif /* __FreeBSD_version >= 600004 && _KERNEL */ #ifdef _KERNEL # if defined(IPFILTER_LKM) && !defined(__sgi) int iplidentify(s) diff --git a/sys/contrib/pf/net/pf.c b/sys/contrib/pf/net/pf.c index 9e2bfee..2a5b627 100644 --- a/sys/contrib/pf/net/pf.c +++ b/sys/contrib/pf/net/pf.c @@ -185,11 +185,19 @@ struct pf_rule *pf_get_translation(struct pf_pdesc *, struct mbuf *, int pf_test_tcp(struct pf_rule **, struct pf_state **, int, struct pfi_kif *, struct mbuf *, int, void *, struct pf_pdesc *, struct pf_rule **, +#ifdef __FreeBSD__ + struct pf_ruleset **, struct inpcb *); +#else struct pf_ruleset **); +#endif int pf_test_udp(struct pf_rule **, struct pf_state **, int, struct pfi_kif *, struct mbuf *, int, void *, struct pf_pdesc *, struct pf_rule **, +#ifdef __FreeBSD__ + struct pf_ruleset **, struct inpcb *); +#else struct pf_ruleset **); +#endif int pf_test_icmp(struct pf_rule **, struct pf_state **, int, struct pfi_kif *, struct mbuf *, int, void *, struct pf_pdesc *, struct pf_rule **, @@ -229,8 +237,13 @@ void pf_route(struct mbuf **, struct pf_rule *, int, struct ifnet *, struct pf_state *); void pf_route6(struct mbuf **, struct pf_rule *, int, struct ifnet *, struct pf_state *); +#ifdef __FreeBSD__ +int pf_socket_lookup(uid_t *, gid_t *, + int, struct pf_pdesc *, struct inpcb *); +#else int pf_socket_lookup(uid_t *, gid_t *, int, struct pf_pdesc *); +#endif u_int8_t pf_get_wscale(struct mbuf *, int, u_int16_t, sa_family_t); u_int16_t pf_get_mss(struct mbuf *, int, u_int16_t, @@ -2376,7 +2389,12 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, } int +#ifdef __FreeBSD__ +pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd, + struct inpcb *inp_arg) +#else pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd) +#endif { struct pf_addr *saddr, *daddr; u_int16_t sport, dport; @@ -2389,6 +2407,17 @@ pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd) *uid = UID_MAX; *gid = GID_MAX; +#ifdef __FreeBSD__ + if (inp_arg != NULL) { + INP_LOCK_ASSERT(inp_arg); + if (inp_arg->inp_socket) { + *uid = inp_arg->inp_socket->so_cred->cr_uid; + *gid = inp_arg->inp_socket->so_cred->cr_groups[0]; + return (1); + } else + return (0); + } +#endif switch (pd->proto) { case IPPROTO_TCP: sport = pd->hdr.tcp->th_sport; @@ -2663,7 +2692,12 @@ pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr) int pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, struct pfi_kif *kif, struct mbuf *m, int off, void *h, +#ifdef __FreeBSD__ + struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, + struct inpcb *inp) +#else struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm) +#endif { struct pf_rule *nr = NULL; struct pf_addr *saddr = pd->src, *daddr = pd->dst; @@ -2742,12 +2776,20 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, else if ((r->flagset & th->th_flags) != r->flags) r = TAILQ_NEXT(r, entries); else if (r->uid.op && (lookup != -1 || (lookup = +#ifdef __FreeBSD__ + pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) && +#else pf_socket_lookup(&uid, &gid, direction, pd), 1)) && +#endif !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1], uid)) r = TAILQ_NEXT(r, entries); else if (r->gid.op && (lookup != -1 || (lookup = +#ifdef __FreeBSD__ + pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) && +#else pf_socket_lookup(&uid, &gid, direction, pd), 1)) && +#endif !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1], gid)) r = TAILQ_NEXT(r, entries); @@ -3023,7 +3065,12 @@ cleanup: int pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, struct pfi_kif *kif, struct mbuf *m, int off, void *h, +#ifdef __FreeBSD__ + struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, + struct inpcb *inp) +#else struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm) +#endif { struct pf_rule *nr = NULL; struct pf_addr *saddr = pd->src, *daddr = pd->dst; @@ -3099,12 +3146,20 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, else if (r->rule_flag & PFRULE_FRAGMENT) r = TAILQ_NEXT(r, entries); else if (r->uid.op && (lookup != -1 || (lookup = +#ifdef __FreeBSD__ + pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) && +#else pf_socket_lookup(&uid, &gid, direction, pd), 1)) && +#endif !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1], uid)) r = TAILQ_NEXT(r, entries); else if (r->gid.op && (lookup != -1 || (lookup = +#ifdef __FreeBSD__ + pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) && +#else pf_socket_lookup(&uid, &gid, direction, pd), 1)) && +#endif !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1], gid)) r = TAILQ_NEXT(r, entries); @@ -5229,7 +5284,7 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, if (oifp != ifp) { #ifdef __FreeBSD__ PF_UNLOCK(); - if (pf_test(PF_OUT, ifp, &m0) != PF_PASS) { + if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS) { PF_LOCK(); goto bad; } else if (m0 == NULL) { @@ -5519,7 +5574,7 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, if (oifp != ifp) { #ifdef __FreeBSD__ PF_UNLOCK(); - if (pf_test6(PF_OUT, ifp, &m0) != PF_PASS) { + if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS) { PF_LOCK(); goto bad; } else if (m0 == NULL) { @@ -5811,7 +5866,11 @@ pf_add_mbuf_tag(struct mbuf *m, u_int tag) #ifdef INET int +#ifdef __FreeBSD__ +pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) +#else pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) +#endif { struct pfi_kif *kif; u_short action, reason = 0, log = 0; @@ -5925,8 +5984,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_tcp(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, inp); +#else action = pf_test_tcp(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset); +#endif break; } @@ -5959,8 +6023,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_udp(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, inp); +#else action = pf_test_udp(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset); +#endif break; } @@ -6137,7 +6206,11 @@ done: #ifdef INET6 int +#ifdef __FreeBSD__ +pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) +#else pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0) +#endif { struct pfi_kif *kif; u_short action, reason = 0, log = 0; @@ -6274,8 +6347,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0) a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_tcp(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, inp); +#else action = pf_test_tcp(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset); +#endif break; } @@ -6308,8 +6386,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0) a = s->anchor.ptr; log = s->log; } else if (s == NULL) +#ifdef __FreeBSD__ + action = pf_test_udp(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, inp); +#else action = pf_test_udp(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset); +#endif break; } diff --git a/sys/contrib/pf/net/pf_ioctl.c b/sys/contrib/pf/net/pf_ioctl.c index 9e173ba..4767dee 100644 --- a/sys/contrib/pf/net/pf_ioctl.c +++ b/sys/contrib/pf/net/pf_ioctl.c @@ -182,14 +182,14 @@ static void pf_clear_srcnodes(void); * Wrapper functions for pfil(9) hooks */ static int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, - int dir); + int dir, struct inpcb *inp); static int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, - int dir); + int dir, struct inpcb *inp); #ifdef INET6 static int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, - int dir); + int dir, struct inpcb *inp); static int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, - int dir); + int dir, struct inpcb *inp); #endif static int hook_pf(void); @@ -3203,7 +3203,8 @@ shutdown_pf(void) } static int -pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) +pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, + struct inpcb *inp) { /* * XXX Wed Jul 9 22:03:16 2003 UTC @@ -3222,7 +3223,7 @@ pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) HTONS(h->ip_len); HTONS(h->ip_off); } - chk = pf_test(PF_IN, ifp, m); + chk = pf_test(PF_IN, ifp, m, inp); if (chk && *m) { m_freem(*m); *m = NULL; @@ -3237,7 +3238,8 @@ pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) } static int -pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) +pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, + struct inpcb *inp) { /* * XXX Wed Jul 9 22:03:16 2003 UTC @@ -3261,7 +3263,7 @@ pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) HTONS(h->ip_len); HTONS(h->ip_off); } - chk = pf_test(PF_OUT, ifp, m); + chk = pf_test(PF_OUT, ifp, m, inp); if (chk && *m) { m_freem(*m); *m = NULL; @@ -3277,14 +3279,15 @@ pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) #ifdef INET6 static int -pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) +pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, + struct inpcb *inp) { /* * IPv6 does not affected ip_len/ip_off byte order changes. */ int chk; - chk = pf_test6(PF_IN, ifp, m); + chk = pf_test6(PF_IN, ifp, m, inp); if (chk && *m) { m_freem(*m); *m = NULL; @@ -3293,7 +3296,8 @@ pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) } static int -pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) +pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, + struct inpcb *inp) { /* * IPv6 does not affected ip_len/ip_off byte order changes. @@ -3305,7 +3309,7 @@ pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir) in_delayed_cksum(*m); (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; } - chk = pf_test6(PF_OUT, ifp, m); + chk = pf_test6(PF_OUT, ifp, m, inp); if (chk && *m) { m_freem(*m); *m = NULL; diff --git a/sys/contrib/pf/net/pfvar.h b/sys/contrib/pf/net/pfvar.h index 11446f8..ab21c59 100644 --- a/sys/contrib/pf/net/pfvar.h +++ b/sys/contrib/pf/net/pfvar.h @@ -54,6 +54,9 @@ #include struct ip; +#ifdef __FreeBSD__ +struct inpcb; +#endif #define PF_TCPS_PROXY_SRC ((TCP_NSTATES)+0) #define PF_TCPS_PROXY_DST ((TCP_NSTATES)+1) @@ -1453,11 +1456,19 @@ void pf_rm_rule(struct pf_rulequeue *, struct pf_rule *); #ifdef INET +#ifdef __FreeBSD__ +int pf_test(int, struct ifnet *, struct mbuf **, struct inpcb *); +#else int pf_test(int, struct ifnet *, struct mbuf **); +#endif #endif /* INET */ #ifdef INET6 +#ifdef __FreeBSD__ +int pf_test6(int, struct ifnet *, struct mbuf **, struct inpcb *); +#else int pf_test6(int, struct ifnet *, struct mbuf **); +#endif void pf_poolmask(struct pf_addr *, struct pf_addr*, struct pf_addr *, struct pf_addr *, u_int8_t); void pf_addr_inc(struct pf_addr *, sa_family_t); diff --git a/sys/net/bridge.c b/sys/net/bridge.c index 1d4472e..75f7c30 100644 --- a/sys/net/bridge.c +++ b/sys/net/bridge.c @@ -1009,7 +1009,7 @@ bdg_forward(struct mbuf *m0, struct ifnet *dst) ip->ip_len = ntohs(ip->ip_len); ip->ip_off = ntohs(ip->ip_off); - if (pfil_run_hooks(&inet_pfil_hook, &m0, src, PFIL_IN) != 0) { + if (pfil_run_hooks(&inet_pfil_hook, &m0, src, PFIL_IN, NULL) != 0) { /* NB: hook should consume packet */ return NULL; } diff --git a/sys/net/pfil.c b/sys/net/pfil.c index 942607c..f5fff2a 100644 --- a/sys/net/pfil.c +++ b/sys/net/pfil.c @@ -52,7 +52,7 @@ MTX_SYSINIT(pfil_heads_lock, &pfil_global_lock, "pfil_head_list lock", MTX_DEF); static int pfil_list_add(pfil_list_t *, struct packet_filter_hook *, int); static int pfil_list_remove(pfil_list_t *, - int (*)(void *, struct mbuf **, struct ifnet *, int), void *); + int (*)(void *, struct mbuf **, struct ifnet *, int, struct inpcb *), void *); LIST_HEAD(, pfil_head) pfil_head_list = LIST_HEAD_INITIALIZER(&pfil_head_list); @@ -113,7 +113,7 @@ PFIL_WUNLOCK(struct pfil_head *ph) */ int pfil_run_hooks(struct pfil_head *ph, struct mbuf **mp, struct ifnet *ifp, - int dir) + int dir, struct inpcb *inp) { struct packet_filter_hook *pfh; struct mbuf *m = *mp; @@ -126,7 +126,7 @@ pfil_run_hooks(struct pfil_head *ph, struct mbuf **mp, struct ifnet *ifp, for (pfh = pfil_hook_get(dir, ph); pfh != NULL; pfh = TAILQ_NEXT(pfh, pfil_link)) { if (pfh->pfil_func != NULL) { - rv = (*pfh->pfil_func)(pfh->pfil_arg, &m, ifp, dir); + rv = (*pfh->pfil_func)(pfh->pfil_arg, &m, ifp, dir, inp); if (rv != 0 || m == NULL) break; } @@ -233,7 +233,7 @@ pfil_head_get(int type, u_long val) * PFIL_WAITOK OK to call malloc with M_WAITOK. */ int -pfil_add_hook(int (*func)(void *, struct mbuf **, struct ifnet *, int), +pfil_add_hook(int (*func)(void *, struct mbuf **, struct ifnet *, int, struct inpcb *), void *arg, int flags, struct pfil_head *ph) { struct packet_filter_hook *pfh1 = NULL; @@ -305,7 +305,7 @@ error: * hook list. */ int -pfil_remove_hook(int (*func)(void *, struct mbuf **, struct ifnet *, int), +pfil_remove_hook(int (*func)(void *, struct mbuf **, struct ifnet *, int, struct inpcb *), void *arg, int flags, struct pfil_head *ph) { int err = 0; @@ -361,7 +361,7 @@ pfil_list_add(pfil_list_t *list, struct packet_filter_hook *pfh1, int flags) */ static int pfil_list_remove(pfil_list_t *list, - int (*func)(void *, struct mbuf **, struct ifnet *, int), void *arg) + int (*func)(void *, struct mbuf **, struct ifnet *, int, struct inpcb *), void *arg) { struct packet_filter_hook *pfh; diff --git a/sys/net/pfil.h b/sys/net/pfil.h index 5400a72..ed5a3d0 100644 --- a/sys/net/pfil.h +++ b/sys/net/pfil.h @@ -40,6 +40,7 @@ struct mbuf; struct ifnet; +struct inpcb; /* * The packet filter hooks are designed for anything to call them to @@ -47,7 +48,7 @@ struct ifnet; */ struct packet_filter_hook { TAILQ_ENTRY(packet_filter_hook) pfil_link; - int (*pfil_func)(void *, struct mbuf **, struct ifnet *, int); + int (*pfil_func)(void *, struct mbuf **, struct ifnet *, int, struct inpcb *); void *pfil_arg; int pfil_flags; }; @@ -84,12 +85,12 @@ struct pfil_head { }; int pfil_run_hooks(struct pfil_head *, struct mbuf **, struct ifnet *, - int); + int, struct inpcb *inp); int pfil_add_hook(int (*func)(void *, struct mbuf **, - struct ifnet *, int), void *, int, struct pfil_head *); + struct ifnet *, int, struct inpcb *), void *, int, struct pfil_head *); int pfil_remove_hook(int (*func)(void *, struct mbuf **, - struct ifnet *, int), void *, int, struct pfil_head *); + struct ifnet *, int, struct inpcb *), void *, int, struct pfil_head *); int pfil_head_register(struct pfil_head *); int pfil_head_unregister(struct pfil_head *); diff --git a/sys/netinet/ip_fastfwd.c b/sys/netinet/ip_fastfwd.c index 8d78c0e..9095756 100644 --- a/sys/netinet/ip_fastfwd.c +++ b/sys/netinet/ip_fastfwd.c @@ -359,7 +359,7 @@ ip_fastforward(struct mbuf *m) if (inet_pfil_hook.ph_busy_count == -1) goto passin; - if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN) || + if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN, NULL) || m == NULL) return 1; @@ -437,7 +437,7 @@ passin: if (inet_pfil_hook.ph_busy_count == -1) goto passout; - if (pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_OUT) || m == NULL) { + if (pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_OUT, NULL) || m == NULL) { goto consumed; } diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index 0229a22..ac903f5 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -425,6 +425,7 @@ struct ip_fw_args { struct ipfw_flow_id f_id; /* grabbed from IP header */ u_int32_t retval; + struct inpcb *inp; }; /* @@ -435,8 +436,8 @@ struct ip_fw_args { struct sockopt; struct dn_flow_set; -int ipfw_check_in(void *, struct mbuf **, struct ifnet *, int); -int ipfw_check_out(void *, struct mbuf **, struct ifnet *, int); +int ipfw_check_in(void *, struct mbuf **, struct ifnet *, int, struct inpcb *inp); +int ipfw_check_out(void *, struct mbuf **, struct ifnet *, int, struct inpcb *inp); int ipfw_chk(struct ip_fw_args *); diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c index a33b361..a8bcede 100644 --- a/sys/netinet/ip_fw2.c +++ b/sys/netinet/ip_fw2.c @@ -1532,21 +1532,48 @@ dump_table(ipfw_table *tbl) return (0); } +static void +fill_ugid_cache(struct inpcb *inp, struct ip_fw_ugid *ugp) +{ + struct ucred *cr; + + if (inp->inp_socket != NULL) { + cr = inp->inp_socket->so_cred; + ugp->fw_prid = jailed(cr) ? + cr->cr_prison->pr_id : -1; + ugp->fw_uid = cr->cr_uid; + ugp->fw_ngroups = cr->cr_ngroups; + bcopy(cr->cr_groups, ugp->fw_groups, + sizeof(ugp->fw_groups)); + } +} + static int check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif, struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip, u_int16_t src_port, - struct ip_fw_ugid *ugp, int *lookup) + struct ip_fw_ugid *ugp, int *lookup, struct inpcb *inp) { struct inpcbinfo *pi; int wildcard; struct inpcb *pcb; int match; - struct ucred *cr; gid_t *gp; /* + * Check to see if the UDP or TCP stack supplied us with + * the PCB. If so, rather then holding a lock and looking + * up the PCB, we can use the one that was supplied. + */ + if (inp && *lookup == 0) { + INP_LOCK_ASSERT(inp); + if (inp->inp_socket != NULL) { + fill_ugid_cache(inp, ugp); + *lookup = 1; + } + } + /* * If we have already been here and the packet has no * PCB entry associated with it, then we can safely * assume that this is a no match. @@ -1563,7 +1590,7 @@ check_uidgid(ipfw_insn_u32 *insn, return 0; match = 0; if (*lookup == 0) { - INP_INFO_RLOCK(pi); /* XXX LOR with IPFW */ + INP_INFO_RLOCK(pi); pcb = (oif) ? in_pcblookup_hash(pi, dst_ip, htons(dst_port), @@ -1576,13 +1603,7 @@ check_uidgid(ipfw_insn_u32 *insn, if (pcb != NULL) { INP_LOCK(pcb); if (pcb->inp_socket != NULL) { - cr = pcb->inp_socket->so_cred; - ugp->fw_prid = jailed(cr) ? - cr->cr_prison->pr_id : -1; - ugp->fw_uid = cr->cr_uid; - ugp->fw_ngroups = cr->cr_ngroups; - bcopy(cr->cr_groups, ugp->fw_groups, - sizeof(ugp->fw_groups)); + fill_ugid_cache(pcb, ugp); *lookup = 1; } INP_UNLOCK(pcb); @@ -1938,7 +1959,7 @@ check_body: proto, oif, dst_ip, dst_port, src_ip, src_port, &fw_ugid_cache, - &ugid_lookup); + &ugid_lookup, args->inp); break; case O_RECV: diff --git a/sys/netinet/ip_fw_pfil.c b/sys/netinet/ip_fw_pfil.c index 69e0188..3b08f69 100644 --- a/sys/netinet/ip_fw_pfil.c +++ b/sys/netinet/ip_fw_pfil.c @@ -73,7 +73,8 @@ ip_dn_ruledel_t *ip_dn_ruledel_ptr = NULL; static int ipfw_divert(struct mbuf **, int, int); int -ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir) +ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir, + struct inpcb *inp) { struct ip_fw_args args; struct m_tag *dn_tag; @@ -102,6 +103,7 @@ ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir) again: args.m = *m0; + args.inp = inp; ipfw = ipfw_chk(&args); *m0 = args.m; @@ -156,7 +158,8 @@ pass: } int -ipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir) +ipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir, + struct inpcb *inp) { struct ip_fw_args args; struct m_tag *dn_tag; @@ -186,6 +189,7 @@ ipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir) again: args.m = *m0; args.oif = ifp; + args.inp = inp; ipfw = ipfw_chk(&args); *m0 = args.m; diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 223866f..37fbfd6 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -437,7 +437,7 @@ tooshort: odst = ip->ip_dst; if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif, - PFIL_IN) != 0) + PFIL_IN, NULL) != 0) return; if (m == NULL) /* consumed by filter */ return; diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index d50beef..dfc939b 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -662,7 +662,7 @@ spd_done: /* Run through list of hooks for output packets. */ odst.s_addr = ip->ip_dst.s_addr; - error = pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_OUT); + error = pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_OUT, inp); if (error != 0 || m == NULL) goto done; diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c index 94206ab..c85e5e5 100644 --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -580,7 +580,7 @@ ip6_forward(m, srcrt) goto pass; /* Run through list of hooks for output packets. */ - error = pfil_run_hooks(&inet6_pfil_hook, &m, rt->rt_ifp, PFIL_OUT); + error = pfil_run_hooks(&inet6_pfil_hook, &m, rt->rt_ifp, PFIL_OUT, NULL); if (error != 0) goto senderr; if (m == NULL) diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index e5bb0c3..dc3b318 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -424,7 +424,7 @@ ip6_input(m) if (inet6_pfil_hook.ph_busy_count == -1) goto passin; - if (pfil_run_hooks(&inet6_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN)) + if (pfil_run_hooks(&inet6_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN, NULL)) return; if (m == NULL) /* consumed by filter */ return; diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index bdee8fe..03ef3bc 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -938,7 +938,7 @@ skip_ipsec2:; goto passout; /* Run through list of hooks for output packets. */ - error = pfil_run_hooks(&inet6_pfil_hook, &m, ifp, PFIL_OUT); + error = pfil_run_hooks(&inet6_pfil_hook, &m, ifp, PFIL_OUT, inp); if (error != 0 || m == NULL) goto done; ip6 = mtod(m, struct ip6_hdr *); diff --git a/sys/sys/param.h b/sys/sys/param.h index 8b062df..b0d5864 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -57,7 +57,7 @@ * is created, otherwise 1. */ #undef __FreeBSD_version -#define __FreeBSD_version 600003 /* Master, propagated to newvers */ +#define __FreeBSD_version 600004 /* Master, propagated to newvers */ #ifndef LOCORE #include -- cgit v1.1