summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/man9/mbuf_tags.914
-rw-r--r--sys/net/pf.c46
-rw-r--r--sys/netinet/in_pcb.c47
-rw-r--r--sys/netinet/in_pcb.h6
-rw-r--r--sys/netinet/tcp_input.c8
-rw-r--r--sys/netinet/tcp_usrreq.c6
-rw-r--r--sys/netinet/udp_usrreq.c10
-rw-r--r--sys/sys/mbuf.h3
8 files changed, 108 insertions, 32 deletions
diff --git a/share/man/man9/mbuf_tags.9 b/share/man/man9/mbuf_tags.9
index 9a598ec858d..953e835200d 100644
--- a/share/man/man9/mbuf_tags.9
+++ b/share/man/man9/mbuf_tags.9
@@ -1,4 +1,4 @@
-.\" $OpenBSD: mbuf_tags.9,v 1.17 2003/06/06 20:56:32 jmc Exp $
+.\" $OpenBSD: mbuf_tags.9,v 1.18 2003/12/08 07:07:35 mcbride Exp $
.\"
.\" The author of this man page is Angelos D. Keromytis (angelos@cis.upenn.edu)
.\"
@@ -193,6 +193,18 @@ The tag contains the ID of the queue this packet should go to.
Used by
.Xr pf 4
to tag packets and filtering on those later on.
+.It PACKET_TAG_PF_TRANSLATE_LOCALHOST
+Used by
+.Xr pf 4
+to mark TCP and UDP packets redirected to loopback addresses.
+The functions tcp_input() and udp_input() reverse the order of
+lookups in in_pcblookup_listen(), when this tag is present, so
+unspecific listeners are matched before specific ones.
+This prevents external connections from appearing local to daemons
+such as
+.Xr portmap 8
+listening on both unspecific and specific loopback sockets in order to
+grant higher privileges to local users.
.El
.Pp
.Fn m_tag_free
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 95765175c08..57bc51437dc 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.404 2003/11/28 01:06:59 mcbride Exp $ */
+/* $OpenBSD: pf.c,v 1.405 2003/12/08 07:07:35 mcbride Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -204,6 +204,7 @@ int pf_check_proto_cksum(struct mbuf *, int, int,
u_int8_t, sa_family_t);
int pf_addr_wrap_neq(struct pf_addr_wrap *,
struct pf_addr_wrap *);
+static int pf_add_mbuf_tag(struct mbuf *, u_int);
struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] =
@@ -2001,7 +2002,7 @@ pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd)
case AF_INET:
inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport);
if (inp == NULL) {
- inp = in_pcblookup_listen(tb, daddr->v4, dport);
+ inp = in_pcblookup_listen(tb, daddr->v4, dport, 0);
if (inp == NULL)
return (0);
}
@@ -2011,7 +2012,7 @@ pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd)
inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6,
dport);
if (inp == NULL) {
- inp = in6_pcblookup_listen(tb, &daddr->v6, dport);
+ inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0);
if (inp == NULL)
return (0);
}
@@ -4829,6 +4830,20 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t a
return (0);
}
+static int
+pf_add_mbuf_tag(struct mbuf *m, u_int tag)
+{
+ struct m_tag *mtag;
+
+ if (m_tag_find(m, tag, NULL) != NULL)
+ return (0);
+ mtag = m_tag_get(tag, 0, M_NOWAIT);
+ if (mtag == NULL)
+ return (1);
+ m_tag_prepend(m, mtag);
+ return (0);
+}
+
#ifdef INET
int
pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
@@ -5016,6 +5031,21 @@ done:
}
#endif
+ /*
+ * connections redirected to loopback should not match sockets
+ * bound specifically to loopback due to security implications,
+ * see tcp_input() and in_pcblookup_listen().
+ */
+ if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
+ pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
+ (s->nat_rule.ptr->action == PF_RDR ||
+ s->nat_rule.ptr->action == PF_BINAT) &&
+ (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET &&
+ pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_MEMORY);
+ }
+
if (log)
PFLOG_PACKET(ifp, h, m, AF_INET, dir, reason, r, a, ruleset);
@@ -5271,6 +5301,16 @@ done:
}
#endif
+ if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
+ pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
+ (s->nat_rule.ptr->action == PF_RDR ||
+ s->nat_rule.ptr->action == PF_BINAT) &&
+ IN6_IS_ADDR_LOOPBACK(&pd.dst->v6) &&
+ pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_MEMORY);
+ }
+
if (log)
PFLOG_PACKET(ifp, h, m, AF_INET6, dir, reason, r, a, ruleset);
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index 5d8e28ff09c..82c2c71ef96 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_pcb.c,v 1.69 2003/11/04 21:43:16 markus Exp $ */
+/* $OpenBSD: in_pcb.c,v 1.70 2003/12/08 07:07:36 mcbride Exp $ */
/* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */
/*
@@ -1055,35 +1055,45 @@ in6_pcbhashlookup(table, faddr, fport_arg, laddr, lport_arg)
* *.* <-> *.lport
*/
struct inpcb *
-in_pcblookup_listen(table, laddr, lport_arg)
+in_pcblookup_listen(table, laddr, lport_arg, reverse)
struct inpcbtable *table;
struct in_addr laddr;
u_int lport_arg;
+ int reverse;
{
struct inpcbhead *head;
+ struct in_addr *key1, *key2;
register struct inpcb *inp;
u_int16_t lport = lport_arg;
- head = INPCBHASH(table, &zeroin_addr, 0, &laddr, lport);
+ if (reverse) {
+ key1 = &zeroin_addr;
+ key2 = &laddr;
+ } else {
+ key1 = &laddr;
+ key2 = &zeroin_addr;
+ }
+
+ head = INPCBHASH(table, &zeroin_addr, 0, key1, lport);
LIST_FOREACH(inp, head, inp_hash) {
#ifdef INET6
if (inp->inp_flags & INP_IPV6)
continue; /*XXX*/
#endif
if (inp->inp_lport == lport && inp->inp_fport == 0 &&
- inp->inp_laddr.s_addr == laddr.s_addr &&
+ inp->inp_laddr.s_addr == key1->s_addr &&
inp->inp_faddr.s_addr == INADDR_ANY)
break;
}
- if (inp == NULL && laddr.s_addr != INADDR_ANY) {
- head = INPCBHASH(table, &zeroin_addr, 0, &zeroin_addr, lport);
+ if (inp == NULL && key1->s_addr != key2->s_addr) {
+ head = INPCBHASH(table, &zeroin_addr, 0, key2, lport);
LIST_FOREACH(inp, head, inp_hash) {
#ifdef INET6
if (inp->inp_flags & INP_IPV6)
continue; /*XXX*/
#endif
if (inp->inp_lport == lport && inp->inp_fport == 0 &&
- inp->inp_laddr.s_addr == INADDR_ANY &&
+ inp->inp_laddr.s_addr == key2->s_addr &&
inp->inp_faddr.s_addr == INADDR_ANY)
break;
}
@@ -1108,32 +1118,41 @@ in_pcblookup_listen(table, laddr, lport_arg)
#ifdef INET6
struct inpcb *
-in6_pcblookup_listen(table, laddr, lport_arg)
+in6_pcblookup_listen(table, laddr, lport_arg, reverse)
struct inpcbtable *table;
struct in6_addr *laddr;
u_int lport_arg;
+ int reverse;
{
struct inpcbhead *head;
+ struct in6_addr *key1, *key2;
register struct inpcb *inp;
u_int16_t lport = lport_arg;
- head = IN6PCBHASH(table, &zeroin6_addr, 0, laddr, lport);
+ if (reverse) {
+ key1 = &zeroin6_addr;
+ key2 = laddr;
+ } else {
+ key1 = laddr;
+ key2 = &zeroin6_addr;
+ }
+
+ head = IN6PCBHASH(table, &zeroin6_addr, 0, key1, lport);
LIST_FOREACH(inp, head, inp_hash) {
if (!(inp->inp_flags & INP_IPV6))
continue;
if (inp->inp_lport == lport && inp->inp_fport == 0 &&
- IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr) &&
+ IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, key1) &&
IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
break;
}
- if (inp == NULL && !IN6_IS_ADDR_UNSPECIFIED(laddr)) {
- head = IN6PCBHASH(table, &zeroin6_addr, 0,
- &zeroin6_addr, lport);
+ if (inp == NULL && ! IN6_ARE_ADDR_EQUAL(key1, key2)) {
+ head = IN6PCBHASH(table, &zeroin6_addr, 0, key2, lport);
LIST_FOREACH(inp, head, inp_hash) {
if (!(inp->inp_flags & INP_IPV6))
continue;
if (inp->inp_lport == lport && inp->inp_fport == 0 &&
- IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) &&
+ IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, key2) &&
IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
break;
}
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index 5f5ec71b589..27d411b4a5c 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_pcb.h,v 1.47 2003/11/04 21:43:16 markus Exp $ */
+/* $OpenBSD: in_pcb.h,v 1.48 2003/12/08 07:07:36 mcbride Exp $ */
/* $NetBSD: in_pcb.h,v 1.14 1996/02/13 23:42:00 christos Exp $ */
/*
@@ -239,14 +239,14 @@ struct inpcb *
in_pcbhashlookup(struct inpcbtable *, struct in_addr,
u_int, struct in_addr, u_int);
struct inpcb *
- in_pcblookup_listen(struct inpcbtable *, struct in_addr, u_int);
+ in_pcblookup_listen(struct inpcbtable *, struct in_addr, u_int, int);
#ifdef INET6
struct inpcb *
in6_pcbhashlookup(struct inpcbtable *, struct in6_addr *,
u_int, struct in6_addr *, u_int);
struct inpcb *
in6_pcblookup_listen(struct inpcbtable *,
- struct in6_addr *, u_int);
+ struct in6_addr *, u_int, int);
int in6_pcbbind(struct inpcb *, struct mbuf *);
int in6_pcbconnect(struct inpcb *, struct mbuf *);
int in6_setsockaddr(struct inpcb *, struct mbuf *);
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index a786851a75a..945076d1f62 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_input.c,v 1.134 2003/11/04 21:43:16 markus Exp $ */
+/* $OpenBSD: tcp_input.c,v 1.135 2003/12/08 07:07:36 mcbride Exp $ */
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
/*
@@ -671,12 +671,14 @@ findpcb:
#ifdef INET6
case AF_INET6:
inp = in6_pcblookup_listen(&tcbtable,
- &ip6->ip6_dst, th->th_dport);
+ &ip6->ip6_dst, th->th_dport, m_tag_find(m,
+ PACKET_TAG_PF_TRANSLATE_LOCALHOST, NULL) != NULL);
break;
#endif /* INET6 */
case AF_INET:
inp = in_pcblookup_listen(&tcbtable,
- ip->ip_dst, th->th_dport);
+ ip->ip_dst, th->th_dport, m_tag_find(m,
+ PACKET_TAG_PF_TRANSLATE_LOCALHOST, NULL) != NULL);
break;
}
/*
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index ff9983289b7..7512d1a99b0 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_usrreq.c,v 1.72 2003/11/04 21:43:16 markus Exp $ */
+/* $OpenBSD: tcp_usrreq.c,v 1.73 2003/12/08 07:07:36 mcbride Exp $ */
/* $NetBSD: tcp_usrreq.c,v 1.20 1996/02/13 23:44:16 christos Exp $ */
/*
@@ -835,12 +835,12 @@ tcp_ident(oldp, oldlenp, newp, newlen)
#ifdef INET6
case AF_INET6:
inp = in6_pcblookup_listen(&tcbtable,
- &l6, lin6->sin6_port);
+ &l6, lin6->sin6_port, 0);
break;
#endif
case AF_INET:
inp = in_pcblookup_listen(&tcbtable,
- lin->sin_addr, lin->sin_port);
+ lin->sin_addr, lin->sin_port, 0);
break;
}
}
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 2d5aed4bbec..b5823ac6073 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: udp_usrreq.c,v 1.93 2003/12/02 23:16:29 markus Exp $ */
+/* $OpenBSD: udp_usrreq.c,v 1.94 2003/12/08 07:07:36 mcbride Exp $ */
/* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
/*
@@ -525,11 +525,13 @@ udp_input(struct mbuf *m, ...)
#ifdef INET6
if (ip6) {
inp = in6_pcblookup_listen(&udbtable,
- &ip6->ip6_dst, uh->uh_dport);
+ &ip6->ip6_dst, uh->uh_dport, m_tag_find(m,
+ PACKET_TAG_PF_TRANSLATE_LOCALHOST, NULL) != NULL);
} else
#endif /* INET6 */
inp = in_pcblookup_listen(&udbtable,
- ip->ip_dst, uh->uh_dport);
+ ip->ip_dst, uh->uh_dport, m_tag_find(m,
+ PACKET_TAG_PF_TRANSLATE_LOCALHOST, NULL) != NULL);
if (inp == 0) {
udpstat.udps_noport++;
if (m->m_flags & (M_BCAST | M_MCAST)) {
@@ -820,7 +822,7 @@ udp6_ctlinput(cmd, sa, d)
* is really ours.
*/
else if (in6_pcblookup_listen(&udbtable,
- &sa6_src.sin6_addr, uh.uh_sport))
+ &sa6_src.sin6_addr, uh.uh_sport, 0);
valid = 1;
#endif
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
index 1f22798d048..d860e2dfc17 100644
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: mbuf.h,v 1.73 2003/10/17 21:04:59 mcbride Exp $ */
+/* $OpenBSD: mbuf.h,v 1.74 2003/12/08 07:07:36 mcbride Exp $ */
/* $NetBSD: mbuf.h,v 1.19 1996/02/09 18:25:14 christos Exp $ */
/*
@@ -598,6 +598,7 @@ struct m_tag *m_tag_next(struct mbuf *, struct m_tag *);
#define PACKET_TAG_PF_QID 14 /* PF queue id */
#define PACKET_TAG_PF_TAG 15 /* PF tags */
#define PACKET_TAG_CARP 16 /* CARP info */
+#define PACKET_TAG_PF_TRANSLATE_LOCALHOST 17 /* translated to localhost */
#ifdef MBTYPES
int mbtypes[] = { /* XXX */