| From foo@baz Tue Nov 21 13:07:02 CET 2017 |
| From: "Eric W. Biederman" <ebiederm@xmission.com> |
| Date: Wed, 15 Nov 2017 22:17:48 -0600 |
| Subject: net/sctp: Always set scope_id in sctp_inet6_skb_msgname |
| |
| From: "Eric W. Biederman" <ebiederm@xmission.com> |
| |
| |
| [ Upstream commit 7c8a61d9ee1df0fb4747879fa67a99614eb62fec ] |
| |
| Alexandar Potapenko while testing the kernel with KMSAN and syzkaller |
| discovered that in some configurations sctp would leak 4 bytes of |
| kernel stack. |
| |
| Working with his reproducer I discovered that those 4 bytes that |
| are leaked is the scope id of an ipv6 address returned by recvmsg. |
| |
| With a little code inspection and a shrewd guess I discovered that |
| sctp_inet6_skb_msgname only initializes the scope_id field for link |
| local ipv6 addresses to the interface index the link local address |
| pertains to instead of initializing the scope_id field for all ipv6 |
| addresses. |
| |
| That is almost reasonable as scope_id's are meaniningful only for link |
| local addresses. Set the scope_id in all other cases to 0 which is |
| not a valid interface index to make it clear there is nothing useful |
| in the scope_id field. |
| |
| There should be no danger of breaking userspace as the stack leak |
| guaranteed that previously meaningless random data was being returned. |
| |
| Fixes: 372f525b495c ("SCTP: Resync with LKSCTP tree.") |
| History-tree: https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git |
| Reported-by: Alexander Potapenko <glider@google.com> |
| Tested-by: Alexander Potapenko <glider@google.com> |
| Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/sctp/ipv6.c | 5 +++-- |
| 1 file changed, 3 insertions(+), 2 deletions(-) |
| |
| --- a/net/sctp/ipv6.c |
| +++ b/net/sctp/ipv6.c |
| @@ -807,9 +807,10 @@ static void sctp_inet6_skb_msgname(struc |
| addr->v6.sin6_flowinfo = 0; |
| addr->v6.sin6_port = sh->source; |
| addr->v6.sin6_addr = ipv6_hdr(skb)->saddr; |
| - if (ipv6_addr_type(&addr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) { |
| + if (ipv6_addr_type(&addr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) |
| addr->v6.sin6_scope_id = sctp_v6_skb_iif(skb); |
| - } |
| + else |
| + addr->v6.sin6_scope_id = 0; |
| } |
| |
| *addr_len = sctp_v6_addr_to_user(sctp_sk(skb->sk), addr); |