Author: gordon
Date: Tue May 14 23:12:22 2019
New Revision: 347593
URL: https://svnweb.freebsd.org/changeset/base/347593

Log:
  Fix ICMP/ICMP6 packet filter bypass in pf.
  
  Approved by:  so
  Security:     FreeBSD-SA-19:06.pf
  Security:     CVE-2019-5598

Modified:
  releng/11.2/sys/netpfil/pf/pf.c
  releng/12.0/sys/netpfil/pf/pf.c

Modified: releng/11.2/sys/netpfil/pf/pf.c
==============================================================================
--- releng/11.2/sys/netpfil/pf/pf.c     Tue May 14 23:12:14 2019        
(r347592)
+++ releng/11.2/sys/netpfil/pf/pf.c     Tue May 14 23:12:22 2019        
(r347593)
@@ -4550,7 +4550,7 @@ pf_test_state_icmp(struct pf_state **state, int direct
 {
        struct pf_addr  *saddr = pd->src, *daddr = pd->dst;
        u_int16_t        icmpid = 0, *icmpsum;
-       u_int8_t         icmptype;
+       u_int8_t         icmptype, icmpcode;
        int              state_icmp = 0;
        struct pf_state_key_cmp key;
 
@@ -4559,6 +4559,7 @@ pf_test_state_icmp(struct pf_state **state, int direct
 #ifdef INET
        case IPPROTO_ICMP:
                icmptype = pd->hdr.icmp->icmp_type;
+               icmpcode = pd->hdr.icmp->icmp_code;
                icmpid = pd->hdr.icmp->icmp_id;
                icmpsum = &pd->hdr.icmp->icmp_cksum;
 
@@ -4573,6 +4574,7 @@ pf_test_state_icmp(struct pf_state **state, int direct
 #ifdef INET6
        case IPPROTO_ICMPV6:
                icmptype = pd->hdr.icmp6->icmp6_type;
+               icmpcode = pd->hdr.icmp6->icmp6_code;
                icmpid = pd->hdr.icmp6->icmp6_id;
                icmpsum = &pd->hdr.icmp6->icmp6_cksum;
 
@@ -4771,6 +4773,23 @@ pf_test_state_icmp(struct pf_state **state, int direct
 #endif /* INET6 */
                }
 
+               if (PF_ANEQ(pd->dst, pd2.src, pd->af)) {
+                       if (V_pf_status.debug >= PF_DEBUG_MISC) {
+                               printf("pf: BAD ICMP %d:%d outer dst: ",
+                                   icmptype, icmpcode);
+                               pf_print_host(pd->src, 0, pd->af);
+                               printf(" -> ");
+                               pf_print_host(pd->dst, 0, pd->af);
+                               printf(" inner src: ");
+                               pf_print_host(pd2.src, 0, pd2.af);
+                               printf(" -> ");
+                               pf_print_host(pd2.dst, 0, pd2.af);
+                               printf("\n");
+                       }
+                       REASON_SET(reason, PFRES_BADSTATE);
+                       return (PF_DROP);
+               }
+
                switch (pd2.proto) {
                case IPPROTO_TCP: {
                        struct tcphdr            th;
@@ -4827,7 +4846,7 @@ pf_test_state_icmp(struct pf_state **state, int direct
                            !SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)))) 
{
                                if (V_pf_status.debug >= PF_DEBUG_MISC) {
                                        printf("pf: BAD ICMP %d:%d ",
-                                           icmptype, pd->hdr.icmp->icmp_code);
+                                           icmptype, icmpcode);
                                        pf_print_host(pd->src, 0, pd->af);
                                        printf(" -> ");
                                        pf_print_host(pd->dst, 0, pd->af);
@@ -4840,7 +4859,7 @@ pf_test_state_icmp(struct pf_state **state, int direct
                        } else {
                                if (V_pf_status.debug >= PF_DEBUG_MISC) {
                                        printf("pf: OK ICMP %d:%d ",
-                                           icmptype, pd->hdr.icmp->icmp_code);
+                                           icmptype, icmpcode);
                                        pf_print_host(pd->src, 0, pd->af);
                                        printf(" -> ");
                                        pf_print_host(pd->dst, 0, pd->af);

Modified: releng/12.0/sys/netpfil/pf/pf.c
==============================================================================
--- releng/12.0/sys/netpfil/pf/pf.c     Tue May 14 23:12:14 2019        
(r347592)
+++ releng/12.0/sys/netpfil/pf/pf.c     Tue May 14 23:12:22 2019        
(r347593)
@@ -4588,7 +4588,7 @@ pf_test_state_icmp(struct pf_state **state, int direct
 {
        struct pf_addr  *saddr = pd->src, *daddr = pd->dst;
        u_int16_t        icmpid = 0, *icmpsum;
-       u_int8_t         icmptype;
+       u_int8_t         icmptype, icmpcode;
        int              state_icmp = 0;
        struct pf_state_key_cmp key;
 
@@ -4597,6 +4597,7 @@ pf_test_state_icmp(struct pf_state **state, int direct
 #ifdef INET
        case IPPROTO_ICMP:
                icmptype = pd->hdr.icmp->icmp_type;
+               icmpcode = pd->hdr.icmp->icmp_code;
                icmpid = pd->hdr.icmp->icmp_id;
                icmpsum = &pd->hdr.icmp->icmp_cksum;
 
@@ -4611,6 +4612,7 @@ pf_test_state_icmp(struct pf_state **state, int direct
 #ifdef INET6
        case IPPROTO_ICMPV6:
                icmptype = pd->hdr.icmp6->icmp6_type;
+               icmpcode = pd->hdr.icmp6->icmp6_code;
                icmpid = pd->hdr.icmp6->icmp6_id;
                icmpsum = &pd->hdr.icmp6->icmp6_cksum;
 
@@ -4809,6 +4811,23 @@ pf_test_state_icmp(struct pf_state **state, int direct
 #endif /* INET6 */
                }
 
+               if (PF_ANEQ(pd->dst, pd2.src, pd->af)) {
+                       if (V_pf_status.debug >= PF_DEBUG_MISC) {
+                               printf("pf: BAD ICMP %d:%d outer dst: ",
+                                   icmptype, icmpcode);
+                               pf_print_host(pd->src, 0, pd->af);
+                               printf(" -> ");
+                               pf_print_host(pd->dst, 0, pd->af);
+                               printf(" inner src: ");
+                               pf_print_host(pd2.src, 0, pd2.af);
+                               printf(" -> ");
+                               pf_print_host(pd2.dst, 0, pd2.af);
+                               printf("\n");
+                       }
+                       REASON_SET(reason, PFRES_BADSTATE);
+                       return (PF_DROP);
+               }
+
                switch (pd2.proto) {
                case IPPROTO_TCP: {
                        struct tcphdr            th;
@@ -4865,7 +4884,7 @@ pf_test_state_icmp(struct pf_state **state, int direct
                            !SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)))) 
{
                                if (V_pf_status.debug >= PF_DEBUG_MISC) {
                                        printf("pf: BAD ICMP %d:%d ",
-                                           icmptype, pd->hdr.icmp->icmp_code);
+                                           icmptype, icmpcode);
                                        pf_print_host(pd->src, 0, pd->af);
                                        printf(" -> ");
                                        pf_print_host(pd->dst, 0, pd->af);
@@ -4878,7 +4897,7 @@ pf_test_state_icmp(struct pf_state **state, int direct
                        } else {
                                if (V_pf_status.debug >= PF_DEBUG_MISC) {
                                        printf("pf: OK ICMP %d:%d ",
-                                           icmptype, pd->hdr.icmp->icmp_code);
+                                           icmptype, icmpcode);
                                        pf_print_host(pd->src, 0, pd->af);
                                        printf(" -> ");
                                        pf_print_host(pd->dst, 0, pd->af);
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to