Skip to content

Commit 2002983

Browse files
matanb10dledford
authored andcommitted
IB/core: Validate route when we init ah
In order to make sure API users don't try to use SGIDs which don't conform to the routing table, validate the route before searching the RoCE GID table. Signed-off-by: Matan Barak <[email protected]> Signed-off-by: Doug Ledford <[email protected]>
1 parent 6020d7e commit 2002983

File tree

7 files changed

+270
-80
lines changed

7 files changed

+270
-80
lines changed

drivers/infiniband/core/addr.c

+124-51
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
121121
}
122122
EXPORT_SYMBOL(rdma_copy_addr);
123123

124-
int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr,
124+
int rdma_translate_ip(const struct sockaddr *addr,
125+
struct rdma_dev_addr *dev_addr,
125126
u16 *vlan_id)
126127
{
127128
struct net_device *dev;
@@ -139,7 +140,7 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr,
139140
switch (addr->sa_family) {
140141
case AF_INET:
141142
dev = ip_dev_find(dev_addr->net,
142-
((struct sockaddr_in *) addr)->sin_addr.s_addr);
143+
((const struct sockaddr_in *)addr)->sin_addr.s_addr);
143144

144145
if (!dev)
145146
return ret;
@@ -154,7 +155,7 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr,
154155
rcu_read_lock();
155156
for_each_netdev_rcu(dev_addr->net, dev) {
156157
if (ipv6_chk_addr(dev_addr->net,
157-
&((struct sockaddr_in6 *) addr)->sin6_addr,
158+
&((const struct sockaddr_in6 *)addr)->sin6_addr,
158159
dev, 1)) {
159160
ret = rdma_copy_addr(dev_addr, dev, NULL);
160161
if (vlan_id)
@@ -198,7 +199,8 @@ static void queue_req(struct addr_req *req)
198199
mutex_unlock(&lock);
199200
}
200201

201-
static int dst_fetch_ha(struct dst_entry *dst, struct rdma_dev_addr *dev_addr, void *daddr)
202+
static int dst_fetch_ha(struct dst_entry *dst, struct rdma_dev_addr *dev_addr,
203+
const void *daddr)
202204
{
203205
struct neighbour *n;
204206
int ret;
@@ -222,8 +224,9 @@ static int dst_fetch_ha(struct dst_entry *dst, struct rdma_dev_addr *dev_addr, v
222224
}
223225

224226
static int addr4_resolve(struct sockaddr_in *src_in,
225-
struct sockaddr_in *dst_in,
226-
struct rdma_dev_addr *addr)
227+
const struct sockaddr_in *dst_in,
228+
struct rdma_dev_addr *addr,
229+
struct rtable **prt)
227230
{
228231
__be32 src_ip = src_in->sin_addr.s_addr;
229232
__be32 dst_ip = dst_in->sin_addr.s_addr;
@@ -243,36 +246,23 @@ static int addr4_resolve(struct sockaddr_in *src_in,
243246
src_in->sin_family = AF_INET;
244247
src_in->sin_addr.s_addr = fl4.saddr;
245248

246-
if (rt->dst.dev->flags & IFF_LOOPBACK) {
247-
ret = rdma_translate_ip((struct sockaddr *)dst_in, addr, NULL);
248-
if (!ret)
249-
memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN);
250-
goto put;
251-
}
252-
253-
/* If the device does ARP internally, return 'done' */
254-
if (rt->dst.dev->flags & IFF_NOARP) {
255-
ret = rdma_copy_addr(addr, rt->dst.dev, NULL);
256-
goto put;
257-
}
258-
259249
/* If there's a gateway, we're definitely in RoCE v2 (as RoCE v1 isn't
260250
* routable) and we could set the network type accordingly.
261251
*/
262252
if (rt->rt_uses_gateway)
263253
addr->network = RDMA_NETWORK_IPV4;
264254

265-
ret = dst_fetch_ha(&rt->dst, addr, &fl4.daddr);
266-
put:
267-
ip_rt_put(rt);
255+
*prt = rt;
256+
return 0;
268257
out:
269258
return ret;
270259
}
271260

272261
#if IS_ENABLED(CONFIG_IPV6)
273262
static int addr6_resolve(struct sockaddr_in6 *src_in,
274-
struct sockaddr_in6 *dst_in,
275-
struct rdma_dev_addr *addr)
263+
const struct sockaddr_in6 *dst_in,
264+
struct rdma_dev_addr *addr,
265+
struct dst_entry **pdst)
276266
{
277267
struct flowi6 fl6;
278268
struct dst_entry *dst;
@@ -299,49 +289,109 @@ static int addr6_resolve(struct sockaddr_in6 *src_in,
299289
src_in->sin6_addr = fl6.saddr;
300290
}
301291

302-
if (dst->dev->flags & IFF_LOOPBACK) {
303-
ret = rdma_translate_ip((struct sockaddr *)dst_in, addr, NULL);
304-
if (!ret)
305-
memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN);
306-
goto put;
307-
}
308-
309-
/* If the device does ARP internally, return 'done' */
310-
if (dst->dev->flags & IFF_NOARP) {
311-
ret = rdma_copy_addr(addr, dst->dev, NULL);
312-
goto put;
313-
}
314-
315292
/* If there's a gateway, we're definitely in RoCE v2 (as RoCE v1 isn't
316293
* routable) and we could set the network type accordingly.
317294
*/
318295
if (rt->rt6i_flags & RTF_GATEWAY)
319296
addr->network = RDMA_NETWORK_IPV6;
320297

321-
ret = dst_fetch_ha(dst, addr, &fl6.daddr);
298+
*pdst = dst;
299+
return 0;
322300
put:
323301
dst_release(dst);
324302
return ret;
325303
}
326304
#else
327305
static int addr6_resolve(struct sockaddr_in6 *src_in,
328-
struct sockaddr_in6 *dst_in,
329-
struct rdma_dev_addr *addr)
306+
const struct sockaddr_in6 *dst_in,
307+
struct rdma_dev_addr *addr,
308+
struct dst_entry **pdst)
330309
{
331310
return -EADDRNOTAVAIL;
332311
}
333312
#endif
334313

