summaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorAlexander Bluhm <bluhm@cvs.openbsd.org>2022-01-24 22:49:49 +0000
committerAlexander Bluhm <bluhm@cvs.openbsd.org>2022-01-24 22:49:49 +0000
commit37f5b35710e48314d1b0f73843edddd08030977b (patch)
tree3930b72b6f0dabb0cf92d9334f43e2cd8d869605 /sys/net
parent814e839e145a1ebd5455cc1dc084663163563233 (diff)
An af-to pf rule must have an address family naf to use after
translation. Make stricter sanity checks in pf ioctl to avoid later crashes during packet processing. Reported-by: syzbot+0ef9190e7d0195496d0d@syzkaller.appspotmail.com OK sashan@
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/pf_ioctl.c58
1 files changed, 32 insertions, 26 deletions
diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c
index 3766d749491..fa2a5dcdb64 100644
--- a/sys/net/pf_ioctl.c
+++ b/sys/net/pf_ioctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_ioctl.c,v 1.370 2022/01/11 09:00:17 sashan Exp $ */
+/* $OpenBSD: pf_ioctl.c,v 1.371 2022/01/24 22:49:48 bluhm Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -109,6 +109,7 @@ void pf_trans_set_commit(void);
void pf_pool_copyin(struct pf_pool *, struct pf_pool *);
int pf_validate_range(u_int8_t, u_int16_t[2]);
int pf_rule_copyin(struct pf_rule *, struct pf_rule *);
+int pf_rule_checkaf(struct pf_rule *);
u_int16_t pf_qname2qid(char *, int);
void pf_qid2qname(u_int16_t, char *);
void pf_qid_unref(u_int16_t);
@@ -1347,22 +1348,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
rule = NULL;
break;
}
- switch (rule->af) {
- case 0:
- break;
- case AF_INET:
- break;
-#ifdef INET6
- case AF_INET6:
- break;
-#endif /* INET6 */
- default:
+ if ((error = pf_rule_checkaf(rule))) {
pf_rule_free(rule);
rule = NULL;
- error = EAFNOSUPPORT;
goto fail;
}
-
if (rule->src.addr.type == PF_ADDR_NONE ||
rule->dst.addr.type == PF_ADDR_NONE) {
error = EINVAL;
@@ -1601,23 +1591,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
newrule = NULL;
break;
}
-
- switch (newrule->af) {
- case 0:
- break;
- case AF_INET:
- break;
-#ifdef INET6
- case AF_INET6:
- break;
-#endif /* INET6 */
- default:
- error = EAFNOSUPPORT;
+ if ((error = pf_rule_checkaf(newrule))) {
pf_rule_free(newrule);
newrule = NULL;
goto fail;
}
-
if (newrule->rt && !newrule->direction) {
pf_rule_free(newrule);
error = EINVAL;
@@ -3219,6 +3197,34 @@ pf_rule_copyin(struct pf_rule *from, struct pf_rule *to)
}
int
+pf_rule_checkaf(struct pf_rule *r)
+{
+ switch (r->af) {
+ case 0:
+ if (r->rule_flag & PFRULE_AFTO)
+ return (EPFNOSUPPORT);
+ break;
+ case AF_INET:
+ if ((r->rule_flag & PFRULE_AFTO) && r->naf != AF_INET6)
+ return (EPFNOSUPPORT);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if ((r->rule_flag & PFRULE_AFTO) && r->naf != AF_INET)
+ return (EPFNOSUPPORT);
+ break;
+#endif /* INET6 */
+ default:
+ return (EPFNOSUPPORT);
+ }
+
+ if ((r->rule_flag & PFRULE_AFTO) == 0 && r->naf != 0)
+ return (EPFNOSUPPORT);
+
+ return (0);
+}
+
+int
pf_sysctl(void *oldp, size_t *oldlenp, void *newp, size_t newlen)
{
struct pf_status pfs;