[PATCH OpenHarmony-4.19 0/6] OpenHarmony-4.19 cve bugfix 0812

There are cves based on OpenHarmony-4.19 as follows: CVE-2021-33909 CVE-2021-3655 Eric Sandeen (1): seq_file: disallow extremely large seq buffer allocations Marcelo Ricardo Leitner (5): sctp: validate from_addr_param return sctp: add size validation when walking chunks sctp: fix return value check in __sctp_rcv_asconf_lookup sctp: add param size validation for SCTP_PARAM_SET_PRIMARY sctp: validate chunk size in __rcv_asconf_lookup fs/seq_file.c | 3 +++ include/net/sctp/structs.h | 2 +- net/sctp/bind_addr.c | 19 +++++++++-------- net/sctp/input.c | 11 +++++++--- net/sctp/ipv6.c | 7 ++++++- net/sctp/protocol.c | 7 ++++++- net/sctp/sm_make_chunk.c | 42 +++++++++++++++++++++++--------------- 7 files changed, 61 insertions(+), 30 deletions(-) -- 2.22.0

From: Eric Sandeen <sandeen@redhat.com> stable inclusion from linux-4.19.198 commit 6de9f0bf7cacc772a618699f9ed5c9f6fca58a1d category: bugfix issue: #I45880 CVE: CVE-2021-33909 -------------------------------- commit 8cae8cd89f05f6de223d63e6d15e31c8ba9cf53b upstream. There is no reasonable need for a buffer larger than this, and it avoids int overflow pitfalls. Fixes: 058504edd026 ("fs/seq_file: fallback to vmalloc allocation") Suggested-by: Al Viro <viro@zeniv.linux.org.uk> Reported-by: Qualys Security Advisory <qsa@qualys.com> Signed-off-by: Eric Sandeen <sandeen@redhat.com> Cc: stable@kernel.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> Signed-off-by: Yu Changchun <yuchangchun1@huawei.com> --- fs/seq_file.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/seq_file.c b/fs/seq_file.c index 05e58b56f620..e11f62b29be8 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -29,6 +29,9 @@ static void seq_set_overflow(struct seq_file *m) static void *seq_buf_alloc(unsigned long size) { + if (unlikely(size > MAX_RW_COUNT)) + return NULL; + return kvmalloc(size, GFP_KERNEL_ACCOUNT); } -- 2.22.0

From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> stable inclusion from linux-4.19.198 commit c7a03ebace4f9cd40d9cd9dd5fb2af558025583c category: bugfix issue: #I4589I CVE: NA -------------------------------- [ Upstream commit 0c5dc070ff3d6246d22ddd931f23a6266249e3db ] 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: Sasha Levin <sashal@kernel.org> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> Signed-off-by: Yu Changchun <yuchangchun1@huawei.com> --- include/net/sctp/structs.h | 2 +- net/sctp/bind_addr.c | 19 +++++++++++-------- 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(+), 26 deletions(-) diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 19f8d5881b08..2882bc7a5b4b 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -474,7 +474,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 *, diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index 38d01cfb313e..f8a283245672 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c @@ -285,22 +285,19 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list, 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); if (sctp_bind_addr_state(bp, &addr) != -1) goto next; retval = sctp_add_bind_addr(bp, &addr, sizeof(addr), SCTP_ADDR_SRC, gfp); - if (retval) { + if (retval) /* Can't finish building the list, clean up. */ - sctp_bind_addr_clean(bp); - break; - } + goto out_err; next: len = ntohs(param->length); @@ -309,6 +306,12 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list, } return retval; + +out_err: + if (retval) + sctp_bind_addr_clean(bp); + + return retval; } /******************************************************************** diff --git a/net/sctp/input.c b/net/sctp/input.c index f64d882c8698..628f9d22f527 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -1088,7 +1088,8 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct net *net, 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, transportp); if (asoc) @@ -1131,7 +1132,8 @@ static struct sctp_association *__sctp_rcv_asconf_lookup( 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); } diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 736d8ca9821b..58f995aa00b6 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -542,15 +542,20 @@ static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk) } /* 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 diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index af054f38341b..dd5125658255 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -268,14 +268,19 @@ static void sctp_v4_to_sk_daddr(union sctp_addr *addr, struct sock *sk) } /* 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 diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index ce6053be60bc..d87cd60c216e 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -2352,11 +2352,13 @@ int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk, /* 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; } @@ -2537,7 +2539,8 @@ static int sctp_process_param(struct sctp_association *asoc, 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)) @@ -2634,15 +2637,13 @@ static int sctp_process_param(struct sctp_association *asoc, addr_param = param.v + sizeof(struct sctp_addip_param); 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; @@ -3059,7 +3060,8 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, 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. @@ -3336,7 +3338,8 @@ static void sctp_asconf_param_success(struct sctp_association *asoc, /* 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: -- 2.22.0

