Commit 7cc9150ebe8ec06cafea9f1c10d92ddacf88d8ae

Authored by Flavio Leitner
Committed by David S. Miller
1 parent da92b194cc

route: fix ICMP redirect validation

The commit f39925dbde7788cfb96419c0f092b086aa325c0f
(ipv4: Cache learned redirect information in inetpeer.)
removed some ICMP packet validations which are required by
RFC 1122, section 3.2.2.2:
...
  A Redirect message SHOULD be silently discarded if the new
  gateway address it specifies is not on the same connected
  (sub-) net through which the Redirect arrived [INTRO:2,
  Appendix A], or if the source of the Redirect is not the
  current first-hop gateway for the specified destination (see
  Section 3.3.1).

Signed-off-by: Flavio Leitner <fbl@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 1 changed file with 31 additions and 5 deletions Side-by-side Diff

... ... @@ -1309,7 +1309,12 @@
1309 1309 void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
1310 1310 __be32 saddr, struct net_device *dev)
1311 1311 {
  1312 + int s, i;
1312 1313 struct in_device *in_dev = __in_dev_get_rcu(dev);
  1314 + struct rtable *rt;
  1315 + __be32 skeys[2] = { saddr, 0 };
  1316 + int ikeys[2] = { dev->ifindex, 0 };
  1317 + struct flowi4 fl4;
1313 1318 struct inet_peer *peer;
1314 1319 struct net *net;
1315 1320  
1316 1321  
1317 1322  
... ... @@ -1332,13 +1337,34 @@
1332 1337 goto reject_redirect;
1333 1338 }
1334 1339  
1335   - peer = inet_getpeer_v4(daddr, 1);
1336   - if (peer) {
1337   - peer->redirect_learned.a4 = new_gw;
  1340 + memset(&fl4, 0, sizeof(fl4));
  1341 + fl4.daddr = daddr;
  1342 + for (s = 0; s < 2; s++) {
  1343 + for (i = 0; i < 2; i++) {
  1344 + fl4.flowi4_oif = ikeys[i];
  1345 + fl4.saddr = skeys[s];
  1346 + rt = __ip_route_output_key(net, &fl4);
  1347 + if (IS_ERR(rt))
  1348 + continue;
1338 1349  
1339   - inet_putpeer(peer);
  1350 + if (rt->dst.error || rt->dst.dev != dev ||
  1351 + rt->rt_gateway != old_gw) {
  1352 + ip_rt_put(rt);
  1353 + continue;
  1354 + }
1340 1355  
1341   - atomic_inc(&__rt_peer_genid);
  1356 + if (!rt->peer)
  1357 + rt_bind_peer(rt, rt->rt_dst, 1);
  1358 +
  1359 + peer = rt->peer;
  1360 + if (peer) {
  1361 + peer->redirect_learned.a4 = new_gw;
  1362 + atomic_inc(&__rt_peer_genid);
  1363 + }
  1364 +
  1365 + ip_rt_put(rt);
  1366 + return;
  1367 + }
1342 1368 }
1343 1369 return;
1344 1370