Skip to content

Commit f887f2a

Browse files
haggaiedledford
authored andcommitted
IB/cma: Validate routing of incoming requests
Pass incoming request parameters through the relevant IPv4/IPv6 routing tables and make sure the network stack is configured to handle such requests. Signed-off-by: Haggai Eran <[email protected]> Signed-off-by: Doug Ledford <[email protected]>
1 parent 4c21b5b commit f887f2a

File tree

1 file changed

+92
-3
lines changed
  • drivers/infiniband/core

1 file changed

+92
-3
lines changed

drivers/infiniband/core/cma.c

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646

4747
#include <net/tcp.h>
4848
#include <net/ipv6.h>
49+
#include <net/ip_fib.h>
50+
#include <net/ip6_route.h>
4951

5052
#include <rdma/rdma_cm.h>
5153
#include <rdma/rdma_cm_ib.h>
@@ -1081,16 +1083,98 @@ static int cma_save_req_info(const struct ib_cm_event *ib_event,
10811083
return 0;
10821084
}
10831085

1086+
static bool validate_ipv4_net_dev(struct net_device *net_dev,
1087+
const struct sockaddr_in *dst_addr,
1088+
const struct sockaddr_in *src_addr)
1089+
{
1090+
__be32 daddr = dst_addr->sin_addr.s_addr,
1091+
saddr = src_addr->sin_addr.s_addr;
1092+
struct fib_result res;
1093+
struct flowi4 fl4;
1094+
int err;
1095+
bool ret;
1096+
1097+
if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) ||
1098+
ipv4_is_lbcast(daddr) || ipv4_is_zeronet(saddr) ||
1099+
ipv4_is_zeronet(daddr) || ipv4_is_loopback(daddr) ||
1100+
ipv4_is_loopback(saddr))
1101+
return false;
1102+
1103+
memset(&fl4, 0, sizeof(fl4));
1104+
fl4.flowi4_iif = net_dev->ifindex;
1105+
fl4.daddr = daddr;
1106+
fl4.saddr = saddr;
1107+
1108+
rcu_read_lock();
1109+
err = fib_lookup(dev_net(net_dev), &fl4, &res, 0);
1110+
if (err)
1111+
return false;
1112+
1113+
ret = FIB_RES_DEV(res) == net_dev;
1114+
rcu_read_unlock();
1115+
1116+
return ret;
1117+
}
1118+
1119+
static bool validate_ipv6_net_dev(struct net_device *net_dev,
1120+
const struct sockaddr_in6 *dst_addr,
1121+
const struct sockaddr_in6 *src_addr)
1122+
{
1123+
#if IS_ENABLED(CONFIG_IPV6)
1124+
const int strict = ipv6_addr_type(&dst_addr->sin6_addr) &
1125+
IPV6_ADDR_LINKLOCAL;
1126+
struct rt6_info *rt = rt6_lookup(dev_net(net_dev), &dst_addr->sin6_addr,
1127+
&src_addr->sin6_addr, net_dev->ifindex,
1128+
strict);
1129+
bool ret;
1130+
1131+
if (!rt)
1132+
return false;
1133+
1134+
ret = rt->rt6i_idev->dev == net_dev;
1135+
ip6_rt_put(rt);
1136+
1137+
return ret;
1138+
#else
1139+
return false;
1140+
#endif
1141+
}
1142+
1143+
static bool validate_net_dev(struct net_device *net_dev,
1144+
const struct sockaddr *daddr,
1145+
const struct sockaddr *saddr)
1146+
{
1147+
const struct sockaddr_in *daddr4 = (const struct sockaddr_in *)daddr;
1148+
const struct sockaddr_in *saddr4 = (const struct sockaddr_in *)saddr;
1149+
const struct sockaddr_in6 *daddr6 = (const struct sockaddr_in6 *)daddr;
1150+
const struct sockaddr_in6 *saddr6 = (const struct sockaddr_in6 *)saddr;
1151+
1152+
switch (daddr->sa_family) {
1153+
case AF_INET:
1154+
return saddr->sa_family == AF_INET &&
1155+
validate_ipv4_net_dev(net_dev, daddr4, saddr4);
1156+
1157+
case AF_INET6:
1158+
return saddr->sa_family == AF_INET6 &&
1159+
validate_ipv6_net_dev(net_dev, daddr6, saddr6);
1160+
1161+
default:
1162+
return false;
1163+
}
1164+
}
1165+
10841166
static struct net_device *cma_get_net_dev(struct ib_cm_event *ib_event,
10851167
const struct cma_req_info *req)
10861168
{
1087-
struct sockaddr_storage listen_addr_storage;
1088-
struct sockaddr *listen_addr = (struct sockaddr *)&listen_addr_storage;
1169+
struct sockaddr_storage listen_addr_storage, src_addr_storage;
1170+
struct sockaddr *listen_addr = (struct sockaddr *)&listen_addr_storage,
1171+
*src_addr = (struct sockaddr *)&src_addr_storage;
10891172
struct net_device *net_dev;
10901173
const union ib_gid *gid = req->has_gid ? &req->local_gid : NULL;
10911174
int err;
10921175

1093-
err = cma_save_ip_info(listen_addr, NULL, ib_event, req->service_id);
1176+
err = cma_save_ip_info(listen_addr, src_addr, ib_event,
1177+
req->service_id);
10941178
if (err)
10951179
return ERR_PTR(err);
10961180

@@ -1099,6 +1183,11 @@ static struct net_device *cma_get_net_dev(struct ib_cm_event *ib_event,
10991183
if (!net_dev)
11001184
return ERR_PTR(-ENODEV);
11011185

1186+
if (!validate_net_dev(net_dev, listen_addr, src_addr)) {
1187+
dev_put(net_dev);
1188+
return ERR_PTR(-EHOSTUNREACH);
1189+
}
1190+
11021191
return net_dev;
11031192
}
11041193

0 commit comments

Comments
 (0)