From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> stable inclusion from linux-4.19.198 commit dd16e38e1531258d332b0fc7c247367f60c6c381 category: bugfix issue: #I4589I CVE: NA -------------------------------- [ Upstream commit 50619dbf8db77e98d821d615af4f634d08e22698 ] The first chunk in a packet is ensured to be present at the beginning of sctp_rcv(), as a packet needs to have at least 1 chunk. But the second one, may not be completely available and ch->length can be over uninitialized memory. Fix here is by only trying to walk on the next chunk if there is enough to hold at least the header, and then proceed with the ch->length validation that is already there. 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: Sasha Levin <sashal@kernel.org> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> Signed-off-by: Yu Changchun <yuchangchun1@huawei.com> --- net/sctp/input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/input.c b/net/sctp/input.c index 628f9d22f527..a0baf35e453a 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -1204,7 +1204,7 @@ static struct sctp_association *__sctp_rcv_walk_lookup(struct net *net, ch = (struct sctp_chunkhdr *)ch_end; chunk_num++; - } while (ch_end < skb_tail_pointer(skb)); + } while (ch_end + sizeof(*ch) < skb_tail_pointer(skb)); return asoc; } -- 2.22.0

From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> stable inclusion from linux-4.19.201 commit d9b6f0a200bef5fb9ba00e4e7d0d51f0b0fa5c6f category: bugfix issue: #I4589I CVE: NA -------------------------------- [ Upstream commit 557fb5862c9272ad9b21407afe1da8acfd9b53eb ] As Ben Hutchings noticed, this check should have been inverted: the call returns true in case of success. Reported-by: Ben Hutchings <ben@decadent.org.uk> Fixes: 0c5dc070ff3d ("sctp: validate from_addr_param return") Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Reviewed-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> Signed-off-by: Yu Changchun <yuchangchun1@huawei.com> --- net/sctp/input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/input.c b/net/sctp/input.c index a0baf35e453a..07bd59a98205 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -1132,7 +1132,7 @@ static struct sctp_association *__sctp_rcv_asconf_lookup( if (unlikely(!af)) return NULL; - if (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); -- 2.22.0

From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> mainline inclusion from mainline-v5.14-rc1 commit ef6c8d6ccf0c1dccdda092ebe8782777cd7803c9 category: bugfix issue: #I4589I CVE: CVE-2021-3655 --------------------------- When SCTP handles an INIT chunk, it calls for example: sctp_sf_do_5_1B_init sctp_verify_init sctp_verify_param sctp_process_init sctp_process_param handling of SCTP_PARAM_SET_PRIMARY sctp_verify_init() wasn't doing proper size validation and neither the later handling, allowing it to work over the chunk itself, possibly being uninitialized memory. Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> Conflicts: net/sctp/sm_make_chunk.c [yyl: asconf_enable is not added in kernel-4.19] Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> Reviewed-by: Xiu Jianfeng <xiujianfeng@huawei.com> Reviewed-by: Yue Haibing <yuehaibing@huawei.com> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> Signed-off-by: Yu Changchun <yuchangchun1@huawei.com> --- net/sctp/sm_make_chunk.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index d87cd60c216e..39bc0683d57e 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -2172,9 +2172,16 @@ static enum sctp_ierror sctp_verify_param(struct net *net, break; case SCTP_PARAM_SET_PRIMARY: - if (net->sctp.addip_enable) - break; - goto fallthrough; + if (!net->sctp.addip_enable) + goto fallthrough; + + if (ntohs(param.p->length) < sizeof(struct sctp_addip_param) + + sizeof(struct sctp_paramhdr)) { + sctp_process_inv_paramlength(asoc, param.p, + chunk, err_chunk); + retval = SCTP_IERROR_ABORT; + } + break; case SCTP_PARAM_HOST_NAME_ADDRESS: /* Tell the peer, we won't support this param. */ -- 2.22.0

From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> mainline inclusion from mainline-v5.14-rc1 commit b6ffe7671b24689c09faa5675dd58f93758a97ae category: bugfix issue: #I4589I CVE: CVE-2021-3655 --------------------------- In one of the fallbacks that SCTP has for identifying an association for an incoming packet, it looks for AddIp chunk (from ASCONF) and take a peek. Thing is, at this stage nothing was validating that the chunk actually had enough content for that, allowing the peek to happen over uninitialized memory. Similar check already exists in actual asconf handling in sctp_verify_asconf(). Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> Reviewed-by: Xiu Jianfeng <xiujianfeng@huawei.com> Reviewed-by: Yue Haibing <yuehaibing@huawei.com> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> Signed-off-by: Yu Changchun <yuchangchun1@huawei.com> --- net/sctp/input.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/sctp/input.c b/net/sctp/input.c index 07bd59a98205..0b09f296df2d 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -1125,6 +1125,9 @@ static struct sctp_association *__sctp_rcv_asconf_lookup( union sctp_addr_param *param; union sctp_addr paddr; + if (ntohs(ch->length) < sizeof(*asconf) + sizeof(struct sctp_paramhdr)) + return NULL; + /* Skip over the ADDIP header and find the Address parameter */ param = (union sctp_addr_param *)(asconf + 1); -- 2.22.0
participants (1)
-
Yu Changchun