314+
static int addr_resolve_neigh(struct dst_entry *dst,
315+
const struct sockaddr *dst_in,
316+
struct rdma_dev_addr *addr)
317+
{
318+
if (dst->dev->flags & IFF_LOOPBACK) {
319+
int ret;
320+
321+
ret = rdma_translate_ip(dst_in, addr, NULL);
322+
if (!ret)
323+
memcpy(addr->dst_dev_addr, addr->src_dev_addr,
324+
MAX_ADDR_LEN);
325+
326+
return ret;
327+
}
328+
329+
/* If the device doesn't do ARP internally */
330+
if (!(dst->dev->flags & IFF_NOARP)) {
331+
const struct sockaddr_in *dst_in4 =
332+
(const struct sockaddr_in *)dst_in;
333+
const struct sockaddr_in6 *dst_in6 =
334+
(const struct sockaddr_in6 *)dst_in;
335+
336+
return dst_fetch_ha(dst, addr,
337+
dst_in->sa_family == AF_INET ?
338+
(const void *)&dst_in4->sin_addr.s_addr :
339+
(const void *)&dst_in6->sin6_addr);
340+
}
341+
342+
return rdma_copy_addr(addr, dst->dev, NULL);
343+
}
344+
335345
static int addr_resolve(struct sockaddr *src_in,
336-
struct sockaddr *dst_in,
337-
struct rdma_dev_addr *addr)
346+
const struct sockaddr *dst_in,
347+
struct rdma_dev_addr *addr,
348+
bool resolve_neigh)
338349
{
350+
struct net_device *ndev;
351+
struct dst_entry *dst;
352+
int ret;
353+
339354
if (src_in->sa_family == AF_INET) {
340-
return addr4_resolve((struct sockaddr_in *) src_in,
341-
(struct sockaddr_in *) dst_in, addr);
342-
} else
343-
return addr6_resolve((struct sockaddr_in6 *) src_in,
344-
(struct sockaddr_in6 *) dst_in, addr);
355+
struct rtable *rt = NULL;
356+
const struct sockaddr_in *dst_in4 =
357+
(const struct sockaddr_in *)dst_in;
358+
359+
ret = addr4_resolve((struct sockaddr_in *)src_in,
360+
dst_in4, addr, &rt);
361+
if (ret)
362+
return ret;
363+
364+
if (resolve_neigh)
365+
ret = addr_resolve_neigh(&rt->dst, dst_in, addr);
366+
367+
ndev = rt->dst.dev;
368+
dev_hold(ndev);
369+
370+
ip_rt_put(rt);
371+
} else {
372+
const struct sockaddr_in6 *dst_in6 =
373+
(const struct sockaddr_in6 *)dst_in;
374+
375+
ret = addr6_resolve((struct sockaddr_in6 *)src_in,
376+
dst_in6, addr,
377+
&dst);
378+
if (ret)
379+
return ret;
380+
381+
if (resolve_neigh)
382+
ret = addr_resolve_neigh(dst, dst_in, addr);
383+
384+
ndev = dst->dev;
385+
dev_hold(ndev);
386+
387+
dst_release(dst);
388+
}
389+
390+
addr->bound_dev_if = ndev->ifindex;
391+
addr->net = dev_net(ndev);
392+
dev_put(ndev);
393+
394+
return ret;
345395
}
346396

