summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Thomas McBride <mcbride@cvs.openbsd.org>2003-12-08 07:07:37 +0000
committerRyan Thomas McBride <mcbride@cvs.openbsd.org>2003-12-08 07:07:37 +0000
commit27292f48c8c9693222952f5d014f0d3c9de14aaf (patch)
tree84013f176779794382e2f9736cc46c1c1938ea09
parent4a8b62f7a064527262e43e34aa5e8de6796ba36c (diff)
Mbuf tag tcp and udp packets which are translated to localhost, and
use the the presence of this tag to reverse the match order in in{6}_pcblookup_listen(). Some daemons (such as portmap) do a double bind, binding to both * and localhost in order to differentiate local from non-local connections, and potentially granting more privilege to local ones. This change ensures that redirected connections to localhost do not appear local to such a daemon. Bulk of changes from dhartmei@, some changes markus@ ok dhartmei@ deraadt@
-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 */