On Thu, Nov 22, 2012 at 16:05 +0100, Mike Belopuhov wrote:
> re pf bug on bugs@:
> 
> apparently the crash is caused by the stack corruption that happens
> in pf_map_addr as it expects to get an array of struct pf_src_node
> pointers, not just one pointer.  the bug was introduced about four
> years ago, but somehow (stack layout?) went unnoticed.
> 
> the proper fix is to pass an empty array of size PF_SN_MAX as done
> in other places.
> 
> i've verified that this fixes the issue for me and arjan is going
> to verify as well.
> 
> while here, i think it makes sense to initialize src_nodes list
> head and while it's essentially a noop, if we convert it to
> something else where it matters, proper initialization might get
> lost.
> 

ok, two more places were found by florian@ in pf_route{,6}.
unfortunately i can't reproduce the crash there even by
assigning sn to something like 0xcf000000 or 0xdeadbeef
(on i386).  as far as i can see it should be triggered by
the route-to with "no state" (as state pointer should be
NULL).

but in any case, we should treat it the same way.

OK?

diff --git sys/net/pf.c sys/net/pf.c
index 5177466..66837ca 100644
--- sys/net/pf.c
+++ sys/net/pf.c
@@ -3204,15 +3204,16 @@ void
 pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
 {
        struct pf_rule *r = s->rule.ptr;
-       struct pf_src_node *sn = NULL;
+       struct pf_src_node *sns[PF_SN_MAX];
 
        s->rt_kif = NULL;
        if (!r->rt)
                return;
+       bzero(sns, sizeof(sns));
        switch (s->key[PF_SK_WIRE]->af) {
 #ifdef INET
        case AF_INET:
-               pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL, &sn,
+               pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL, sns,
                    &r->route, PF_SN_ROUTE);
                s->rt_kif = r->route.kif;
                s->natrule.ptr = r;
@@ -3220,7 +3221,7 @@ pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
 #endif /* INET */
 #ifdef INET6
        case AF_INET6:
-               pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL, &sn,
+               pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL, sns,
                    &r->route, PF_SN_ROUTE);
                s->rt_kif = r->route.kif;
                s->natrule.ptr = r;
@@ -3710,6 +3711,8 @@ pf_create_state(struct pf_pdesc *pd, struct pf_rule *r, 
struct pf_rule *a,
 #endif
        s->set_prio[0] = act->set_prio[0];
        s->set_prio[1] = act->set_prio[1];
+       SLIST_INIT(&s->src_nodes);
+
        switch (pd->proto) {
        case IPPROTO_TCP:
                s->src.seqlo = ntohl(th->th_seq);
@@ -5844,7 +5847,7 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, 
struct ifnet *oifp,
        struct ip               *ip;
        struct ifnet            *ifp = NULL;
        struct pf_addr           naddr;
-       struct pf_src_node      *sn = NULL;
+       struct pf_src_node      *sns[PF_SN_MAX];
        int                      error = 0;
 #ifdef IPSEC
        struct m_tag            *mtag;
@@ -5901,9 +5904,10 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, 
struct ifnet *oifp,
                m0->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
        } else {
                if (s == NULL) {
+                       bzero(sns, sizeof(sns));
                        if (pf_map_addr(AF_INET, r,
                            (struct pf_addr *)&ip->ip_src,
-                           &naddr, NULL, &sn, &r->route, PF_SN_ROUTE)) {
+                           &naddr, NULL, sns, &r->route, PF_SN_ROUTE)) {
                                DPFPRINTF(LOG_ERR,
                                    "pf_route: pf_map_addr() failed.");
                                goto bad;
@@ -6027,7 +6031,7 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, 
struct ifnet *oifp,
        struct ip6_hdr          *ip6;
        struct ifnet            *ifp = NULL;
        struct pf_addr           naddr;
-       struct pf_src_node      *sn = NULL;
+       struct pf_src_node      *sns[PF_SN_MAX];
 
        if (m == NULL || *m == NULL || r == NULL ||
            (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
@@ -6069,8 +6073,9 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, 
struct ifnet *oifp,
        }
 
        if (s == NULL) {
+               bzero(sns, sizeof(sns));
                if (pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
-                   &naddr, NULL, &sn, &r->route, PF_SN_ROUTE)) {
+                   &naddr, NULL, sns, &r->route, PF_SN_ROUTE)) {
                        DPFPRINTF(LOG_ERR,
                            "pf_route6: pf_map_addr() failed.");
                        goto bad;

Reply via email to