aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorNeal Cardwell <ncardwell@google.com>2012-12-08 14:43:23 -0500
committerDavid S. Miller <davem@davemloft.net>2012-12-09 18:59:37 -0500
commitf67caec9068cee426ec23cf9005a1dee2ecad187 (patch)
treef1096bdda02c0d95e02cfb1ee1b3f53c21a24fa1 /net/ipv4
parent405c005949e47b6e91359159c24753519ded0c67 (diff)
inet_diag: avoid unsafe and nonsensical prefix matches in inet_diag_bc_run()
Add logic to check the address family of the user-supplied conditional and the address family of the connection entry. We now do not do prefix matching of addresses from different address families (AF_INET vs AF_INET6), except for the previously existing support for having an IPv4 prefix match an IPv4-mapped IPv6 address (which this commit maintains as-is). This change is needed for two reasons: (1) The addresses are different lengths, so comparing a 128-bit IPv6 prefix match condition to a 32-bit IPv4 connection address can cause us to unwittingly walk off the end of the IPv4 address and read garbage or oops. (2) The IPv4 and IPv6 address spaces are semantically distinct, so a simple bit-wise comparison of the prefixes is not meaningful, and would lead to bogus results (except for the IPv4-mapped IPv6 case, which this commit maintains). Signed-off-by: Neal Cardwell <ncardwell@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/inet_diag.c28
1 files changed, 17 insertions, 11 deletions
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 529747d07a2a..95f1a458371d 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -432,25 +432,31 @@ static int inet_diag_bc_run(const struct nlattr *_bc,
432 break; 432 break;
433 } 433 }
434 434
435 if (cond->prefix_len == 0)
436 break;
437
438 if (op->code == INET_DIAG_BC_S_COND) 435 if (op->code == INET_DIAG_BC_S_COND)
439 addr = entry->saddr; 436 addr = entry->saddr;
440 else 437 else
441 addr = entry->daddr; 438 addr = entry->daddr;
442 439
440 if (cond->family != AF_UNSPEC &&
441 cond->family != entry->family) {
442 if (entry->family == AF_INET6 &&
443 cond->family == AF_INET) {
444 if (addr[0] == 0 && addr[1] == 0 &&
445 addr[2] == htonl(0xffff) &&
446 bitstring_match(addr + 3,
447 cond->addr,
448 cond->prefix_len))
449 break;
450 }
451 yes = 0;
452 break;
453 }
454
455 if (cond->prefix_len == 0)
456 break;
443 if (bitstring_match(addr, cond->addr, 457 if (bitstring_match(addr, cond->addr,
444 cond->prefix_len)) 458 cond->prefix_len))
445 break; 459 break;
446 if (entry->family == AF_INET6 &&
447 cond->family == AF_INET) {
448 if (addr[0] == 0 && addr[1] == 0 &&
449 addr[2] == htonl(0xffff) &&
450 bitstring_match(addr + 3, cond->addr,
451 cond->prefix_len))
452 break;
453 }
454 yes = 0; 460 yes = 0;
455 break; 461 break;
456 } 462 }