Commit 5711b4e8 authored by Máté Eckl's avatar Máté Eckl Committed by Pablo Neira Ayuso

netfilter: nf_tproxy: fix possible non-linear access to transport header

This patch fixes a silent out-of-bound read possibility that was present
because of the misuse of this function.

Mostly it was called with a struct udphdr *hp which had only the udphdr
part linearized by the skb_header_pointer, however
nf_tproxy_get_sock_v{4,6} uses it as a tcphdr pointer, so some reads for
tcp specific attributes may be invalid.

Fixes: a583636a ("inet: refactor inet[6]_lookup functions to take skb")
Signed-off-by: default avatarMáté Eckl <ecklm94@gmail.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent d376bef9
...@@ -64,7 +64,7 @@ nf_tproxy_handle_time_wait4(struct net *net, struct sk_buff *skb, ...@@ -64,7 +64,7 @@ nf_tproxy_handle_time_wait4(struct net *net, struct sk_buff *skb,
* belonging to established connections going through that one. * belonging to established connections going through that one.
*/ */
struct sock * struct sock *
nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp, nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb,
const u8 protocol, const u8 protocol,
const __be32 saddr, const __be32 daddr, const __be32 saddr, const __be32 daddr,
const __be16 sport, const __be16 dport, const __be16 sport, const __be16 dport,
...@@ -103,7 +103,7 @@ nf_tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff, ...@@ -103,7 +103,7 @@ nf_tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff,
struct sock *sk); struct sock *sk);
struct sock * struct sock *
nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp, nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff,
const u8 protocol, const u8 protocol,
const struct in6_addr *saddr, const struct in6_addr *daddr, const struct in6_addr *saddr, const struct in6_addr *daddr,
const __be16 sport, const __be16 dport, const __be16 sport, const __be16 dport,
......
...@@ -37,7 +37,7 @@ nf_tproxy_handle_time_wait4(struct net *net, struct sk_buff *skb, ...@@ -37,7 +37,7 @@ nf_tproxy_handle_time_wait4(struct net *net, struct sk_buff *skb,
* to a listener socket if there's one */ * to a listener socket if there's one */
struct sock *sk2; struct sock *sk2;
sk2 = nf_tproxy_get_sock_v4(net, skb, hp, iph->protocol, sk2 = nf_tproxy_get_sock_v4(net, skb, iph->protocol,
iph->saddr, laddr ? laddr : iph->daddr, iph->saddr, laddr ? laddr : iph->daddr,
hp->source, lport ? lport : hp->dest, hp->source, lport ? lport : hp->dest,
skb->dev, NF_TPROXY_LOOKUP_LISTENER); skb->dev, NF_TPROXY_LOOKUP_LISTENER);
...@@ -71,7 +71,7 @@ __be32 nf_tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr) ...@@ -71,7 +71,7 @@ __be32 nf_tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr)
EXPORT_SYMBOL_GPL(nf_tproxy_laddr4); EXPORT_SYMBOL_GPL(nf_tproxy_laddr4);
struct sock * struct sock *
nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp, nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb,
const u8 protocol, const u8 protocol,
const __be32 saddr, const __be32 daddr, const __be32 saddr, const __be32 daddr,
const __be16 sport, const __be16 dport, const __be16 sport, const __be16 dport,
...@@ -79,16 +79,21 @@ nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp, ...@@ -79,16 +79,21 @@ nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp,
const enum nf_tproxy_lookup_t lookup_type) const enum nf_tproxy_lookup_t lookup_type)
{ {
struct sock *sk; struct sock *sk;
struct tcphdr *tcph;
switch (protocol) { switch (protocol) {
case IPPROTO_TCP: case IPPROTO_TCP: {
struct tcphdr _hdr, *hp;
hp = skb_header_pointer(skb, ip_hdrlen(skb),
sizeof(struct tcphdr), &_hdr);
if (hp == NULL)
return NULL;
switch (lookup_type) { switch (lookup_type) {
case NF_TPROXY_LOOKUP_LISTENER: case NF_TPROXY_LOOKUP_LISTENER:
tcph = hp;
sk = inet_lookup_listener(net, &tcp_hashinfo, skb, sk = inet_lookup_listener(net, &tcp_hashinfo, skb,
ip_hdrlen(skb) + ip_hdrlen(skb) +
__tcp_hdrlen(tcph), __tcp_hdrlen(hp),
saddr, sport, saddr, sport,
daddr, dport, daddr, dport,
in->ifindex, 0); in->ifindex, 0);
...@@ -110,6 +115,7 @@ nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp, ...@@ -110,6 +115,7 @@ nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp,
BUG(); BUG();
} }
break; break;
}
case IPPROTO_UDP: case IPPROTO_UDP:
sk = udp4_lib_lookup(net, saddr, sport, daddr, dport, sk = udp4_lib_lookup(net, saddr, sport, daddr, dport,
in->ifindex); in->ifindex);
......
...@@ -55,7 +55,7 @@ nf_tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff, ...@@ -55,7 +55,7 @@ nf_tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff,
* to a listener socket if there's one */ * to a listener socket if there's one */
struct sock *sk2; struct sock *sk2;
sk2 = nf_tproxy_get_sock_v6(net, skb, thoff, hp, tproto, sk2 = nf_tproxy_get_sock_v6(net, skb, thoff, tproto,
&iph->saddr, &iph->saddr,
nf_tproxy_laddr6(skb, laddr, &iph->daddr), nf_tproxy_laddr6(skb, laddr, &iph->daddr),
hp->source, hp->source,
...@@ -72,7 +72,7 @@ nf_tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff, ...@@ -72,7 +72,7 @@ nf_tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff,
EXPORT_SYMBOL_GPL(nf_tproxy_handle_time_wait6); EXPORT_SYMBOL_GPL(nf_tproxy_handle_time_wait6);
struct sock * struct sock *
nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp, nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff,
const u8 protocol, const u8 protocol,
const struct in6_addr *saddr, const struct in6_addr *daddr, const struct in6_addr *saddr, const struct in6_addr *daddr,
const __be16 sport, const __be16 dport, const __be16 sport, const __be16 dport,
...@@ -80,15 +80,20 @@ nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp, ...@@ -80,15 +80,20 @@ nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp,
const enum nf_tproxy_lookup_t lookup_type) const enum nf_tproxy_lookup_t lookup_type)
{ {
struct sock *sk; struct sock *sk;
struct tcphdr *tcph;
switch (protocol) { switch (protocol) {
case IPPROTO_TCP: case IPPROTO_TCP: {
struct tcphdr _hdr, *hp;
hp = skb_header_pointer(skb, thoff,
sizeof(struct tcphdr), &_hdr);
if (hp == NULL)
return NULL;
switch (lookup_type) { switch (lookup_type) {
case NF_TPROXY_LOOKUP_LISTENER: case NF_TPROXY_LOOKUP_LISTENER:
tcph = hp;
sk = inet6_lookup_listener(net, &tcp_hashinfo, skb, sk = inet6_lookup_listener(net, &tcp_hashinfo, skb,
thoff + __tcp_hdrlen(tcph), thoff + __tcp_hdrlen(hp),
saddr, sport, saddr, sport,
daddr, ntohs(dport), daddr, ntohs(dport),
in->ifindex, 0); in->ifindex, 0);
...@@ -110,6 +115,7 @@ nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp, ...@@ -110,6 +115,7 @@ nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp,
BUG(); BUG();
} }
break; break;
}
case IPPROTO_UDP: case IPPROTO_UDP:
sk = udp6_lib_lookup(net, saddr, sport, daddr, dport, sk = udp6_lib_lookup(net, saddr, sport, daddr, dport,
in->ifindex); in->ifindex);
......
...@@ -61,7 +61,7 @@ tproxy_tg4(struct net *net, struct sk_buff *skb, __be32 laddr, __be16 lport, ...@@ -61,7 +61,7 @@ tproxy_tg4(struct net *net, struct sk_buff *skb, __be32 laddr, __be16 lport,
* addresses, this happens if the redirect already happened * addresses, this happens if the redirect already happened
* and the current packet belongs to an already established * and the current packet belongs to an already established
* connection */ * connection */
sk = nf_tproxy_get_sock_v4(net, skb, hp, iph->protocol, sk = nf_tproxy_get_sock_v4(net, skb, iph->protocol,
iph->saddr, iph->daddr, iph->saddr, iph->daddr,
hp->source, hp->dest, hp->source, hp->dest,
skb->dev, NF_TPROXY_LOOKUP_ESTABLISHED); skb->dev, NF_TPROXY_LOOKUP_ESTABLISHED);
...@@ -77,7 +77,7 @@ tproxy_tg4(struct net *net, struct sk_buff *skb, __be32 laddr, __be16 lport, ...@@ -77,7 +77,7 @@ tproxy_tg4(struct net *net, struct sk_buff *skb, __be32 laddr, __be16 lport,
else if (!sk) else if (!sk)
/* no, there's no established connection, check if /* no, there's no established connection, check if
* there's a listener on the redirected addr/port */ * there's a listener on the redirected addr/port */
sk = nf_tproxy_get_sock_v4(net, skb, hp, iph->protocol, sk = nf_tproxy_get_sock_v4(net, skb, iph->protocol,
iph->saddr, laddr, iph->saddr, laddr,
hp->source, lport, hp->source, lport,
skb->dev, NF_TPROXY_LOOKUP_LISTENER); skb->dev, NF_TPROXY_LOOKUP_LISTENER);
...@@ -150,7 +150,7 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par) ...@@ -150,7 +150,7 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
* addresses, this happens if the redirect already happened * addresses, this happens if the redirect already happened
* and the current packet belongs to an already established * and the current packet belongs to an already established
* connection */ * connection */
sk = nf_tproxy_get_sock_v6(xt_net(par), skb, thoff, hp, tproto, sk = nf_tproxy_get_sock_v6(xt_net(par), skb, thoff, tproto,
&iph->saddr, &iph->daddr, &iph->saddr, &iph->daddr,
hp->source, hp->dest, hp->source, hp->dest,
xt_in(par), NF_TPROXY_LOOKUP_ESTABLISHED); xt_in(par), NF_TPROXY_LOOKUP_ESTABLISHED);
...@@ -171,7 +171,7 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par) ...@@ -171,7 +171,7 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
else if (!sk) else if (!sk)
/* no there's no established connection, check if /* no there's no established connection, check if
* there's a listener on the redirected addr/port */ * there's a listener on the redirected addr/port */
sk = nf_tproxy_get_sock_v6(xt_net(par), skb, thoff, hp, sk = nf_tproxy_get_sock_v6(xt_net(par), skb, thoff,
tproto, &iph->saddr, laddr, tproto, &iph->saddr, laddr,
hp->source, lport, hp->source, lport,
xt_in(par), NF_TPROXY_LOOKUP_LISTENER); xt_in(par), NF_TPROXY_LOOKUP_LISTENER);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment