aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeal Cardwell <ncardwell@google.com>2012-12-08 14:43:21 -0500
committerDavid S. Miller <davem@davemloft.net>2012-12-09 18:59:37 -0500
commit1c95df85ca49640576de2f0a850925957b547b84 (patch)
treef39f7537be01cf536c4f125e0f3671dc83ddc04b
parented23ec4f0a510528e0ffe415f9394107418ae854 (diff)
inet_diag: fix oops for IPv4 AF_INET6 TCP SYN-RECV state
Fix inet_diag to be aware of the fact that AF_INET6 TCP connections instantiated for IPv4 traffic and in the SYN-RECV state were actually created with inet_reqsk_alloc(), instead of inet6_reqsk_alloc(). This means that for such connections inet6_rsk(req) returns a pointer to a random spot in memory up to roughly 64KB beyond the end of the request_sock. With this bug, for a server using AF_INET6 TCP sockets and serving IPv4 traffic, an inet_diag user like `ss state SYN-RECV` would lead to inet_diag_fill_req() causing an oops or the export to user space of 16 bytes of kernel memory as a garbage IPv6 address, depending on where the garbage inet6_rsk(req) pointed. Signed-off-by: Neal Cardwell <ncardwell@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/inet_diag.c53
1 files changed, 39 insertions, 14 deletions
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 0c34bfabc11f..16cfa42cfd99 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -44,6 +44,10 @@ struct inet_diag_entry {
44 u16 dport; 44 u16 dport;
45 u16 family; 45 u16 family;
46 u16 userlocks; 46 u16 userlocks;
47#if IS_ENABLED(CONFIG_IPV6)
48 struct in6_addr saddr_storage; /* for IPv4-mapped-IPv6 addresses */
49 struct in6_addr daddr_storage; /* for IPv4-mapped-IPv6 addresses */
50#endif
47}; 51};
48 52
49static DEFINE_MUTEX(inet_diag_table_mutex); 53static DEFINE_MUTEX(inet_diag_table_mutex);
@@ -596,6 +600,36 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
596 cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh); 600 cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
597} 601}
598 602
603/* Get the IPv4, IPv6, or IPv4-mapped-IPv6 local and remote addresses
604 * from a request_sock. For IPv4-mapped-IPv6 we must map IPv4 to IPv6.
605 */
606static inline void inet_diag_req_addrs(const struct sock *sk,
607 const struct request_sock *req,
608 struct inet_diag_entry *entry)
609{
610 struct inet_request_sock *ireq = inet_rsk(req);
611
612#if IS_ENABLED(CONFIG_IPV6)
613 if (sk->sk_family == AF_INET6) {
614 if (req->rsk_ops->family == AF_INET6) {
615 entry->saddr = inet6_rsk(req)->loc_addr.s6_addr32;
616 entry->daddr = inet6_rsk(req)->rmt_addr.s6_addr32;
617 } else if (req->rsk_ops->family == AF_INET) {
618 ipv6_addr_set_v4mapped(ireq->loc_addr,
619 &entry->saddr_storage);
620 ipv6_addr_set_v4mapped(ireq->rmt_addr,
621 &entry->daddr_storage);
622 entry->saddr = entry->saddr_storage.s6_addr32;
623 entry->daddr = entry->daddr_storage.s6_addr32;
624 }
625 } else
626#endif
627 {
628 entry->saddr = &ireq->loc_addr;
629 entry->daddr = &ireq->rmt_addr;
630 }
631}
632
599static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk, 633static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
600 struct request_sock *req, 634 struct request_sock *req,
601 struct user_namespace *user_ns, 635 struct user_namespace *user_ns,
@@ -637,8 +671,10 @@ static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
637 r->idiag_inode = 0; 671 r->idiag_inode = 0;
638#if IS_ENABLED(CONFIG_IPV6) 672#if IS_ENABLED(CONFIG_IPV6)
639 if (r->idiag_family == AF_INET6) { 673 if (r->idiag_family == AF_INET6) {
640 *(struct in6_addr *)r->id.idiag_src = inet6_rsk(req)->loc_addr; 674 struct inet_diag_entry entry;
641 *(struct in6_addr *)r->id.idiag_dst = inet6_rsk(req)->rmt_addr; 675 inet_diag_req_addrs(sk, req, &entry);
676 memcpy(r->id.idiag_src, entry.saddr, sizeof(struct in6_addr));
677 memcpy(r->id.idiag_dst, entry.daddr, sizeof(struct in6_addr));
642 } 678 }
643#endif 679#endif
644 680
@@ -691,18 +727,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
691 continue; 727 continue;
692 728
693 if (bc) { 729 if (bc) {
694 entry.saddr = 730 inet_diag_req_addrs(sk, req, &entry);
695#if IS_ENABLED(CONFIG_IPV6)
696 (entry.family == AF_INET6) ?
697 inet6_rsk(req)->loc_addr.s6_addr32 :
698#endif
699 &ireq->loc_addr;
700 entry.daddr =
701#if IS_ENABLED(CONFIG_IPV6)
702 (entry.family == AF_INET6) ?
703 inet6_rsk(req)->rmt_addr.s6_addr32 :
704#endif
705 &ireq->rmt_addr;
706 entry.dport = ntohs(ireq->rmt_port); 731 entry.dport = ntohs(ireq->rmt_port);
707 732
708 if (!inet_diag_bc_run(bc, &entry)) 733 if (!inet_diag_bc_run(bc, &entry))