pfctl errata Nov 17

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

pfctl errata Nov 17

Stuart Henderson-6
Patches are now available for 5.5 and 5.6 to fix an issue with pfctl
and certain rules combining IPv4 and IPv6 addresses (in that order) with
a dynamic interface address using the "(interface)" format. The patch
for 5.6 follows.

This problem can be worked around by reversing the order of addresses
(listing IPv6 first, then IPv4).


untrusted comment: signature from openbsd 5.6 base private key
RWR0EANmo9nqhlxzEl3gBOqqoVrDRpZgSYhTqFK031hbFJ9tX84ZYqS72CcubFWty11KDc7YCvei+VSQu1PdYPo/MU/nReUdBQU=

OpenBSD 5.6 errata 7, Nov 17, 2014:  A PF rule using an IPv4 address
followed by an IPv6 address and then a dynamic address, e.g. "pass
from {192.0.2.1 2001:db8::1} to (pppoe0)", will have an incorrect /32
mask applied to the dynamic address.

Apply patch using:

    signify -Vep /etc/signify/openbsd-56-base.pub -x 007.pfctl.patch.sig \
        -m - | (cd /usr/src && patch -p0)

Then build and install pfctl:
    cd /usr/src/sbin/pfctl
    make obj
    make
    make install

Index: sbin/pfctl/parse.y
===================================================================
RCS file: /cvs/src/sbin/pfctl/parse.y,v
retrieving revision 1.636
retrieving revision 1.636.4.1
diff -u -p -r1.636 -r1.636.4.1
--- sbin/pfctl/parse.y 2 Jul 2014 13:03:41 -0000 1.636
+++ sbin/pfctl/parse.y 29 Oct 2014 15:29:33 -0000 1.636.4.1
@@ -4516,7 +4516,7 @@ expand_rule(struct pf_rule *r, int keepr
  char tagname[PF_TAG_NAME_SIZE];
  char match_tagname[PF_TAG_NAME_SIZE];
  u_int8_t flags, flagset, keep_state;
- struct node_host *srch, *dsth;
+ struct node_host *srch, *dsth, *osrch, *odsth;
  struct redirspec binat;
  struct pf_rule rb;
  int dir = r->direction;
@@ -4607,6 +4607,18 @@ expand_rule(struct pf_rule *r, int keepr
     r->af, src_host, src_port, dst_host, dst_port,
     proto->proto);
 
+ osrch = odsth = NULL;
+ if (src_host->addr.type == PF_ADDR_DYNIFTL) {
+ osrch = src_host;
+ if ((src_host = gen_dynnode(src_host, r->af)) == NULL)
+ err(1, "expand_rule: calloc");
+ }
+ if (dst_host->addr.type == PF_ADDR_DYNIFTL) {
+ odsth = dst_host;
+ if ((dst_host = gen_dynnode(dst_host, r->af)) == NULL)
+ err(1, "expand_rule: calloc");
+ }
+
  error += check_netmask(src_host, r->af);
  error += check_netmask(dst_host, r->af);
 
@@ -4757,6 +4769,14 @@ expand_rule(struct pf_rule *r, int keepr
     uid, gid, rcv, icmp_type, anchor_call);
  }
 
+ if (osrch && src_host->addr.type == PF_ADDR_DYNIFTL) {
+ free(src_host);
+ src_host = osrch;
+ }
+ if (odsth && dst_host->addr.type == PF_ADDR_DYNIFTL) {
+ free(dst_host);
+ dst_host = odsth;
+ }
  ))))))))));
 
  if (!keeprule) {
Index: sbin/pfctl/pfctl_parser.c
===================================================================
RCS file: /cvs/src/sbin/pfctl/pfctl_parser.c,v
retrieving revision 1.298
retrieving revision 1.298.6.1
diff -u -p -r1.298 -r1.298.6.1
--- sbin/pfctl/pfctl_parser.c 20 Jan 2014 02:59:13 -0000 1.298
+++ sbin/pfctl/pfctl_parser.c 29 Oct 2014 15:29:34 -0000 1.298.6.1
@@ -1244,16 +1244,12 @@ int
 check_netmask(struct node_host *h, sa_family_t af)
 {
  struct node_host *n = NULL;
- struct pf_addr *m;
+ struct pf_addr *m;
 
  for (n = h; n != NULL; n = n->next) {
  if (h->addr.type == PF_ADDR_TABLE)
  continue;
  m = &h->addr.v.a.mask;
- /* fix up netmask for dynaddr */
- if (af == AF_INET && h->addr.type == PF_ADDR_DYNIFTL &&
-    unmask(m, AF_INET6) > 32)
- set_ipmask(n, 32);
  /* netmasks > 32 bit are invalid on v4 */
  if (af == AF_INET &&
     (m->addr32[1] || m->addr32[2] || m->addr32[3])) {
@@ -1263,6 +1259,30 @@ check_netmask(struct node_host *h, sa_fa
  }
  }
  return (0);
+}
+
+struct node_host *
+gen_dynnode(struct node_host *h, sa_family_t af)
+{
+ struct node_host *n;
+ struct pf_addr *m;
+
+ if (h->addr.type != PF_ADDR_DYNIFTL)
+ return (NULL);
+
+ if ((n = calloc(1, sizeof(*n))) == NULL)
+ return (NULL);
+ bcopy(h, n, sizeof(*n));
+ n->ifname = NULL;
+ n->next = NULL;
+ n->tail = NULL;
+
+ /* fix up netmask */
+ m = &n->addr.v.a.mask;
+ if (af == AF_INET && unmask(m, AF_INET6) > 32)
+ set_ipmask(n, 32);
+
+ return (n);
 }
 
 /* interface lookup routines */
Index: sbin/pfctl/pfctl_parser.h
===================================================================
RCS file: /cvs/src/sbin/pfctl/pfctl_parser.h,v
retrieving revision 1.102
retrieving revision 1.102.4.1
diff -u -p -r1.102 -r1.102.4.1
--- sbin/pfctl/pfctl_parser.h 19 Apr 2014 14:22:32 -0000 1.102
+++ sbin/pfctl/pfctl_parser.h 29 Oct 2014 15:29:34 -0000 1.102.4.1
@@ -265,6 +265,7 @@ extern const struct pf_timeout pf_timeou
 void set_ipmask(struct node_host *, u_int8_t);
 int check_netmask(struct node_host *, sa_family_t);
 int unmask(struct pf_addr *, sa_family_t);
+struct node_host *gen_dynnode(struct node_host *, sa_family_t);
 void ifa_load(void);
 unsigned int ifa_nametoindex(const char *);
 char *ifa_indextoname(unsigned int, char *);