[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1029217: bullseye-pu: package libapreq2/2.13-7~deb11u1



forgot to attach the diff

diff -Nru libapreq2-2.13/debian/changelog libapreq2-2.13/debian/changelog
--- libapreq2-2.13/debian/changelog	2019-09-18 09:12:54.000000000 +0200
+++ libapreq2-2.13/debian/changelog	2023-01-19 20:25:21.000000000 +0100
@@ -1,3 +1,10 @@
+libapreq2 (2.13-7~deb11u1) UNRELEASED; urgency=high
+
+  * Non-maintainer upload by the Security Team.
+  * Backport fix for CVE-2022-22728. (Closes: #1018191)
+
+ -- Tobias Frost <tobi@debian.org>  Thu, 19 Jan 2023 20:25:21 +0100
+
 libapreq2 (2.13-7) unstable; urgency=high
 
   * Source-only upload.
diff -Nru libapreq2-2.13/debian/patches/10-CVE-2022-22728_1of4.patch libapreq2-2.13/debian/patches/10-CVE-2022-22728_1of4.patch
--- libapreq2-2.13/debian/patches/10-CVE-2022-22728_1of4.patch	1970-01-01 01:00:00.000000000 +0100
+++ libapreq2-2.13/debian/patches/10-CVE-2022-22728_1of4.patch	2023-01-19 20:24:24.000000000 +0100
@@ -0,0 +1,385 @@
+Description: CVE-2022-22728 -- multipart form parse memory corruption
+ A flaw in Apache libapreq2 versions 2.16 and earlier could cause a
+ buffer overflow while processing multipart form uploads. A remote
+ attacker could send a request causing a process crash which could lead
+ to a denial of service attack.
+ This is #1 of 4 patches, see also https://www.openwall.com/lists/oss-security/2023/01/02/2
+Origin: https://svn.apache.org/viewvc?view=revision&revision=1894937
+Bug-Debian: https://bugs.debian.org/1018191
+Reviewed-by: Tobias Frost <tobi@debian.org>
+Last-Update: 2023-01-13 <YYYY-MM-DD, last update of the meta-information, optional>
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+--- a/library/parser_header.c
++++ b/library/parser_header.c
+@@ -39,7 +39,10 @@
+         HDR_GAP,
+         HDR_VALUE,
+         HDR_NEWLINE,
+-        HDR_CONTINUE,
++        HDR_CONTLINE,
++        HDR_WANTLINE,
++        HDR_NEXTLINE,
++        HDR_LASTLINE,
+         HDR_COMPLETE,
+         HDR_ERROR
+     }                   status;
+@@ -59,16 +62,17 @@
+     apreq_value_t *v;
+     apr_bucket *e, *f;
+     apr_status_t s;
+-    struct iovec vec[APREQ_DEFAULT_NELTS], *iov, *end;
+-    apr_array_header_t arr;
++    struct iovec vec[APREQ_DEFAULT_NELTS], *iov;
++    apr_array_header_t arr, *a = &arr;
+     char *dest;
+     const char *data;
+     apr_size_t dlen;
++    int i;
+ 
+     if (nlen == 0)
+         return APR_EBADARG;
+ 
+-    param = apreq_param_make(pool, NULL, nlen, NULL, vlen - 1); /*drop (CR)LF */
++    param = apreq_param_make(pool, NULL, nlen, NULL, vlen);
+     *(const apreq_value_t **)&v = &param->v;
+ 
+     arr.pool     = pool;
+@@ -80,67 +84,78 @@
+     e = APR_BRIGADE_FIRST(bb);
+ 
+     /* store name in a temporary iovec array */
+-
+     while (nlen > 0) {
+         apr_size_t len;
+-        end = apr_array_push(&arr);
+-        s = apr_bucket_read(e, (const char **)&end->iov_base,
++
++        if (a->nelts == a->nalloc) {
++            a = apr_array_make(pool, arr.nalloc * 2, sizeof(struct iovec));
++            memcpy(a->elts, arr.elts, arr.nelts * sizeof(struct iovec));
++            a->nelts = arr.nelts;
++        }
++        iov = (struct iovec *)apr_array_push(a);
++
++        assert(e != APR_BRIGADE_SENTINEL(bb));
++        s = apr_bucket_read(e, (const char **)&iov->iov_base,
+                             &len, APR_BLOCK_READ);
+         if (s != APR_SUCCESS)
+             return s;
++        iov->iov_len = len;
+ 
+         assert(nlen >= len);
+-        end->iov_len = len;
+         nlen -= len;
+ 
+         e = APR_BUCKET_NEXT(e);
+     }
+ 
+     /* skip gap */
+-
+     while (glen > 0) {
++        assert(e != APR_BRIGADE_SENTINEL(bb));
+         s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
+         if (s != APR_SUCCESS)
+             return s;
+ 
+         assert(glen >= dlen);
+         glen -= dlen;
++
+         e = APR_BUCKET_NEXT(e);
+     }
+ 
+     /* copy value */
+-    assert(vlen > 0);
+     dest = v->data;
+     while (vlen > 0) {
++        apr_size_t off;
+ 
++        assert(e != APR_BRIGADE_SENTINEL(bb));
+         s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
+         if (s != APR_SUCCESS)
+             return s;
+ 
+-        memcpy(dest, data, dlen);
+-        dest += dlen;
+-        assert(vlen >= dlen);
+-        vlen -= dlen;
++        for (off = 0; off < dlen; ++off) {
++            const char ch = data[off];
++            if (ch == '\r' || ch == '\n') {
++                /* skip continuation CRLF(s) */
++                continue;
++            }
++            assert(vlen > 0);
++            *dest = ch;
++            ++dest;
++            --vlen;
++        }
++
+         e = APR_BUCKET_NEXT(e);
+     }
+-
+-    assert(dest[-1] == '\n');
+-
+-    if (dest[-2] == '\r')
+-        --dest;
+-
+-    dest[-1] = 0;
+-    v->dlen = (dest - v->data) - 1;
++    v->dlen = dest - v->data;
++    *dest++ = 0;
+ 
+     /* write name */
+     v->name = dest;
+-    iov = (struct iovec *)arr.elts;
+-
+-    while (iov <= end) {
++    for (i = 0; i < a->nelts; ++i) {
++        iov = (struct iovec *)a->elts + i;
+         memcpy(dest, iov->iov_base, iov->iov_len);
+         dest += iov->iov_len;
+         ++iov;
+     }
++    v->nlen = dest - v->name;
+     *dest = 0;
+     nlen = dest - v->name;
+ 
+@@ -159,6 +174,7 @@
+     apr_pool_t *pool = parser->pool;
+     apr_bucket *e;
+     struct hdr_ctx *ctx;
++    char ch;
+ 
+     if (parser->ctx == NULL) {
+         ctx = apr_pcalloc(pool, sizeof *ctx);
+@@ -173,9 +189,6 @@
+     e = APR_BRIGADE_LAST(ctx->bb);
+     APR_BRIGADE_CONCAT(ctx->bb, bb);
+ 
+- parse_hdr_brigade:
+-
+-
+     /* parse the brigade for CRLF_CRLF-terminated header block,
+      * each time starting from the front of the brigade.
+      */
+@@ -194,8 +207,8 @@
+             APR_BRIGADE_CONCAT(bb, ctx->bb);
+             return APR_SUCCESS;
+         }
+-        s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
+ 
++        s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
+         if ( s != APR_SUCCESS ) {
+             ctx->status = HDR_ERROR;
+             return s;
+@@ -217,21 +230,8 @@
+         case HDR_NAME:
+ 
+             while (off < dlen) {
+-                switch (data[off++]) {
+-
+-                case '\n':
+-                    if (off < dlen)
+-                        apr_bucket_split(e, off);
+-                    e = APR_BUCKET_NEXT(e);
+-
+-                    do {
+-                        apr_bucket *f = APR_BRIGADE_FIRST(ctx->bb);
+-                        apr_bucket_delete(f);
+-                    } while (e != APR_BRIGADE_FIRST(ctx->bb));
+-                    APR_BRIGADE_CONCAT(bb, ctx->bb);
+-                    ctx->status = HDR_COMPLETE;
+-                    return APR_SUCCESS;
+-
++                ch = data[off++];
++                switch (ch) {
+                 case ':':
+                     if (off > 1) {
+                         apr_bucket_split(e, off - 1);
+@@ -247,16 +247,15 @@
+                 default:
+                     ++ctx->nlen;
+                 }
+-
+             }
+-
+             break;
+ 
+ 
+         case HDR_GAP:
+ 
+             while (off < dlen) {
+-                switch (data[off++]) {
++                ch = data[off++];
++                switch (ch) {
+                 case ' ':
+                 case '\t':
+                     ++ctx->glen;
+@@ -266,6 +265,10 @@
+                     ctx->status = HDR_NEWLINE;
+                     goto parse_hdr_bucket;
+ 
++                case '\r':
++                    ctx->status = HDR_WANTLINE;
++                    goto parse_hdr_bucket;
++
+                 default:
+                     ctx->status = HDR_VALUE;
+                     if (off > 1) {
+@@ -285,25 +288,52 @@
+         case HDR_VALUE:
+ 
+             while (off < dlen) {
+-                ++ctx->vlen;
+-                if (data[off++] == '\n') {
++                ch = data[off++];
++                switch (ch) {
++                case '\n':
+                     ctx->status = HDR_NEWLINE;
+                     goto parse_hdr_bucket;
++
++                case '\r':
++                    ctx->status = HDR_WANTLINE;
++                    goto parse_hdr_bucket;
++
++                default:
++                    ++ctx->vlen;
+                 }
+             }
+             break;
+ 
+ 
++        case HDR_WANTLINE:
++        case HDR_LASTLINE:
++
++            if (off == dlen)
++                break;
++
++            if (data[off++] != '\n') {
++                ctx->status = HDR_ERROR;
++                return APR_EINVAL;
++            }
++
++            if (ctx->status == HDR_LASTLINE) {
++                ctx->status = HDR_COMPLETE;
++                goto parse_hdr_bucket;
++            }
++
++            /* fall thru */
++            ctx->status = HDR_NEWLINE;
++
+         case HDR_NEWLINE:
+ 
+             if (off == dlen)
+                 break;
+-            else {
+-                switch (data[off]) {
+ 
++            {
++                ch = data[off];
++                switch (ch) {
+                 case ' ':
+                 case '\t':
+-                    ctx->status = HDR_CONTINUE;
+                     ++off;
+                     ++ctx->vlen;
+                     break;
+@@ -315,30 +345,29 @@
+                     s = split_header_line(&param, pool, ctx->bb, ctx->nlen, ctx->glen, ctx->vlen);
+                     if (parser->hook != NULL && s == APR_SUCCESS)
+                         s = apreq_hook_run(parser->hook, param, NULL);
+-
+                     if (s != APR_SUCCESS) {
+                         ctx->status = HDR_ERROR;
+                         return s;
+                     }
+ 
+                     apreq_value_table_add(&param->v, t);
+-                    e = APR_BRIGADE_SENTINEL(ctx->bb);
+-                    ctx->status = HDR_NAME;
+                     ctx->nlen = 0;
+                     ctx->vlen = 0;
+                     ctx->glen = 0;
+ 
+-                    goto parse_hdr_brigade;
++                    ctx->status = HDR_NEXTLINE;
++                    goto parse_hdr_bucket;
+                 }
+-
+-                /* cases ' ', '\t' fall through to HDR_CONTINUE */
+             }
+ 
++            /* fall thru */
++            ctx->status = HDR_CONTLINE;
+ 
+-        case HDR_CONTINUE:
++        case HDR_CONTLINE:
+ 
+             while (off < dlen) {
+-                switch (data[off++]) {
++                ch = data[off++];
++                switch (ch) {
+                 case ' ':
+                 case '\t':
+                     ++ctx->vlen;
+@@ -348,6 +377,10 @@
+                     ctx->status = HDR_NEWLINE;
+                     goto parse_hdr_bucket;
+ 
++                case '\r':
++                    ctx->status = HDR_WANTLINE;
++                    goto parse_hdr_bucket;
++
+                 default:
+                     ctx->status = HDR_VALUE;
+                     ++ctx->vlen;
+@@ -356,8 +389,47 @@
+             }
+             break;
+ 
++
++        case HDR_NEXTLINE:
++
++            if (off == dlen)
++                break;
++
++            ch = data[off++];
++            switch (ch) {
++            case '\n':
++                /* We are done */
++                break;
++
++            case '\r':
++                ctx->status = HDR_LASTLINE;
++                goto parse_hdr_bucket;
++
++            default:
++                ctx->status = HDR_NAME;
++                goto parse_hdr_bucket;
++            }
++
++            /* fall thru */
++            ctx->status = HDR_COMPLETE;
++
++        case HDR_COMPLETE:
++
++            if (off < dlen)
++                apr_bucket_split(e, off);
++
++            e = APR_BUCKET_NEXT(e);
++            do {
++                apr_bucket *f = APR_BRIGADE_FIRST(ctx->bb);
++                apr_bucket_delete(f);
++            } while (e != APR_BRIGADE_FIRST(ctx->bb));
++
++            APR_BRIGADE_CONCAT(bb, ctx->bb);
++            return APR_SUCCESS;
++
++
+         default:
+-            ; /* not reached */
++            assert(0); /* not reached */
+         }
+     }
+     apreq_brigade_setaside(ctx->bb,pool);
diff -Nru libapreq2-2.13/debian/patches/11-CVE-2022-22728_2of4.patch libapreq2-2.13/debian/patches/11-CVE-2022-22728_2of4.patch
--- libapreq2-2.13/debian/patches/11-CVE-2022-22728_2of4.patch	1970-01-01 01:00:00.000000000 +0100
+++ libapreq2-2.13/debian/patches/11-CVE-2022-22728_2of4.patch	2023-01-19 20:24:31.000000000 +0100
@@ -0,0 +1,89 @@
+Description: CVE-2022-22728 -- multipart form parse memory corruption
+ A flaw in Apache libapreq2 versions 2.16 and earlier could cause a
+ buffer overflow while processing multipart form uploads. A remote
+ attacker could send a request causing a process crash which could lead
+ to a denial of service attack.
+ This is #2 of 4 patches, see alos https://www.openwall.com/lists/oss-security/2023/01/02/2
+Origin: https://svn.apache.org/viewvc?view=revision&revision=1894940
+Bug-Debian: https://bugs.debian.org/1018191
+Reviewed-by: Tobias Frost <tobi@debian.org>
+Last-Update: 2023-01-13 <YYYY-MM-DD, last update of the meta-information, optional>
+--- a/library/parser_header.c
++++ b/library/parser_header.c
+@@ -39,7 +39,7 @@
+         HDR_GAP,
+         HDR_VALUE,
+         HDR_NEWLINE,
+-        HDR_CONTLINE,
++        HDR_FOLDLINE,
+         HDR_WANTLINE,
+         HDR_NEXTLINE,
+         HDR_LASTLINE,
+@@ -329,41 +329,39 @@
+             if (off == dlen)
+                 break;
+ 
+-            {
+-                ch = data[off];
+-                switch (ch) {
+-                case ' ':
+-                case '\t':
+-                    ++off;
+-                    ++ctx->vlen;
+-                    break;
++            ch = data[off];
++            switch (ch) {
++            case ' ':
++            case '\t':
++                ++off;
++                ++ctx->vlen;
++                break;
+ 
+-                default:
+-                    /* can parse brigade now */
+-                    if (off > 0)
+-                        apr_bucket_split(e, off);
+-                    s = split_header_line(&param, pool, ctx->bb, ctx->nlen, ctx->glen, ctx->vlen);
+-                    if (parser->hook != NULL && s == APR_SUCCESS)
+-                        s = apreq_hook_run(parser->hook, param, NULL);
+-                    if (s != APR_SUCCESS) {
+-                        ctx->status = HDR_ERROR;
+-                        return s;
+-                    }
++            default:
++                /* can parse brigade now */
++                if (off > 0)
++                    apr_bucket_split(e, off);
++                s = split_header_line(&param, pool, ctx->bb, ctx->nlen, ctx->glen, ctx->vlen);
++                if (parser->hook != NULL && s == APR_SUCCESS)
++                    s = apreq_hook_run(parser->hook, param, NULL);
++                if (s != APR_SUCCESS) {
++                    ctx->status = HDR_ERROR;
++                    return s;
++                }
+ 
+-                    apreq_value_table_add(&param->v, t);
+-                    ctx->nlen = 0;
+-                    ctx->vlen = 0;
+-                    ctx->glen = 0;
++                apreq_value_table_add(&param->v, t);
++                ctx->nlen = 0;
++                ctx->vlen = 0;
++                ctx->glen = 0;
+ 
+-                    ctx->status = HDR_NEXTLINE;
+-                    goto parse_hdr_bucket;
+-                }
++                ctx->status = HDR_NEXTLINE;
++                goto parse_hdr_bucket;
+             }
+ 
+             /* fall thru */
+-            ctx->status = HDR_CONTLINE;
++            ctx->status = HDR_FOLDLINE;
+ 
+-        case HDR_CONTLINE:
++        case HDR_FOLDLINE:
+ 
+             while (off < dlen) {
+                 ch = data[off++];
diff -Nru libapreq2-2.13/debian/patches/12-CVE-2022-22728_3of4.patch libapreq2-2.13/debian/patches/12-CVE-2022-22728_3of4.patch
--- libapreq2-2.13/debian/patches/12-CVE-2022-22728_3of4.patch	1970-01-01 01:00:00.000000000 +0100
+++ libapreq2-2.13/debian/patches/12-CVE-2022-22728_3of4.patch	2023-01-19 20:24:40.000000000 +0100
@@ -0,0 +1,351 @@
+Description: CVE-2022-22728 -- multipart form parse memory corruption
+ A flaw in Apache libapreq2 versions 2.16 and earlier could cause a
+ buffer overflow while processing multipart form uploads. A remote
+ attacker could send a request causing a process crash which could lead
+ to a denial of service attack.
+ This is #3 of 4 patches, see alos https://www.openwall.com/lists/oss-security/2023/01/02/2
+Origin: https://svn.apache.org/viewvc?view=revision&revision=1894977
+Bug-Debian: https://bugs.debian.org/1018191
+Reviewed-by: Tobias Frost <tobi@debian.org>
+Last-Update: 2023-01-13 <YYYY-MM-DD, last update of the meta-information, optional>
+--- a/library/parser_header.c
++++ b/library/parser_header.c
+@@ -19,6 +19,8 @@
+ #include "apreq_error.h"
+ #include "apreq_util.h"
+ 
++#include "apr_lib.h" /* for apr_iscntrl() & co */
++
+ #define PARSER_STATUS_CHECK(PREFIX)   do {         \
+     if (ctx->status == PREFIX##_ERROR)             \
+         return APREQ_ERROR_GENERAL;                \
+@@ -39,9 +41,8 @@
+         HDR_GAP,
+         HDR_VALUE,
+         HDR_NEWLINE,
++        HDR_ENDLINE,
+         HDR_FOLDLINE,
+-        HDR_WANTLINE,
+-        HDR_NEXTLINE,
+         HDR_LASTLINE,
+         HDR_COMPLETE,
+         HDR_ERROR
+@@ -51,27 +52,37 @@
+ /********************* header parsing utils ********************/
+ 
+ 
+-static apr_status_t split_header_line(apreq_param_t **p,
+-                                      apr_pool_t *pool,
+-                                      apr_bucket_brigade *bb,
+-                                      apr_size_t nlen,
+-                                      apr_size_t glen,
+-                                      apr_size_t vlen)
++static apr_bucket *split_header_line(apr_bucket *e, apr_size_t *off,
++                                     const char **data, apr_size_t *dlen)
++{
++    if (*off > 1) {
++        apr_bucket_split(e, *off - 1);
++        e = APR_BUCKET_NEXT(e);
++        *dlen -= *off - 1;
++        *data += *off - 1;
++        *off = 1;
++    }
++    return e;
++}
++
++static apr_status_t consume_header_line(apreq_param_t **p,
++                                        apr_pool_t *pool,
++                                        apr_bucket_brigade *bb,
++                                        apr_size_t nlen,
++                                        apr_size_t glen,
++                                        apr_size_t vlen)
+ {
+     apreq_param_t *param;
+     apreq_value_t *v;
+     apr_bucket *e, *f;
+     apr_status_t s;
+     struct iovec vec[APREQ_DEFAULT_NELTS], *iov;
+-    apr_array_header_t arr, *a = &arr;
++    apr_array_header_t arr;
+     char *dest;
+     const char *data;
+     apr_size_t dlen;
+     int i;
+ 
+-    if (nlen == 0)
+-        return APR_EBADARG;
+-
+     param = apreq_param_make(pool, NULL, nlen, NULL, vlen);
+     *(const apreq_value_t **)&v = &param->v;
+ 
+@@ -84,17 +95,11 @@
+     e = APR_BRIGADE_FIRST(bb);
+ 
+     /* store name in a temporary iovec array */
+-    while (nlen > 0) {
++    do {
+         apr_size_t len;
+ 
+-        if (a->nelts == a->nalloc) {
+-            a = apr_array_make(pool, arr.nalloc * 2, sizeof(struct iovec));
+-            memcpy(a->elts, arr.elts, arr.nelts * sizeof(struct iovec));
+-            a->nelts = arr.nelts;
+-        }
+-        iov = (struct iovec *)apr_array_push(a);
+-
+         assert(e != APR_BRIGADE_SENTINEL(bb));
++        iov = (struct iovec *)apr_array_push(&arr);
+         s = apr_bucket_read(e, (const char **)&iov->iov_base,
+                             &len, APR_BLOCK_READ);
+         if (s != APR_SUCCESS)
+@@ -105,10 +110,10 @@
+         nlen -= len;
+ 
+         e = APR_BUCKET_NEXT(e);
+-    }
++    } while (nlen > 0);
+ 
+     /* skip gap */
+-    while (glen > 0) {
++    do {
+         assert(e != APR_BRIGADE_SENTINEL(bb));
+         s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
+         if (s != APR_SUCCESS)
+@@ -118,11 +123,11 @@
+         glen -= dlen;
+ 
+         e = APR_BUCKET_NEXT(e);
+-    }
++    } while (glen > 0);
+ 
+     /* copy value */
+     dest = v->data;
+-    while (vlen > 0) {
++    do {
+         apr_size_t off;
+ 
+         assert(e != APR_BRIGADE_SENTINEL(bb));
+@@ -143,14 +148,14 @@
+         }
+ 
+         e = APR_BUCKET_NEXT(e);
+-    }
++    } while (vlen > 0);
+     v->dlen = dest - v->data;
+     *dest++ = 0;
+ 
+     /* write name */
+     v->name = dest;
+-    for (i = 0; i < a->nelts; ++i) {
+-        iov = (struct iovec *)a->elts + i;
++    for (i = 0; i < arr.nelts; ++i) {
++        iov = &((struct iovec *)arr.elts)[i];
+         memcpy(dest, iov->iov_base, iov->iov_len);
+         dest += iov->iov_len;
+         ++iov;
+@@ -168,6 +173,8 @@
+ 
+ }
+ 
++#define IS_TOKEN_CHAR(c) (apr_isalnum(c) \
++                          || ((c) && strchr("!#$%&'*+-.^_`|~", (c))))
+ 
+ APREQ_DECLARE_PARSER(apreq_parse_headers)
+ {
+@@ -233,18 +240,20 @@
+                 ch = data[off++];
+                 switch (ch) {
+                 case ':':
+-                    if (off > 1) {
+-                        apr_bucket_split(e, off - 1);
+-                        dlen -= off - 1;
+-                        data += off - 1;
+-                        off = 1;
+-                        e = APR_BUCKET_NEXT(e);
++                    if (!ctx->nlen) {
++                        ctx->status = HDR_ERROR;
++                        return APREQ_ERROR_BADHEADER;
+                     }
++                    e = split_header_line(e, &off, &data, &dlen);
+                     ++ctx->glen;
+                     ctx->status = HDR_GAP;
+                     goto parse_hdr_bucket;
+ 
+                 default:
++                    if (!IS_TOKEN_CHAR(ch)) {
++                        ctx->status = HDR_ERROR;
++                        return APREQ_ERROR_BADCHAR;
++                    }
+                     ++ctx->nlen;
+                 }
+             }
+@@ -262,23 +271,23 @@
+                     break;
+ 
+                 case '\n':
++                    e = split_header_line(e, &off, &data, &dlen);
+                     ctx->status = HDR_NEWLINE;
+                     goto parse_hdr_bucket;
+ 
+                 case '\r':
+-                    ctx->status = HDR_WANTLINE;
++                    e = split_header_line(e, &off, &data, &dlen);
++                    ctx->status = HDR_ENDLINE;
+                     goto parse_hdr_bucket;
+ 
+                 default:
+-                    ctx->status = HDR_VALUE;
+-                    if (off > 1) {
+-                        apr_bucket_split(e, off - 1);
+-                        dlen -= off - 1;
+-                        data += off - 1;
+-                        off = 1;
+-                        e = APR_BUCKET_NEXT(e);
++                    if (apr_iscntrl(ch)) {
++                        ctx->status = HDR_ERROR;
++                        return APREQ_ERROR_BADCHAR;
+                     }
++                    e = split_header_line(e, &off, &data, &dlen);
+                     ++ctx->vlen;
++                    ctx->status = HDR_VALUE;
+                     goto parse_hdr_bucket;
+                 }
+             }
+@@ -295,17 +304,21 @@
+                     goto parse_hdr_bucket;
+ 
+                 case '\r':
+-                    ctx->status = HDR_WANTLINE;
++                    ctx->status = HDR_ENDLINE;
+                     goto parse_hdr_bucket;
+ 
+                 default:
++                    if (apr_iscntrl(ch)) {
++                        ctx->status = HDR_ERROR;
++                        return APREQ_ERROR_BADCHAR;
++                    }
+                     ++ctx->vlen;
+                 }
+             }
+             break;
+ 
+ 
+-        case HDR_WANTLINE:
++        case HDR_ENDLINE:
+         case HDR_LASTLINE:
+ 
+             if (off == dlen)
+@@ -313,7 +326,7 @@
+ 
+             if (data[off++] != '\n') {
+                 ctx->status = HDR_ERROR;
+-                return APR_EINVAL;
++                return APREQ_ERROR_BADHEADER;
+             }
+ 
+             if (ctx->status == HDR_LASTLINE) {
+@@ -329,32 +342,48 @@
+             if (off == dlen)
+                 break;
+ 
+-            ch = data[off];
++            ch = data[off++];
+             switch (ch) {
+             case ' ':
+             case '\t':
+-                ++off;
+                 ++ctx->vlen;
+                 break;
+ 
+             default:
+-                /* can parse brigade now */
+-                if (off > 0)
+-                    apr_bucket_split(e, off);
+-                s = split_header_line(&param, pool, ctx->bb, ctx->nlen, ctx->glen, ctx->vlen);
++                e = split_header_line(e, &off, &data, &dlen);
++
++                /* consume from splitted brigade now */
++                s = consume_header_line(&param, pool, ctx->bb,
++                                        ctx->nlen, ctx->glen, ctx->vlen);
+                 if (parser->hook != NULL && s == APR_SUCCESS)
+                     s = apreq_hook_run(parser->hook, param, NULL);
+                 if (s != APR_SUCCESS) {
+                     ctx->status = HDR_ERROR;
+                     return s;
+                 }
+-
+                 apreq_value_table_add(&param->v, t);
+                 ctx->nlen = 0;
+                 ctx->vlen = 0;
+                 ctx->glen = 0;
+ 
+-                ctx->status = HDR_NEXTLINE;
++                switch (ch) {
++                case '\n':
++                    ctx->status = HDR_COMPLETE;
++                    break;
++
++                case '\r':
++                    ctx->status = HDR_LASTLINE;
++                    break;
++
++                default:
++                    if (!IS_TOKEN_CHAR(ch)) {
++                        ctx->status = HDR_ERROR;
++                        return APREQ_ERROR_BADCHAR;
++                    }
++                    ++ctx->nlen;
++                    ctx->status = HDR_NAME;
++                    break;
++                }
+                 goto parse_hdr_bucket;
+             }
+ 
+@@ -376,10 +405,14 @@
+                     goto parse_hdr_bucket;
+ 
+                 case '\r':
+-                    ctx->status = HDR_WANTLINE;
++                    ctx->status = HDR_ENDLINE;
+                     goto parse_hdr_bucket;
+ 
+                 default:
++                    if (apr_iscntrl(ch)) {
++                        ctx->status = HDR_ERROR;
++                        return APREQ_ERROR_BADCHAR;
++                    }
+                     ctx->status = HDR_VALUE;
+                     ++ctx->vlen;
+                     goto parse_hdr_bucket;
+@@ -388,30 +421,7 @@
+             break;
+ 
+ 
+-        case HDR_NEXTLINE:
+-
+-            if (off == dlen)
+-                break;
+-
+-            ch = data[off++];
+-            switch (ch) {
+-            case '\n':
+-                /* We are done */
+-                break;
+-
+-            case '\r':
+-                ctx->status = HDR_LASTLINE;
+-                goto parse_hdr_bucket;
+-
+-            default:
+-                ctx->status = HDR_NAME;
+-                goto parse_hdr_bucket;
+-            }
+-
+-            /* fall thru */
+-            ctx->status = HDR_COMPLETE;
+-
+-        case HDR_COMPLETE:
++         case HDR_COMPLETE:
+ 
+             if (off < dlen)
+                 apr_bucket_split(e, off);
diff -Nru libapreq2-2.13/debian/patches/13-CVE-2022-22728_4of4.patch libapreq2-2.13/debian/patches/13-CVE-2022-22728_4of4.patch
--- libapreq2-2.13/debian/patches/13-CVE-2022-22728_4of4.patch	1970-01-01 01:00:00.000000000 +0100
+++ libapreq2-2.13/debian/patches/13-CVE-2022-22728_4of4.patch	2023-01-19 20:25:00.000000000 +0100
@@ -0,0 +1,50 @@
+Description: CVE-2022-22728 -- multipart form parse memory corruption
+ A flaw in Apache libapreq2 versions 2.16 and earlier could cause a
+ buffer overflow while processing multipart form uploads. A remote
+ attacker could send a request causing a process crash which could lead
+ to a denial of service attack.
+ This is #4 of 4 patches, see alos https://www.openwall.com/lists/oss-security/2023/01/02/2
+Origin: https://svn.apache.org/viewvc?view=revision&revision=1895054
+Bug-Debian: https://bugs.debian.org/1018191
+Reviewed-by: Tobias Frost <tobi@debian.org>
+Last-Update: 2023-01-13 <YYYY-MM-DD, last update of the meta-information, optional>
+--- a/library/parser_header.c
++++ b/library/parser_header.c
+@@ -81,7 +81,7 @@
+     char *dest;
+     const char *data;
+     apr_size_t dlen;
+-    int i;
++    int i, eol = 0;
+ 
+     param = apreq_param_make(pool, NULL, nlen, NULL, vlen);
+     *(const apreq_value_t **)&v = &param->v;
+@@ -138,7 +138,9 @@
+         for (off = 0; off < dlen; ++off) {
+             const char ch = data[off];
+             if (ch == '\r' || ch == '\n') {
+-                /* skip continuation CRLF(s) */
++                /* Eat [CR]LF of continuation or end of line */
++                if (!vlen && ch == '\n')
++                    eol = 1; /* done */
+                 continue;
+             }
+             assert(vlen > 0);
+@@ -148,7 +150,7 @@
+         }
+ 
+         e = APR_BUCKET_NEXT(e);
+-    } while (vlen > 0);
++    } while (!eol);
+     v->dlen = dest - v->data;
+     *dest++ = 0;
+ 
+@@ -421,7 +423,7 @@
+             break;
+ 
+ 
+-         case HDR_COMPLETE:
++        case HDR_COMPLETE:
+ 
+             if (off < dlen)
+                 apr_bucket_split(e, off);
diff -Nru libapreq2-2.13/debian/patches/series libapreq2-2.13/debian/patches/series
--- libapreq2-2.13/debian/patches/series	2019-09-15 18:26:35.000000000 +0200
+++ libapreq2-2.13/debian/patches/series	2023-01-19 20:24:47.000000000 +0100
@@ -3,3 +3,7 @@
 03-link-in-apr-shared-objects.patch
 04-pass-libdir-to-configure.patch
 05-nested-multipart-null-dereference.patch
+10-CVE-2022-22728_1of4.patch
+11-CVE-2022-22728_2of4.patch
+12-CVE-2022-22728_3of4.patch
+13-CVE-2022-22728_4of4.patch

Reply to: