[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date: Mon, 20 Mar 2023 19:49:46 -0700
From: Hyunwoo Kim <v4bel@...ori.io>
To: Taehee Yoo <ap420073@...il.com>,
"David S. Miller" <davem@...emloft.net>,
Eric Dumazet <edumazet@...gle.com>,
Jakub Kicinski <kuba@...nel.org>,
Paolo Abeni <pabeni@...hat.com>, Dmitry Kozlov <xeb@...l.ru>,
David Ahern <dsahern@...nel.org>
Cc: tudordana@...gle.com, netdev@...r.kernel.org, imv4bel@...il.com,
v4bel@...ori.io
Subject: [PATCH] net: Fix invalid ip_route_output_ports() call
If you pass the address of the struct flowi4 you declared as a
local variable as the fl4 argument to ip_route_output_ports(),
the subsequent call to xfrm_state_find() will read the local
variable by AF_INET6 rather than AF_INET as per policy,
which could cause it to go out of scope on the kernel stack.
Reported-by: syzbot+ada7c035554bcee65580@...kaller.appspotmail.com
Signed-off-by: Hyunwoo Kim <v4bel@...ori.io>
---
drivers/net/amt.c | 15 +++++++++------
.../net/ethernet/chelsio/libcxgb/libcxgb_cm.c | 5 +++--
drivers/net/ppp/pptp.c | 14 ++++++++------
net/ipv4/datagram.c | 5 +++--
net/ipv4/igmp.c | 16 +++++++++-------
net/ipv4/ipmr.c | 7 ++++---
net/ipv6/ip6_tunnel.c | 7 ++++---
net/ipv6/sit.c | 5 +++--
8 files changed, 43 insertions(+), 31 deletions(-)
diff --git a/drivers/net/amt.c b/drivers/net/amt.c
index 2d20be6ffb7e..4d8caaedc9d4 100644
--- a/drivers/net/amt.c
+++ b/drivers/net/amt.c
@@ -617,7 +617,8 @@ static void amt_send_discovery(struct amt_dev *amt)
struct sk_buff *skb;
struct iphdr *iph;
struct rtable *rt;
- struct flowi4 fl4;
+ struct flowi fl;
+ struct flowi4 *fl4 = &fl.u.ip4;
u32 len;
int err;
@@ -629,7 +630,7 @@ static void amt_send_discovery(struct amt_dev *amt)
if (!netif_running(amt->stream_dev) || !netif_running(amt->dev))
goto out;
- rt = ip_route_output_ports(amt->net, &fl4, sock->sk,
+ rt = ip_route_output_ports(amt->net, fl4, sock->sk,
amt->discovery_ip, amt->local_ip,
amt->gw_port, amt->relay_port,
IPPROTO_UDP, 0,
@@ -706,7 +707,8 @@ static void amt_send_request(struct amt_dev *amt, bool v6)
struct sk_buff *skb;
struct iphdr *iph;
struct rtable *rt;
- struct flowi4 fl4;
+ struct flowi fl;
+ struct flowi4 *fl4 = &fl.u.ip4;
u32 len;
int err;
@@ -718,7 +720,7 @@ static void amt_send_request(struct amt_dev *amt, bool v6)
if (!netif_running(amt->stream_dev) || !netif_running(amt->dev))
goto out;
- rt = ip_route_output_ports(amt->net, &fl4, sock->sk,
+ rt = ip_route_output_ports(amt->net, fl4, sock->sk,
amt->remote_ip, amt->local_ip,
amt->gw_port, amt->relay_port,
IPPROTO_UDP, 0,
@@ -2554,7 +2556,8 @@ static void amt_send_advertisement(struct amt_dev *amt, __be32 nonce,
struct sk_buff *skb;
struct iphdr *iph;
struct rtable *rt;
- struct flowi4 fl4;
+ struct flowi fl;
+ struct flowi4 *fl4 = &fl.u.ip4;
u32 len;
int err;
@@ -2566,7 +2569,7 @@ static void amt_send_advertisement(struct amt_dev *amt, __be32 nonce,
if (!netif_running(amt->stream_dev) || !netif_running(amt->dev))
goto out;
- rt = ip_route_output_ports(amt->net, &fl4, sock->sk,
+ rt = ip_route_output_ports(amt->net, fl4, sock->sk,
daddr, amt->local_ip,
dport, amt->relay_port,
IPPROTO_UDP, 0,
diff --git a/drivers/net/ethernet/chelsio/libcxgb/libcxgb_cm.c b/drivers/net/ethernet/chelsio/libcxgb/libcxgb_cm.c
index da8d10475a08..e06a6d0a3595 100644
--- a/drivers/net/ethernet/chelsio/libcxgb/libcxgb_cm.c
+++ b/drivers/net/ethernet/chelsio/libcxgb/libcxgb_cm.c
@@ -95,10 +95,11 @@ cxgb_find_route(struct cxgb4_lld_info *lldi,
__be16 peer_port, u8 tos)
{
struct rtable *rt;
- struct flowi4 fl4;
+ struct flowi fl;
+ struct flowi4 *fl4 = &fl.u.ip4;
struct neighbour *n;
- rt = ip_route_output_ports(&init_net, &fl4, NULL, peer_ip, local_ip,
+ rt = ip_route_output_ports(&init_net, fl4, NULL, peer_ip, local_ip,
peer_port, local_port, IPPROTO_TCP,
tos & ~INET_ECN_MASK, 0);
if (IS_ERR(rt))
diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
index 0fe78826c8fa..6e4422ce89b5 100644
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -136,7 +136,8 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
struct pptp_opt *opt = &po->proto.pptp;
struct pptp_gre_header *hdr;
unsigned int header_len = sizeof(*hdr);
- struct flowi4 fl4;
+ struct flowi fl;
+ struct flowi4 *fl4 = &fl.u.ip4;
int islcp;
int len;
unsigned char *data;
@@ -151,7 +152,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
if (sk_pppox(po)->sk_state & PPPOX_DEAD)
goto tx_error;
- rt = ip_route_output_ports(net, &fl4, NULL,
+ rt = ip_route_output_ports(net, fl4, NULL,
opt->dst_addr.sin_addr.s_addr,
opt->src_addr.sin_addr.s_addr,
0, 0, IPPROTO_GRE,
@@ -230,8 +231,8 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
iph->frag_off = 0;
iph->protocol = IPPROTO_GRE;
iph->tos = 0;
- iph->daddr = fl4.daddr;
- iph->saddr = fl4.saddr;
+ iph->daddr = fl4->daddr;
+ iph->saddr = fl4->saddr;
iph->ttl = ip4_dst_hoplimit(&rt->dst);
iph->tot_len = htons(skb->len);
@@ -405,7 +406,8 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
struct pppox_sock *po = pppox_sk(sk);
struct pptp_opt *opt = &po->proto.pptp;
struct rtable *rt;
- struct flowi4 fl4;
+ struct flowi fl;
+ struct flowi4 *fl4 = &fl.u.ip4;
int error = 0;
if (sockaddr_len < sizeof(struct sockaddr_pppox))
@@ -438,7 +440,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
po->chan.private = sk;
po->chan.ops = &pptp_chan_ops;
- rt = ip_route_output_ports(sock_net(sk), &fl4, sk,
+ rt = ip_route_output_ports(sock_net(sk), fl4, sk,
opt->dst_addr.sin_addr.s_addr,
opt->src_addr.sin_addr.s_addr,
0, 0,
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c
index 4d1af0cd7d99..12656eb49e50 100644
--- a/net/ipv4/datagram.c
+++ b/net/ipv4/datagram.c
@@ -103,7 +103,8 @@ void ip4_datagram_release_cb(struct sock *sk)
const struct ip_options_rcu *inet_opt;
__be32 daddr = inet->inet_daddr;
struct dst_entry *dst;
- struct flowi4 fl4;
+ struct flowi fl;
+ struct flowi4 *fl4 = &fl.u.ip4;
struct rtable *rt;
rcu_read_lock();
@@ -116,7 +117,7 @@ void ip4_datagram_release_cb(struct sock *sk)
inet_opt = rcu_dereference(inet->inet_opt);
if (inet_opt && inet_opt->opt.srr)
daddr = inet_opt->opt.faddr;
- rt = ip_route_output_ports(sock_net(sk), &fl4, sk, daddr,
+ rt = ip_route_output_ports(sock_net(sk), fl4, sk, daddr,
inet->inet_saddr, inet->inet_dport,
inet->inet_sport, sk->sk_protocol,
RT_CONN_FLAGS(sk), sk->sk_bound_dev_if);
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index c920aa9a62a9..b7de65708b37 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -350,7 +350,8 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu)
struct iphdr *pip;
struct igmpv3_report *pig;
struct net *net = dev_net(dev);
- struct flowi4 fl4;
+ struct flowi fl;
+ struct flowi4 *fl4 = &fl.u.ip4;
int hlen = LL_RESERVED_SPACE(dev);
int tlen = dev->needed_tailroom;
unsigned int size = mtu;
@@ -366,7 +367,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu)
}
skb->priority = TC_PRIO_CONTROL;
- rt = ip_route_output_ports(net, &fl4, NULL, IGMPV3_ALL_MCR, 0,
+ rt = ip_route_output_ports(net, fl4, NULL, IGMPV3_ALL_MCR, 0,
0, 0,
IPPROTO_IGMP, 0, dev->ifindex);
if (IS_ERR(rt)) {
@@ -389,10 +390,10 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu)
pip->tos = 0xc0;
pip->frag_off = htons(IP_DF);
pip->ttl = 1;
- pip->daddr = fl4.daddr;
+ pip->daddr = fl4->daddr;
rcu_read_lock();
- pip->saddr = igmpv3_get_srcaddr(dev, &fl4);
+ pip->saddr = igmpv3_get_srcaddr(dev, fl4);
rcu_read_unlock();
pip->protocol = IPPROTO_IGMP;
@@ -730,7 +731,8 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
struct net_device *dev = in_dev->dev;
struct net *net = dev_net(dev);
__be32 group = pmc ? pmc->multiaddr : 0;
- struct flowi4 fl4;
+ struct flowi fl;
+ struct flowi4 *fl4 = &fl.u.ip4;
__be32 dst;
int hlen, tlen;
@@ -746,7 +748,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
else
dst = group;
- rt = ip_route_output_ports(net, &fl4, NULL, dst, 0,
+ rt = ip_route_output_ports(net, fl4, NULL, dst, 0,
0, 0,
IPPROTO_IGMP, 0, dev->ifindex);
if (IS_ERR(rt))
@@ -775,7 +777,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
iph->frag_off = htons(IP_DF);
iph->ttl = 1;
iph->daddr = dst;
- iph->saddr = fl4.saddr;
+ iph->saddr = fl4->saddr;
iph->protocol = IPPROTO_IGMP;
ip_select_ident(net, skb, NULL);
((u8 *)&iph[1])[0] = IPOPT_RA;
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index eec1f6df80d8..994dd589835c 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1829,7 +1829,8 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
struct net_device *vif_dev;
struct net_device *dev;
struct rtable *rt;
- struct flowi4 fl4;
+ struct flowi fl;
+ struct flowi4 *fl4 = &fl.u.ip4;
int encap = 0;
vif_dev = vif_dev_read(vif);
@@ -1849,7 +1850,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
goto out_free;
if (vif->flags & VIFF_TUNNEL) {
- rt = ip_route_output_ports(net, &fl4, NULL,
+ rt = ip_route_output_ports(net, fl4, NULL,
vif->remote, vif->local,
0, 0,
IPPROTO_IPIP,
@@ -1858,7 +1859,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
goto out_free;
encap = sizeof(struct iphdr);
} else {
- rt = ip_route_output_ports(net, &fl4, NULL, iph->daddr, 0,
+ rt = ip_route_output_ports(net, fl4, NULL, iph->daddr, 0,
0, 0,
IPPROTO_IPIP,
RT_TOS(iph->tos), vif->link);
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 47b6607a1370..078a97742b7d 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -567,7 +567,8 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
u8 rel_type = type;
u8 rel_code = code;
struct rtable *rt;
- struct flowi4 fl4;
+ struct flowi fl;
+ struct flowi4 *fl4 = &fl.u.ip4;
err = ip6_tnl_err(skb, IPPROTO_IPIP, opt, &rel_type, &rel_code,
&rel_msg, &rel_info, offset);
@@ -608,7 +609,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
eiph = ip_hdr(skb2);
/* Try to guess incoming interface */
- rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, eiph->saddr,
+ rt = ip_route_output_ports(dev_net(skb->dev), fl4, NULL, eiph->saddr,
0, 0, 0, IPPROTO_IPIP, RT_TOS(eiph->tos), 0);
if (IS_ERR(rt))
goto out;
@@ -618,7 +619,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
/* route "incoming" packet */
if (rt->rt_flags & RTCF_LOCAL) {
- rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL,
+ rt = ip_route_output_ports(dev_net(skb->dev), fl4, NULL,
eiph->daddr, eiph->saddr, 0, 0,
IPPROTO_IPIP, RT_TOS(eiph->tos), 0);
if (IS_ERR(rt) || rt->dst.dev->type != ARPHRD_TUNNEL6) {
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 70d81bba5093..fc2fb6bae588 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -1098,13 +1098,14 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev)
struct net_device *tdev = NULL;
struct ip_tunnel *tunnel;
const struct iphdr *iph;
- struct flowi4 fl4;
+ struct flowi fl;
+ struct flowi4 *fl4 = &fl.u.ip4;
tunnel = netdev_priv(dev);
iph = &tunnel->parms.iph;
if (iph->daddr) {
- struct rtable *rt = ip_route_output_ports(tunnel->net, &fl4,
+ struct rtable *rt = ip_route_output_ports(tunnel->net, fl4,
NULL,
iph->daddr, iph->saddr,
0, 0,
--
2.25.1
Powered by blists - more mailing lists