]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 24 Sep 2021 12:41:27 +0000 (14:41 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 24 Sep 2021 12:41:27 +0000 (14:41 +0200)
added patches:
sctp-validate-from_addr_param-return.patch

queue-4.4/sctp-validate-from_addr_param-return.patch [new file with mode: 0644]
queue-4.4/series

diff --git a/queue-4.4/sctp-validate-from_addr_param-return.patch b/queue-4.4/sctp-validate-from_addr_param-return.patch
new file mode 100644 (file)
index 0000000..e43020d
--- /dev/null
@@ -0,0 +1,222 @@
+From 0c5dc070ff3d6246d22ddd931f23a6266249e3db Mon Sep 17 00:00:00 2001
+From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+Date: Mon, 28 Jun 2021 16:13:41 -0300
+Subject: sctp: validate from_addr_param return
+
+From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+
+commit 0c5dc070ff3d6246d22ddd931f23a6266249e3db upstream.
+
+Ilja reported that, simply putting it, nothing was validating that
+from_addr_param functions were operating on initialized memory. That is,
+the parameter itself was being validated by sctp_walk_params, but it
+doesn't check for types and their specific sizes and it could be a 0-length
+one, causing from_addr_param to potentially work over the next parameter or
+even uninitialized memory.
+
+The fix here is to, in all calls to from_addr_param, check if enough space
+is there for the wanted IP address type.
+
+Reported-by: Ilja Van Sprundel <ivansprundel@ioactive.com>
+Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/sctp/structs.h |    2 +-
+ net/sctp/bind_addr.c       |   20 +++++++++++---------
+ net/sctp/input.c           |    6 ++++--
+ net/sctp/ipv6.c            |    7 ++++++-
+ net/sctp/protocol.c        |    7 ++++++-
+ net/sctp/sm_make_chunk.c   |   29 ++++++++++++++++-------------
+ 6 files changed, 44 insertions(+), 27 deletions(-)
+
+--- a/include/net/sctp/structs.h
++++ b/include/net/sctp/structs.h
+@@ -469,7 +469,7 @@ struct sctp_af {
+                                        int saddr);
+       void            (*from_sk)      (union sctp_addr *,
+                                        struct sock *sk);
+-      void            (*from_addr_param) (union sctp_addr *,
++      bool            (*from_addr_param) (union sctp_addr *,
+                                           union sctp_addr_param *,
+                                           __be16 port, int iif);
+       int             (*to_addr_param) (const union sctp_addr *,
+--- a/net/sctp/bind_addr.c
++++ b/net/sctp/bind_addr.c
+@@ -284,19 +284,15 @@ int sctp_raw_to_bind_addrs(struct sctp_b
+               rawaddr = (union sctp_addr_param *)raw_addr_list;
+               af = sctp_get_af_specific(param_type2af(param->type));
+-              if (unlikely(!af)) {
++              if (unlikely(!af) ||
++                  !af->from_addr_param(&addr, rawaddr, htons(port), 0)) {
+                       retval = -EINVAL;
+-                      sctp_bind_addr_clean(bp);
+-                      break;
++                      goto out_err;
+               }
+-              af->from_addr_param(&addr, rawaddr, htons(port), 0);
+               retval = sctp_add_bind_addr(bp, &addr, SCTP_ADDR_SRC, gfp);
+-              if (retval) {
+-                      /* Can't finish building the list, clean up. */
+-                      sctp_bind_addr_clean(bp);
+-                      break;
+-              }
++              if (retval)
++                      goto out_err;
+               len = ntohs(param->length);
+               addrs_len -= len;
+@@ -304,6 +300,12 @@ int sctp_raw_to_bind_addrs(struct sctp_b
+       }
+       return retval;
++
++out_err:
++      if (retval)
++              sctp_bind_addr_clean(bp);
++
++      return retval;
+ }
+ /********************************************************************
+--- a/net/sctp/input.c
++++ b/net/sctp/input.c
+@@ -972,7 +972,8 @@ static struct sctp_association *__sctp_r
+               if (!af)
+                       continue;
+-              af->from_addr_param(paddr, params.addr, sh->source, 0);
++              if (!af->from_addr_param(paddr, params.addr, sh->source, 0))
++                      continue;
+               asoc = __sctp_lookup_association(net, laddr, paddr, &transport);
+               if (asoc)
+@@ -1018,7 +1019,8 @@ static struct sctp_association *__sctp_r
+       if (unlikely(!af))
+               return NULL;
+-      af->from_addr_param(&paddr, param, peer_port, 0);
++      if (af->from_addr_param(&paddr, param, peer_port, 0))
++              return NULL;
+       return __sctp_lookup_association(net, laddr, &paddr, transportp);
+ }
+--- a/net/sctp/ipv6.c
++++ b/net/sctp/ipv6.c
+@@ -488,15 +488,20 @@ static void sctp_v6_to_sk_daddr(union sc
+ }
+ /* Initialize a sctp_addr from an address parameter. */
+-static void sctp_v6_from_addr_param(union sctp_addr *addr,
++static bool sctp_v6_from_addr_param(union sctp_addr *addr,
+                                   union sctp_addr_param *param,
+                                   __be16 port, int iif)
+ {
++      if (ntohs(param->v6.param_hdr.length) < sizeof(struct sctp_ipv6addr_param))
++              return false;
++
+       addr->v6.sin6_family = AF_INET6;
+       addr->v6.sin6_port = port;
+       addr->v6.sin6_flowinfo = 0; /* BUG */
+       addr->v6.sin6_addr = param->v6.addr;
+       addr->v6.sin6_scope_id = iif;
++
++      return true;
+ }
+ /* Initialize an address parameter from a sctp_addr and return the length
+--- a/net/sctp/protocol.c
++++ b/net/sctp/protocol.c
+@@ -272,14 +272,19 @@ static void sctp_v4_to_sk_daddr(union sc
+ }
+ /* Initialize a sctp_addr from an address parameter. */
+-static void sctp_v4_from_addr_param(union sctp_addr *addr,
++static bool sctp_v4_from_addr_param(union sctp_addr *addr,
+                                   union sctp_addr_param *param,
+                                   __be16 port, int iif)
+ {
++      if (ntohs(param->v4.param_hdr.length) < sizeof(struct sctp_ipv4addr_param))
++              return false;
++
+       addr->v4.sin_family = AF_INET;
+       addr->v4.sin_port = port;
+       addr->v4.sin_addr.s_addr = param->v4.addr.s_addr;
+       memset(addr->v4.sin_zero, 0, sizeof(addr->v4.sin_zero));
++
++      return true;
+ }
+ /* Initialize an address parameter from a sctp_addr and return the length
+--- a/net/sctp/sm_make_chunk.c
++++ b/net/sctp/sm_make_chunk.c
+@@ -2333,11 +2333,13 @@ int sctp_process_init(struct sctp_associ
+       /* Process the initialization parameters.  */
+       sctp_walk_params(param, peer_init, init_hdr.params) {
+-              if (!src_match && (param.p->type == SCTP_PARAM_IPV4_ADDRESS ||
+-                  param.p->type == SCTP_PARAM_IPV6_ADDRESS)) {
++              if (!src_match &&
++                  (param.p->type == SCTP_PARAM_IPV4_ADDRESS ||
++                   param.p->type == SCTP_PARAM_IPV6_ADDRESS)) {
+                       af = sctp_get_af_specific(param_type2af(param.p->type));
+-                      af->from_addr_param(&addr, param.addr,
+-                                          chunk->sctp_hdr->source, 0);
++                      if (!af->from_addr_param(&addr, param.addr,
++                                               chunk->sctp_hdr->source, 0))
++                              continue;
+                       if (sctp_cmp_addr_exact(sctp_source(chunk), &addr))
+                               src_match = 1;
+               }
+@@ -2531,7 +2533,8 @@ static int sctp_process_param(struct sct
+                       break;
+ do_addr_param:
+               af = sctp_get_af_specific(param_type2af(param.p->type));
+-              af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0);
++              if (!af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0))
++                      break;
+               scope = sctp_scope(peer_addr);
+               if (sctp_in_scope(net, &addr, scope))
+                       if (!sctp_assoc_add_peer(asoc, &addr, gfp, SCTP_UNCONFIRMED))
+@@ -2624,15 +2627,13 @@ do_addr_param:
+               addr_param = param.v + sizeof(sctp_addip_param_t);
+               af = sctp_get_af_specific(param_type2af(addr_param->p.type));
+-              if (af == NULL)
++              if (!af)
+                       break;
+-              af->from_addr_param(&addr, addr_param,
+-                                  htons(asoc->peer.port), 0);
++              if (!af->from_addr_param(&addr, addr_param,
++                                       htons(asoc->peer.port), 0))
++                      break;
+-              /* if the address is invalid, we can't process it.
+-               * XXX: see spec for what to do.
+-               */
+               if (!af->addr_valid(&addr, NULL, NULL))
+                       break;
+@@ -3042,7 +3043,8 @@ static __be16 sctp_process_asconf_param(
+       if (unlikely(!af))
+               return SCTP_ERROR_DNS_FAILED;
+-      af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0);
++      if (!af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0))
++              return SCTP_ERROR_DNS_FAILED;
+       /* ADDIP 4.2.1  This parameter MUST NOT contain a broadcast
+        * or multicast address.
+@@ -3308,7 +3310,8 @@ static void sctp_asconf_param_success(st
+       /* We have checked the packet before, so we do not check again. */
+       af = sctp_get_af_specific(param_type2af(addr_param->p.type));
+-      af->from_addr_param(&addr, addr_param, htons(bp->port), 0);
++      if (!af->from_addr_param(&addr, addr_param, htons(bp->port), 0))
++              return;
+       switch (asconf_param->param_hdr.type) {
+       case SCTP_PARAM_ADD_IP:
index 6fd96741e4046d829394805dbbf32e549409a909..fe3f3d71bf296d8f3e75a55d9d3b22e783ef6466 100644 (file)
@@ -20,3 +20,4 @@ nilfs2-fix-memory-leak-in-nilfs_sysfs_create_snapsho.patch
 nilfs2-fix-memory-leak-in-nilfs_sysfs_delete_snapsho.patch
 blk-throttle-fix-uaf-by-deleteing-timer-in-blk_throt.patch
 drm-nouveau-nvkm-replace-enosys-with-enodev.patch
+sctp-validate-from_addr_param-return.patch