From: Henry Ptasinski <hptasin...@google.com>

[ Upstream commit fe81d9f6182d1160e625894eecb3d7ff0222cac5 ]

When calculating ancestor_size with IPv6 enabled, simply using
sizeof(struct ipv6_pinfo) doesn't account for extra bytes needed for
alignment in the struct sctp6_sock. On x86, there aren't any extra
bytes, but on ARM the ipv6_pinfo structure is aligned on an 8-byte
boundary so there were 4 pad bytes that were omitted from the
ancestor_size calculation.  This would lead to corruption of the
pd_lobby pointers, causing an oops when trying to free the sctp
structure on socket close.

Fixes: 636d25d557d1 ("sctp: not copy sctp_sock pd_lobby in 
sctp_copy_descendant")
Signed-off-by: Henry Ptasinski <hptasin...@google.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leit...@gmail.com>
Signed-off-by: David S. Miller <da...@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>
---
 include/net/sctp/structs.h |    8 +++++---
 net/sctp/socket.c          |    9 +++------
 2 files changed, 8 insertions(+), 9 deletions(-)

--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -226,12 +226,14 @@ struct sctp_sock {
                data_ready_signalled:1;
 
        atomic_t pd_mode;
+
+       /* Fields after this point will be skipped on copies, like on accept
+        * and peeloff operations
+        */
+
        /* Receive to here while partial delivery is in effect. */
        struct sk_buff_head pd_lobby;
 
-       /* These must be the last fields, as they will skipped on copies,
-        * like on accept and peeloff operations
-        */
        struct list_head auto_asconf_list;
        int do_auto_asconf;
 };
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -9457,13 +9457,10 @@ void sctp_copy_sock(struct sock *newsk,
 static inline void sctp_copy_descendant(struct sock *sk_to,
                                        const struct sock *sk_from)
 {
-       int ancestor_size = sizeof(struct inet_sock) +
-                           sizeof(struct sctp_sock) -
-                           offsetof(struct sctp_sock, pd_lobby);
-
-       if (sk_from->sk_family == PF_INET6)
-               ancestor_size += sizeof(struct ipv6_pinfo);
+       size_t ancestor_size = sizeof(struct inet_sock);
 
+       ancestor_size += sk_from->sk_prot->obj_size;
+       ancestor_size -= offsetof(struct sctp_sock, pd_lobby);
        __inet_sk_copy_descendant(sk_to, sk_from, ancestor_size);
 }
 


Reply via email to