diff options
author | mlaier <mlaier@FreeBSD.org> | 2004-09-29 04:54:33 +0000 |
---|---|---|
committer | mlaier <mlaier@FreeBSD.org> | 2004-09-29 04:54:33 +0000 |
commit | b65eae4c193f1c3c9580e5ac2bad5585034743f2 (patch) | |
tree | b760834c7691b17430788d5a6041455045da8ac1 /sys/contrib | |
parent | e455dd69f84961133d47cca1588021dfafac9e28 (diff) | |
download | FreeBSD-src-b65eae4c193f1c3c9580e5ac2bad5585034743f2.zip FreeBSD-src-b65eae4c193f1c3c9580e5ac2bad5585034743f2.tar.gz |
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)
Diffstat (limited to 'sys/contrib')
-rw-r--r-- | sys/contrib/ipfilter/netinet/ip_fil.c | 27 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf.c | 87 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf_ioctl.c | 28 | ||||
-rw-r--r-- | sys/contrib/pf/net/pfvar.h | 11 |
4 files changed, 137 insertions, 16 deletions
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 <netinet/ip6.h> + +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 <netinet/tcp_fsm.h> 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); |