347397
static void process_req(struct work_struct *work)
@@ -357,7 +407,8 @@ static void process_req(struct work_struct *work)
357407
if (req->status == -ENODATA) {
358408
src_in = (struct sockaddr *) &req->src_addr;
359409
dst_in = (struct sockaddr *) &req->dst_addr;
360-
req->status = addr_resolve(src_in, dst_in, req->addr);
410+
req->status = addr_resolve(src_in, dst_in, req->addr,
411+
true);
361412
if (req->status && time_after_eq(jiffies, req->timeout))
362413
req->status = -ETIMEDOUT;
363414
else if (req->status == -ENODATA)
@@ -417,7 +468,7 @@ int rdma_resolve_ip(struct rdma_addr_client *client,
417468
req->client = client;
418469
atomic_inc(&client->refcount);
419470

420-
req->status = addr_resolve(src_in, dst_in, addr);
471+
req->status = addr_resolve(src_in, dst_in, addr, true);
421472
switch (req->status) {
422473
case 0:
423474
req->timeout = jiffies;
@@ -439,6 +490,25 @@ int rdma_resolve_ip(struct rdma_addr_client *client,
439490
}
440491
EXPORT_SYMBOL(rdma_resolve_ip);
441492

493+
int rdma_resolve_ip_route(struct sockaddr *src_addr,
494+
const struct sockaddr *dst_addr,
495+
struct rdma_dev_addr *addr)
496+
{
497+
struct sockaddr_storage ssrc_addr = {};
498+
struct sockaddr *src_in = (struct sockaddr *)&ssrc_addr;
499+
500+
if (src_addr->sa_family != dst_addr->sa_family)
501+
return -EINVAL;
502+
503+
if (src_addr)
504+
memcpy(src_in, src_addr, rdma_addr_size(src_addr));
505+
else
506+
src_in->sa_family = dst_addr->sa_family;
507+
508+
return addr_resolve(src_in, dst_addr, addr, false);
509+
}
510+
EXPORT_SYMBOL(rdma_resolve_ip_route);
511+
442512
void rdma_addr_cancel(struct rdma_dev_addr *addr)
443513
{
444514
struct addr_req *req, *temp_req;
@@ -471,7 +541,7 @@ static void resolve_cb(int status, struct sockaddr *src_addr,
471541
}
472542

473543
int rdma_addr_find_dmac_by_grh(const union ib_gid *sgid, const union ib_gid *dgid,
474-
u8 *dmac, u16 *vlan_id, int if_index)
544+
u8 *dmac, u16 *vlan_id, int *if_index)
475545
{
476546
int ret = 0;
477547
struct rdma_dev_addr dev_addr;
@@ -489,7 +559,8 @@ int rdma_addr_find_dmac_by_grh(const union ib_gid *sgid, const union ib_gid *dgi
489559
rdma_gid2ip(&dgid_addr._sockaddr, dgid);
490560

491561
memset(&dev_addr, 0, sizeof(dev_addr));
492-
dev_addr.bound_dev_if = if_index;
562+
if (if_index)
563+
dev_addr.bound_dev_if = *if_index;
493564
dev_addr.net = &init_net;
494565

495566
ctx.addr = &dev_addr;
@@ -505,6 +576,8 @@ int rdma_addr_find_dmac_by_grh(const union ib_gid *sgid, const union ib_gid *dgi
505576
dev = dev_get_by_index(&init_net, dev_addr.bound_dev_if);
506577
if (!dev)
507578
return -ENODEV;
579+
if (if_index)
580+
*if_index = dev_addr.bound_dev_if;
508581
if (vlan_id)
509582
*vlan_id = rdma_vlan_dev_vlan_id(dev);
510583
dev_put(dev);

drivers/infiniband/core/cm.c

+8-2
Original file line numberDiff line numberDiff line change
@@ -1646,8 +1646,11 @@ static int cm_req_handler(struct cm_work *work)
16461646
cm_id_priv->av.ah_attr.grh.sgid_index,
16471647
&gid, &gid_attr);
16481648
if (!ret) {
1649-
if (gid_attr.ndev)
1649+
if (gid_attr.ndev) {
1650+
work->path[0].ifindex = gid_attr.ndev->ifindex;
1651+
work->path[0].net = dev_net(gid_attr.ndev);
16501652
dev_put(gid_attr.ndev);
1653+
}
16511654
work->path[0].gid_type = gid_attr.gid_type;
16521655
ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av);
16531656
}
@@ -1656,8 +1659,11 @@ static int cm_req_handler(struct cm_work *work)
16561659
work->port->port_num, 0,
16571660
&work->path[0].sgid,
16581661
&gid_attr);
1659-
if (!err && gid_attr.ndev)
1662+
if (!err && gid_attr.ndev) {
1663+
work->path[0].ifindex = gid_attr.ndev->ifindex;
1664+
work->path[0].net = dev_net(gid_attr.ndev);
16601665
dev_put(gid_attr.ndev);
1666+
}
16611667
work->path[0].gid_type = gid_attr.gid_type;
16621668
ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_GID,
16631669
&work->path[0].sgid, sizeof work->path[0].sgid,

drivers/infiniband/core/cma.c

+28-2
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,20 @@ static inline int cma_validate_port(struct ib_device *device, u8 port,
454454
if ((dev_type != ARPHRD_INFINIBAND) && rdma_protocol_ib(device, port))
455455
return ret;
456456

457-
if (dev_type == ARPHRD_ETHER)
457+
if (dev_type == ARPHRD_ETHER) {
458458
ndev = dev_get_by_index(&init_net, bound_if_index);
459+
if (ndev && ndev->flags & IFF_LOOPBACK) {
460+
pr_info("detected loopback device\n");
461+
dev_put(ndev);
462+
463+
if (!device->get_netdev)
464+
return -EOPNOTSUPP;
465+
466+
ndev = device->get_netdev(device, port);
467+
if (!ndev)
468+
return -ENODEV;
469+
}
470+
}
459471

460472
ret = ib_find_cached_gid_by_port(device, gid, IB_GID_TYPE_IB, port,
461473
ndev, NULL);
@@ -2314,8 +2326,22 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
23142326

23152327
if (addr->dev_addr.bound_dev_if) {
23162328
ndev = dev_get_by_index(&init_net, addr->dev_addr.bound_dev_if);
2329+
if (!ndev)
2330+
return -ENODEV;
2331+
2332+
if (ndev->flags & IFF_LOOPBACK) {
2333+
dev_put(ndev);
2334+
if (!id_priv->id.device->get_netdev)
2335+
return -EOPNOTSUPP;
2336+
2337+
ndev = id_priv->id.device->get_netdev(id_priv->id.device,
2338+
id_priv->id.port_num);
2339+
if (!ndev)
2340+
return -ENODEV;
2341+
}
2342+
23172343
route->path_rec->net = &init_net;
2318-
route->path_rec->ifindex = addr->dev_addr.bound_dev_if;
2344+
route->path_rec->ifindex = ndev->ifindex;
23192345
route->path_rec->gid_type = id_priv->gid_type;
23202346
}
23212347
if (!ndev) {

0 commit comments

Comments
 (0)