From d87931197d3bd989caf3b8a75c5ae3b6d80cca67 Mon Sep 17 00:00:00 2001 From: yangl777 Date: Mon, 28 Mar 2022 19:29:10 +0800 Subject: [PATCH] fix CVE-2022-22719 CVE-2022-22720 CVE-2022-22721 CVE-2022-23934 sync from 22.03 --- backport-001-CVE-2022-23934.patch | 358 ++++++++++++++++++++++++++++++ backport-002-CVE-2022-23934.patch | 61 +++++ backport-CVE-2022-22719.patch | 93 ++++++++ backport-CVE-2022-22720.patch | 187 ++++++++++++++++ backport-CVE-2022-22721.patch | 113 ++++++++++ httpd.spec | 17 +- 6 files changed, 826 insertions(+), 3 deletions(-) create mode 100644 backport-001-CVE-2022-23934.patch create mode 100644 backport-002-CVE-2022-23934.patch create mode 100644 backport-CVE-2022-22719.patch create mode 100644 backport-CVE-2022-22720.patch create mode 100644 backport-CVE-2022-22721.patch diff --git a/backport-001-CVE-2022-23934.patch b/backport-001-CVE-2022-23934.patch new file mode 100644 index 0000000..5556e8b --- /dev/null +++ b/backport-001-CVE-2022-23934.patch @@ -0,0 +1,358 @@ +From 943f57b336f264d77e5b780c82ab73daf3d14deb Mon Sep 17 00:00:00 2001 +From: Yann Ylavic +Date: Mon, 7 Mar 2022 14:52:42 +0000 +Subject: [PATCH] mod_sed: use size_t to allow for larger buffer sizes and + unsigned arithmetics. + +Let's switch to apr_size_t buffers and get rid of the ints. + + +Merge r1898690 from trunk. +Submitted by: rpluem +Reviewed by: rpluem, covener, ylavic + + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1898695 13f79535-47bb-0310-9956-ffa450edef68 +--- + modules/filters/libsed.h | 12 +++--- + modules/filters/mod_sed.c | 10 ++--- + modules/filters/sed1.c | 79 +++++++++++++++++++++++---------------- + 3 files changed, 58 insertions(+), 43 deletions(-) + +diff --git a/modules/filters/libsed.h b/modules/filters/libsed.h +index 76cbc0ce8ad..0256b1ea831 100644 +--- a/modules/filters/libsed.h ++++ b/modules/filters/libsed.h +@@ -60,7 +60,7 @@ struct sed_label_s { + }; + + typedef apr_status_t (sed_err_fn_t)(void *data, const char *error); +-typedef apr_status_t (sed_write_fn_t)(void *ctx, char *buf, int sz); ++typedef apr_status_t (sed_write_fn_t)(void *ctx, char *buf, apr_size_t sz); + + typedef struct sed_commands_s sed_commands_t; + #define NWFILES 11 /* 10 plus one for standard output */ +@@ -69,7 +69,7 @@ struct sed_commands_s { + sed_err_fn_t *errfn; + void *data; + +- unsigned lsize; ++ apr_size_t lsize; + char *linebuf; + char *lbend; + const char *saveq; +@@ -116,15 +116,15 @@ struct sed_eval_s { + apr_int64_t lnum; + void *fout; + +- unsigned lsize; ++ apr_size_t lsize; + char *linebuf; + char *lspend; + +- unsigned hsize; ++ apr_size_t hsize; + char *holdbuf; + char *hspend; + +- unsigned gsize; ++ apr_size_t gsize; + char *genbuf; + char *lcomend; + +@@ -160,7 +160,7 @@ apr_status_t sed_init_eval(sed_eval_t *eval, sed_commands_t *commands, + sed_err_fn_t *errfn, void *data, + sed_write_fn_t *writefn, apr_pool_t *p); + apr_status_t sed_reset_eval(sed_eval_t *eval, sed_commands_t *commands, sed_err_fn_t *errfn, void *data); +-apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void *fout); ++apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz, void *fout); + apr_status_t sed_eval_file(sed_eval_t *eval, apr_file_t *fin, void *fout); + apr_status_t sed_finalize_eval(sed_eval_t *eval, void *f); + void sed_destroy_eval(sed_eval_t *eval); +diff --git a/modules/filters/mod_sed.c b/modules/filters/mod_sed.c +index 9b408029a86..7092dd5e7f1 100644 +--- a/modules/filters/mod_sed.c ++++ b/modules/filters/mod_sed.c +@@ -51,7 +51,7 @@ typedef struct sed_filter_ctxt + apr_bucket_brigade *bbinp; + char *outbuf; + char *curoutbuf; +- int bufsize; ++ apr_size_t bufsize; + apr_pool_t *tpool; + int numbuckets; + } sed_filter_ctxt; +@@ -100,7 +100,7 @@ static void alloc_outbuf(sed_filter_ctxt* ctx) + /* append_bucket + * Allocate a new bucket from buf and sz and append to ctx->bb + */ +-static apr_status_t append_bucket(sed_filter_ctxt* ctx, char* buf, int sz) ++static apr_status_t append_bucket(sed_filter_ctxt* ctx, char* buf, apr_size_t sz) + { + apr_status_t status = APR_SUCCESS; + apr_bucket *b; +@@ -133,7 +133,7 @@ static apr_status_t append_bucket(sed_filter_ctxt* ctx, char* buf, int sz) + */ + static apr_status_t flush_output_buffer(sed_filter_ctxt *ctx) + { +- int size = ctx->curoutbuf - ctx->outbuf; ++ apr_size_t size = ctx->curoutbuf - ctx->outbuf; + char *out; + apr_status_t status = APR_SUCCESS; + if ((ctx->outbuf == NULL) || (size <=0)) +@@ -147,12 +147,12 @@ static apr_status_t flush_output_buffer(sed_filter_ctxt *ctx) + /* This is a call back function. When libsed wants to generate the output, + * this function will be invoked. + */ +-static apr_status_t sed_write_output(void *dummy, char *buf, int sz) ++static apr_status_t sed_write_output(void *dummy, char *buf, apr_size_t sz) + { + /* dummy is basically filter context. Context is passed during invocation + * of sed_eval_buffer + */ +- int remainbytes = 0; ++ apr_size_t remainbytes = 0; + apr_status_t status = APR_SUCCESS; + sed_filter_ctxt *ctx = (sed_filter_ctxt *) dummy; + if (ctx->outbuf == NULL) { +diff --git a/modules/filters/sed1.c b/modules/filters/sed1.c +index be035067885..67a8d06515e 100644 +--- a/modules/filters/sed1.c ++++ b/modules/filters/sed1.c +@@ -71,7 +71,7 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n, + static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2); + static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + step_vars_storage *step_vars); +-static apr_status_t wline(sed_eval_t *eval, char *buf, int sz); ++static apr_status_t wline(sed_eval_t *eval, char *buf, apr_size_t sz); + static apr_status_t arout(sed_eval_t *eval); + + static void eval_errf(sed_eval_t *eval, const char *fmt, ...) +@@ -92,11 +92,11 @@ static void eval_errf(sed_eval_t *eval, const char *fmt, ...) + * grow_buffer + */ + static void grow_buffer(apr_pool_t *pool, char **buffer, +- char **spend, unsigned int *cursize, +- unsigned int newsize) ++ char **spend, apr_size_t *cursize, ++ apr_size_t newsize) + { + char* newbuffer = NULL; +- int spendsize = 0; ++ apr_size_t spendsize = 0; + if (*cursize >= newsize) + return; + /* Avoid number of times realloc is called. It could cause huge memory +@@ -124,7 +124,7 @@ static void grow_buffer(apr_pool_t *pool, char **buffer, + /* + * grow_line_buffer + */ +-static void grow_line_buffer(sed_eval_t *eval, int newsize) ++static void grow_line_buffer(sed_eval_t *eval, apr_size_t newsize) + { + grow_buffer(eval->pool, &eval->linebuf, &eval->lspend, + &eval->lsize, newsize); +@@ -133,7 +133,7 @@ static void grow_line_buffer(sed_eval_t *eval, int newsize) + /* + * grow_hold_buffer + */ +-static void grow_hold_buffer(sed_eval_t *eval, int newsize) ++static void grow_hold_buffer(sed_eval_t *eval, apr_size_t newsize) + { + grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend, + &eval->hsize, newsize); +@@ -142,7 +142,7 @@ static void grow_hold_buffer(sed_eval_t *eval, int newsize) + /* + * grow_gen_buffer + */ +-static void grow_gen_buffer(sed_eval_t *eval, int newsize, ++static void grow_gen_buffer(sed_eval_t *eval, apr_size_t newsize, + char **gspend) + { + if (gspend == NULL) { +@@ -156,9 +156,9 @@ static void grow_gen_buffer(sed_eval_t *eval, int newsize, + /* + * appendmem_to_linebuf + */ +-static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, int len) ++static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, apr_size_t len) + { +- unsigned int reqsize = (eval->lspend - eval->linebuf) + len; ++ apr_size_t reqsize = (eval->lspend - eval->linebuf) + len; + if (eval->lsize < reqsize) { + grow_line_buffer(eval, reqsize); + } +@@ -169,21 +169,36 @@ static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, int len) + /* + * append_to_linebuf + */ +-static void append_to_linebuf(sed_eval_t *eval, const char* sz) ++static void append_to_linebuf(sed_eval_t *eval, const char* sz, ++ step_vars_storage *step_vars) + { +- int len = strlen(sz); ++ apr_size_t len = strlen(sz); ++ char *old_linebuf = eval->linebuf; + /* Copy string including null character */ + appendmem_to_linebuf(eval, sz, len + 1); + --eval->lspend; /* lspend will now point to NULL character */ ++ /* Sync step_vars after a possible linebuf expansion */ ++ if (step_vars && old_linebuf != eval->linebuf) { ++ if (step_vars->loc1) { ++ step_vars->loc1 = step_vars->loc1 - old_linebuf + eval->linebuf; ++ } ++ if (step_vars->loc2) { ++ step_vars->loc2 = step_vars->loc2 - old_linebuf + eval->linebuf; ++ } ++ if (step_vars->locs) { ++ step_vars->locs = step_vars->locs - old_linebuf + eval->linebuf; ++ } ++ } + } + + /* + * copy_to_linebuf + */ +-static void copy_to_linebuf(sed_eval_t *eval, const char* sz) ++static void copy_to_linebuf(sed_eval_t *eval, const char* sz, ++ step_vars_storage *step_vars) + { + eval->lspend = eval->linebuf; +- append_to_linebuf(eval, sz); ++ append_to_linebuf(eval, sz, step_vars); + } + + /* +@@ -191,8 +206,8 @@ static void copy_to_linebuf(sed_eval_t *eval, const char* sz) + */ + static void append_to_holdbuf(sed_eval_t *eval, const char* sz) + { +- int len = strlen(sz); +- unsigned int reqsize = (eval->hspend - eval->holdbuf) + len + 1; ++ apr_size_t len = strlen(sz); ++ apr_size_t reqsize = (eval->hspend - eval->holdbuf) + len + 1; + if (eval->hsize <= reqsize) { + grow_hold_buffer(eval, reqsize); + } +@@ -215,8 +230,8 @@ static void copy_to_holdbuf(sed_eval_t *eval, const char* sz) + */ + static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend) + { +- int len = strlen(sz); +- unsigned int reqsize = (*gspend - eval->genbuf) + len + 1; ++ apr_size_t len = strlen(sz); ++ apr_size_t reqsize = (*gspend - eval->genbuf) + len + 1; + if (eval->gsize < reqsize) { + grow_gen_buffer(eval, reqsize, gspend); + } +@@ -230,8 +245,8 @@ static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend) + */ + static void copy_to_genbuf(sed_eval_t *eval, const char* sz) + { +- int len = strlen(sz); +- unsigned int reqsize = len + 1; ++ apr_size_t len = strlen(sz); ++ apr_size_t reqsize = len + 1; + if (eval->gsize < reqsize) { + grow_gen_buffer(eval, reqsize, NULL); + } +@@ -353,7 +368,7 @@ apr_status_t sed_eval_file(sed_eval_t *eval, apr_file_t *fin, void *fout) + /* + * sed_eval_buffer + */ +-apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void *fout) ++apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz, void *fout) + { + apr_status_t rv; + +@@ -383,7 +398,7 @@ apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void + + while (bufsz) { + char *n; +- int llen; ++ apr_size_t llen; + + n = memchr(buf, '\n', bufsz); + if (n == NULL) +@@ -442,7 +457,7 @@ apr_status_t sed_finalize_eval(sed_eval_t *eval, void *fout) + * buffer is not a newline. + */ + /* Assure space for NULL */ +- append_to_linebuf(eval, ""); ++ append_to_linebuf(eval, "", NULL); + } + + *eval->lspend = '\0'; +@@ -666,7 +681,7 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n, + lp = step_vars->loc2; + step_vars->loc2 = sp - eval->genbuf + eval->linebuf; + append_to_genbuf(eval, lp, &sp); +- copy_to_linebuf(eval, eval->genbuf); ++ copy_to_linebuf(eval, eval->genbuf, step_vars); + return rv; + } + +@@ -676,8 +691,8 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n, + static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2) + { + char *sp = asp; +- int n = al2 - al1; +- unsigned int reqsize = (sp - eval->genbuf) + n + 1; ++ apr_size_t n = al2 - al1; ++ apr_size_t reqsize = (sp - eval->genbuf) + n + 1; + + if (eval->gsize < reqsize) { + grow_gen_buffer(eval, reqsize, &sp); +@@ -735,7 +750,7 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + } + + p1++; +- copy_to_linebuf(eval, p1); ++ copy_to_linebuf(eval, p1, step_vars); + eval->jflag++; + break; + +@@ -745,12 +760,12 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + break; + + case GCOM: +- copy_to_linebuf(eval, eval->holdbuf); ++ copy_to_linebuf(eval, eval->holdbuf, step_vars); + break; + + case CGCOM: +- append_to_linebuf(eval, "\n"); +- append_to_linebuf(eval, eval->holdbuf); ++ append_to_linebuf(eval, "\n", step_vars); ++ append_to_linebuf(eval, eval->holdbuf, step_vars); + break; + + case HCOM: +@@ -881,7 +896,7 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + if (rv != APR_SUCCESS) + return rv; + } +- append_to_linebuf(eval, "\n"); ++ append_to_linebuf(eval, "\n", step_vars); + eval->pending = ipc->next; + break; + +@@ -956,7 +971,7 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + + case XCOM: + copy_to_genbuf(eval, eval->linebuf); +- copy_to_linebuf(eval, eval->holdbuf); ++ copy_to_linebuf(eval, eval->holdbuf, step_vars); + copy_to_holdbuf(eval, eval->genbuf); + break; + +@@ -1013,7 +1028,7 @@ static apr_status_t arout(sed_eval_t *eval) + /* + * wline + */ +-static apr_status_t wline(sed_eval_t *eval, char *buf, int sz) ++static apr_status_t wline(sed_eval_t *eval, char *buf, apr_size_t sz) + { + apr_status_t rv = APR_SUCCESS; + rv = eval->writefn(eval->fout, buf, sz); + diff --git a/backport-002-CVE-2022-23934.patch b/backport-002-CVE-2022-23934.patch new file mode 100644 index 0000000..3f4fa11 --- /dev/null +++ b/backport-002-CVE-2022-23934.patch @@ -0,0 +1,61 @@ +From e266bd09c313a668d7cca17a8b096d189148be49 Mon Sep 17 00:00:00 2001 +From: Ruediger Pluem +Date: Wed, 9 Mar 2022 07:41:40 +0000 +Subject: [PATCH] Merge r1898735 from trunk: + +* Improve the logic flow + +Reviewed by: rpluem, covener, ylavic + + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1898772 13f79535-47bb-0310-9956-ffa450edef68 +--- + modules/filters/mod_sed.c | 30 +++++++++++++++++++----------- + 1 file changed, 19 insertions(+), 11 deletions(-) + +diff --git a/modules/filters/mod_sed.c b/modules/filters/mod_sed.c +index 7092dd5e7f1..4bdb4ce33ae 100644 +--- a/modules/filters/mod_sed.c ++++ b/modules/filters/mod_sed.c +@@ -168,21 +168,29 @@ static apr_status_t sed_write_output(void *dummy, char *buf, apr_size_t sz) + } + /* buffer is now full */ + status = append_bucket(ctx, ctx->outbuf, ctx->bufsize); +- /* old buffer is now used so allocate new buffer */ +- alloc_outbuf(ctx); +- /* if size is bigger than the allocated buffer directly add to output +- * brigade */ +- if ((status == APR_SUCCESS) && (sz >= ctx->bufsize)) { +- char* newbuf = apr_pmemdup(ctx->tpool, buf, sz); +- status = append_bucket(ctx, newbuf, sz); +- /* pool might get clear after append_bucket */ +- if (ctx->outbuf == NULL) { ++ if (status == APR_SUCCESS) { ++ /* if size is bigger than the allocated buffer directly add to output ++ * brigade */ ++ if (sz >= ctx->bufsize) { ++ char* newbuf = apr_pmemdup(ctx->tpool, buf, sz); ++ status = append_bucket(ctx, newbuf, sz); ++ if (status == APR_SUCCESS) { ++ /* old buffer is now used so allocate new buffer */ ++ alloc_outbuf(ctx); ++ } ++ else { ++ clear_ctxpool(ctx); ++ } ++ } ++ else { ++ /* old buffer is now used so allocate new buffer */ + alloc_outbuf(ctx); ++ memcpy(ctx->curoutbuf, buf, sz); ++ ctx->curoutbuf += sz; + } + } + else { +- memcpy(ctx->curoutbuf, buf, sz); +- ctx->curoutbuf += sz; ++ clear_ctxpool(ctx); + } + } + else { + diff --git a/backport-CVE-2022-22719.patch b/backport-CVE-2022-22719.patch new file mode 100644 index 0000000..4e71022 --- /dev/null +++ b/backport-CVE-2022-22719.patch @@ -0,0 +1,93 @@ +From 1b96582269d9ec7c82ee0fea1f67934e4b8176ad Mon Sep 17 00:00:00 2001 +From: Yann Ylavic +Date: Mon, 7 Mar 2022 14:51:19 +0000 +Subject: [PATCH] mod_lua: Error out if lua_read_body() or lua_write_body() + fail. + +Otherwise r:requestbody() or r:parsebody() failures might go unnoticed for +the user. + + +Merge r1898689 from trunk. +Submitted by: rpluem +Reviewed by: rpluem, covener, ylavic + + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1898694 13f79535-47bb-0310-9956-ffa450edef68 +--- + modules/lua/lua_request.c | 33 ++++++++++++++++++++------------- + 1 file changed, 20 insertions(+), 13 deletions(-) + +diff --git a/modules/lua/lua_request.c b/modules/lua/lua_request.c +index 493b2bb431c..1eab7b6a47b 100644 +--- a/modules/lua/lua_request.c ++++ b/modules/lua/lua_request.c +@@ -235,14 +235,16 @@ static int lua_read_body(request_rec *r, const char **rbuf, apr_off_t *size, + { + int rc = OK; + ++ *rbuf = NULL; ++ *size = 0; ++ + if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) { + return (rc); + } + if (ap_should_client_block(r)) { + + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +- char argsbuffer[HUGE_STRING_LEN]; +- apr_off_t rsize, len_read, rpos = 0; ++ apr_off_t len_read, rpos = 0; + apr_off_t length = r->remaining; + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + +@@ -250,18 +252,18 @@ static int lua_read_body(request_rec *r, const char **rbuf, apr_off_t *size, + return APR_EINCOMPLETE; /* Only room for incomplete data chunk :( */ + } + *rbuf = (const char *) apr_pcalloc(r->pool, (apr_size_t) (length + 1)); +- *size = length; +- while ((len_read = ap_get_client_block(r, argsbuffer, sizeof(argsbuffer))) > 0) { +- if ((rpos + len_read) > length) { +- rsize = length - rpos; +- } +- else { +- rsize = len_read; +- } +- +- memcpy((char *) *rbuf + rpos, argsbuffer, (size_t) rsize); +- rpos += rsize; ++ while ((rpos < length) ++ && (len_read = ap_get_client_block(r, (char *) *rbuf + rpos, ++ length - rpos)) > 0) { ++ rpos += len_read; ++ } ++ if (len_read < 0) { ++ return APR_EINCOMPLETE; + } ++ *size = rpos; ++ } ++ else { ++ rc = DONE; + } + + return (rc); +@@ -278,6 +280,8 @@ static apr_status_t lua_write_body(request_rec *r, apr_file_t *file, apr_off_t * + { + apr_status_t rc = OK; + ++ *size = 0; ++ + if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) + return rc; + if (ap_should_client_block(r)) { +@@ -303,6 +307,9 @@ static apr_status_t lua_write_body(request_rec *r, apr_file_t *file, apr_off_t * + rpos += rsize; + } + } ++ else { ++ rc = DONE; ++ } + + return rc; + } + diff --git a/backport-CVE-2022-22720.patch b/backport-CVE-2022-22720.patch new file mode 100644 index 0000000..3035110 --- /dev/null +++ b/backport-CVE-2022-22720.patch @@ -0,0 +1,187 @@ +From 19aa2d83b379719420f3a178413325156d7a62f3 Mon Sep 17 00:00:00 2001 +From: Yann Ylavic +Date: Mon, 7 Mar 2022 14:46:08 +0000 +Subject: [PATCH] core: Simpler connection close logic if discarding the + request body fails. + +If ap_discard_request_body() sets AP_CONN_CLOSE by itself it simplifies and +allows to consolidate end_output_stream() and error_output_stream(). + + +Merge r1898683 from trunk. +Submitted by: ylavic, rpluem +Reviewed by: ylavic, rpluem, covener + + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1898692 13f79535-47bb-0310-9956-ffa450edef68 +--- + changes-entries/discard_body.diff | 2 + + modules/http/http_filters.c | 69 ++++++++++++++++--------------- + server/protocol.c | 14 +++++-- + 3 files changed, 48 insertions(+), 37 deletions(-) + create mode 100644 changes-entries/discard_body.diff + +diff --git a/changes-entries/discard_body.diff b/changes-entries/discard_body.diff +new file mode 100644 +index 00000000000..6b467ac5ee3 +--- /dev/null ++++ b/changes-entries/discard_body.diff +@@ -0,0 +1,2 @@ ++ *) core: Simpler connection close logic if discarding the request body fails. ++ [Yann Ylavic, Ruediger Pluem] +\ No newline at end of file +diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c +index d9b36212155..43e8c6dd5d5 100644 +--- a/modules/http/http_filters.c ++++ b/modules/http/http_filters.c +@@ -1598,9 +1598,9 @@ AP_DECLARE(int) ap_map_http_request_error(apr_status_t rv, int status) + */ + AP_DECLARE(int) ap_discard_request_body(request_rec *r) + { ++ int rc = OK; ++ conn_rec *c = r->connection; + apr_bucket_brigade *bb; +- int seen_eos; +- apr_status_t rv; + + /* Sometimes we'll get in a state where the input handling has + * detected an error where we want to drop the connection, so if +@@ -1609,54 +1609,57 @@ AP_DECLARE(int) ap_discard_request_body(request_rec *r) + * + * This function is also a no-op on a subrequest. + */ +- if (r->main || r->connection->keepalive == AP_CONN_CLOSE || +- ap_status_drops_connection(r->status)) { ++ if (r->main || c->keepalive == AP_CONN_CLOSE) { ++ return OK; ++ } ++ if (ap_status_drops_connection(r->status)) { ++ c->keepalive = AP_CONN_CLOSE; + return OK; + } + + bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); +- seen_eos = 0; +- do { +- apr_bucket *bucket; ++ for (;;) { ++ apr_status_t rv; + + rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, + APR_BLOCK_READ, HUGE_STRING_LEN); +- + if (rv != APR_SUCCESS) { +- apr_brigade_destroy(bb); +- return ap_map_http_request_error(rv, HTTP_BAD_REQUEST); ++ rc = ap_map_http_request_error(rv, HTTP_BAD_REQUEST); ++ goto cleanup; + } + +- for (bucket = APR_BRIGADE_FIRST(bb); +- bucket != APR_BRIGADE_SENTINEL(bb); +- bucket = APR_BUCKET_NEXT(bucket)) +- { +- const char *data; +- apr_size_t len; ++ while (!APR_BRIGADE_EMPTY(bb)) { ++ apr_bucket *b = APR_BRIGADE_FIRST(bb); + +- if (APR_BUCKET_IS_EOS(bucket)) { +- seen_eos = 1; +- break; +- } +- +- /* These are metadata buckets. */ +- if (bucket->length == 0) { +- continue; ++ if (APR_BUCKET_IS_EOS(b)) { ++ goto cleanup; + } + +- /* We MUST read because in case we have an unknown-length +- * bucket or one that morphs, we want to exhaust it. ++ /* There is no need to read empty or metadata buckets or ++ * buckets of known length, but we MUST read buckets of ++ * unknown length in order to exhaust them. + */ +- rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ); +- if (rv != APR_SUCCESS) { +- apr_brigade_destroy(bb); +- return HTTP_BAD_REQUEST; ++ if (b->length == (apr_size_t)-1) { ++ apr_size_t len; ++ const char *data; ++ ++ rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ); ++ if (rv != APR_SUCCESS) { ++ rc = HTTP_BAD_REQUEST; ++ goto cleanup; ++ } + } ++ ++ apr_bucket_delete(b); + } +- apr_brigade_cleanup(bb); +- } while (!seen_eos); ++ } + +- return OK; ++cleanup: ++ apr_brigade_cleanup(bb); ++ if (rc != OK) { ++ c->keepalive = AP_CONN_CLOSE; ++ } ++ return rc; + } + + /* Here we deal with getting the request message body from the client. +diff --git a/server/protocol.c b/server/protocol.c +index 2214f72b5a4..298f61e1fb8 100644 +--- a/server/protocol.c ++++ b/server/protocol.c +@@ -1687,23 +1687,29 @@ AP_DECLARE(void) ap_set_sub_req_protocol(request_rec *rnew, + rnew->main = (request_rec *) r; + } + +-static void end_output_stream(request_rec *r) ++static void end_output_stream(request_rec *r, int status) + { + conn_rec *c = r->connection; + apr_bucket_brigade *bb; + apr_bucket *b; + + bb = apr_brigade_create(r->pool, c->bucket_alloc); ++ if (status != OK) { ++ b = ap_bucket_error_create(status, NULL, r->pool, c->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(bb, b); ++ } + b = apr_bucket_eos_create(c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, b); ++ + ap_pass_brigade(r->output_filters, bb); ++ apr_brigade_cleanup(bb); + } + + AP_DECLARE(void) ap_finalize_sub_req_protocol(request_rec *sub) + { + /* tell the filter chain there is no more content coming */ + if (!sub->eos_sent) { +- end_output_stream(sub); ++ end_output_stream(sub, OK); + } + } + +@@ -1714,11 +1720,11 @@ AP_DECLARE(void) ap_finalize_sub_req_protocol(request_rec *sub) + */ + AP_DECLARE(void) ap_finalize_request_protocol(request_rec *r) + { +- (void) ap_discard_request_body(r); ++ int status = ap_discard_request_body(r); + + /* tell the filter chain there is no more content coming */ + if (!r->eos_sent) { +- end_output_stream(r); ++ end_output_stream(r, status); + } + } + \ No newline at end of file diff --git a/backport-CVE-2022-22721.patch b/backport-CVE-2022-22721.patch new file mode 100644 index 0000000..df904a2 --- /dev/null +++ b/backport-CVE-2022-22721.patch @@ -0,0 +1,113 @@ +From 5a72f0fe6f2f8ce35c45242e99a421dc19251ab5 Mon Sep 17 00:00:00 2001 +From: Yann Ylavic +Date: Mon, 7 Mar 2022 14:48:54 +0000 +Subject: [PATCH] core: Make sure and check that LimitXMLRequestBody fits in + system memory. + +LimitXMLRequestBody can not exceed the size needed to ap_escape_html2() the +body without failing to allocate memory, so enforce this at load time based +on APR_SIZE_MAX, and make sure that ap_escape_html2() is within the bounds. + +Document the limits for LimitXMLRequestBody in our docs. + + +Merge r1898686 from trunk. +Submitted by: ylavic, rpluem +Reviewed by: ylavic, covener, rpluem + + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1898693 13f79535-47bb-0310-9956-ffa450edef68 +--- + changes-entries/AP_MAX_LIMIT_XML_BODY.diff | 2 ++ + server/core.c | 9 +++++++++ + server/util.c | 8 ++++++-- + server/util_xml.c | 2 +- + 4 files changed, 27 insertions(+), 6 deletions(-) + create mode 100644 changes-entries/AP_MAX_LIMIT_XML_BODY.diff + +diff --git a/changes-entries/AP_MAX_LIMIT_XML_BODY.diff b/changes-entries/AP_MAX_LIMIT_XML_BODY.diff +new file mode 100644 +index 00000000000..07fef3c624c +--- /dev/null ++++ b/changes-entries/AP_MAX_LIMIT_XML_BODY.diff +@@ -0,0 +1,2 @@ ++ *) core: Make sure and check that LimitXMLRequestBody fits in system memory. ++ [Ruediger Pluem, Yann Ylavic] +\ No newline at end of file +diff --git a/server/core.c b/server/core.c +index 798212b4808..090e3976421 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -72,6 +72,8 @@ + /* LimitXMLRequestBody handling */ + #define AP_LIMIT_UNSET ((long) -1) + #define AP_DEFAULT_LIMIT_XML_BODY ((apr_size_t)1000000) ++/* Hard limit for ap_escape_html2() */ ++#define AP_MAX_LIMIT_XML_BODY ((apr_size_t)(APR_SIZE_MAX / 6 - 1)) + + #define AP_MIN_SENDFILE_BYTES (256) + +@@ -3761,6 +3763,11 @@ static const char *set_limit_xml_req_body(cmd_parms *cmd, void *conf_, + if (conf->limit_xml_body < 0) + return "LimitXMLRequestBody requires a non-negative integer."; + ++ /* zero is AP_MAX_LIMIT_XML_BODY (implicitly) */ ++ if ((apr_size_t)conf->limit_xml_body > AP_MAX_LIMIT_XML_BODY) ++ return apr_psprintf(cmd->pool, "LimitXMLRequestBody must not exceed " ++ "%" APR_SIZE_T_FMT, AP_MAX_LIMIT_XML_BODY); ++ + return NULL; + } + +@@ -3849,6 +3856,8 @@ AP_DECLARE(apr_size_t) ap_get_limit_xml_body(const request_rec *r) + conf = ap_get_core_module_config(r->per_dir_config); + if (conf->limit_xml_body == AP_LIMIT_UNSET) + return AP_DEFAULT_LIMIT_XML_BODY; ++ if (conf->limit_xml_body == 0) ++ return AP_MAX_LIMIT_XML_BODY; + + return (apr_size_t)conf->limit_xml_body; + } +diff --git a/server/util.c b/server/util.c +index 6cfe0035c49..604be1a1ce3 100644 +--- a/server/util.c ++++ b/server/util.c +@@ -2142,11 +2142,14 @@ AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer) + + AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc) + { +- int i, j; ++ apr_size_t i, j; + char *x; + + /* first, count the number of extra characters */ +- for (i = 0, j = 0; s[i] != '\0'; i++) ++ for (i = 0, j = 0; s[i] != '\0'; i++) { ++ if (i + j > APR_SIZE_MAX - 6) { ++ abort(); ++ } + if (s[i] == '<' || s[i] == '>') + j += 3; + else if (s[i] == '&') +@@ -2155,6 +2158,7 @@ AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc) + j += 5; + else if (toasc && !apr_isascii(s[i])) + j += 5; ++ } + + if (j == 0) + return apr_pstrmemdup(p, s, i); +diff --git a/server/util_xml.c b/server/util_xml.c +index 4845194656e..22806fa8a40 100644 +--- a/server/util_xml.c ++++ b/server/util_xml.c +@@ -85,7 +85,7 @@ AP_DECLARE(int) ap_xml_parse_input(request_rec * r, apr_xml_doc **pdoc) + } + + total_read += len; +- if (limit_xml_body && total_read > limit_xml_body) { ++ if (total_read > limit_xml_body) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00539) + "XML request body is larger than the configured " + "limit of %lu", (unsigned long)limit_xml_body); + diff --git a/httpd.spec b/httpd.spec index f40e96f..c0dc600 100644 --- a/httpd.spec +++ b/httpd.spec @@ -8,7 +8,7 @@ Name: httpd Summary: Apache HTTP Server Version: 2.4.51 -Release: 1 +Release: 2 License: ASL 2.0 URL: https://httpd.apache.org/ Source0: https://archive.apache.org/dist/httpd/httpd-%{version}.tar.bz2 @@ -68,8 +68,13 @@ Patch14: backport-layout_add_openEuler.patch Patch15: backport-httpd-2.4.43-gettid.patch Patch16: backport-httpd-2.4.43-r1861793+.patch Patch17: backport-httpd-2.4.48-r1828172+.patch -Patch18: backport-httpd-2.4.46-htcacheclean-dont-break.patch -Patch19: backport-CVE-2021-44790.patch +Patch18: backport-httpd-2.4.46-htcacheclean-dont-break.patch +Patch19: backport-CVE-2022-22719.patch +Patch20: backport-CVE-2022-22720.patch +Patch21: backport-CVE-2022-22721.patch +Patch22: backport-001-CVE-2022-23934.patch +Patch23: backport-002-CVE-2022-23934.patch +Patch24: backport-CVE-2021-44790.patch BuildRequires: gcc autoconf pkgconfig findutils xmlto perl-interpreter perl-generators systemd-devel BuildRequires: zlib-devel libselinux-devel lua-devel brotli-devel @@ -502,6 +507,12 @@ exit $rv %{_rpmconfigdir}/macros.d/macros.httpd %changelog +* Mon Mar 28 2022 yanglu - 2.4.51-2 +- Type:cves +- ID:NA +- SUG:restart +- DESC:fix CVE-2022-22719 CVE-2022-22720 CVE-2022-22721 CVE-2022-23934 + * Sat Mar 26 2022 yanglu - 2.4.51-1 - Type:requirement - ID:NA -- Gitee