Hi On Sun, Dec 28, 2025 at 09:37:51PM +0100, Salvatore Bonaccorso wrote: > Source: gnupg2 > Version: 2.4.8-4 > Severity: important > Tags: security upstream > X-Debbugs-Cc: [email protected], Debian Security Team > <[email protected]> > Control: found -1 2.4.7-21 > Control: found -1 2.2.40-1.1+deb12u1 > Control: found -1 2.2.40-1.1 > > Hi, > > The following vulnerability was published for gnupg2. > > CVE-2025-68973[0]: > | In GnuPG through 2.4.8, armor_filter in g10/armor.c has two > | increments of an index variable where one is intended, leading to an > | out-of-bounds write for crafted input. > > > If you fix the vulnerability please also make sure to include the > CVE (Common Vulnerabilities & Exposures) id in your changelog entry. > > For further information see: > > [0] https://security-tracker.debian.org/tracker/CVE-2025-68973 > https://www.cve.org/CVERecord?id=CVE-2025-68973 > [1] > https://github.com/gpg/gnupg/commit/115d138ba599328005c5321c0ef9f00355838ca9
Proposed changes (not in form of a NMU) are in https://salsa.debian.org/debian/gnupg2/-/merge_requests/20 (and debdiff attached with the NMU entry, but this is just a proposal for the changes, I'm really not sure if you prefer to skip the comment changes, I choosed this strategy to make the upstream commit apply and there are no functional changes by applying the first commit). It is as well tested on debusine: https://debusine.debian.net/debian/developers/work-request/297747/ Please count for now this just really as proposal of changes. Regards, Salvatore
diff -Nru gnupg2-2.4.8/debian/changelog gnupg2-2.4.8/debian/changelog --- gnupg2-2.4.8/debian/changelog 2025-10-22 22:39:23.000000000 +0200 +++ gnupg2-2.4.8/debian/changelog 2025-12-28 22:15:23.000000000 +0100 @@ -1,3 +1,12 @@ +gnupg2 (2.4.8-4.1) unstable; urgency=medium + + * Non-maintainer upload. + * common: Reformat some comments in iobuf.c + * gpg: Fix possible memory corruption in the armor parser (CVE-2025-68973) + (Closes: #1124221) + + -- Salvatore Bonaccorso <[email protected]> Sun, 28 Dec 2025 22:15:23 +0100 + gnupg2 (2.4.8-4) unstable; urgency=medium * Make OpenPGP compliance mode require a self-sig for each UID diff -Nru gnupg2-2.4.8/debian/patches/common-Reformat-some-comments-in-iobuf.c.patch gnupg2-2.4.8/debian/patches/common-Reformat-some-comments-in-iobuf.c.patch --- gnupg2-2.4.8/debian/patches/common-Reformat-some-comments-in-iobuf.c.patch 1970-01-01 01:00:00.000000000 +0100 +++ gnupg2-2.4.8/debian/patches/common-Reformat-some-comments-in-iobuf.c.patch 2025-12-28 22:13:27.000000000 +0100 @@ -0,0 +1,515 @@ +From: Werner Koch <[email protected]> +Date: Fri, 10 Oct 2025 10:28:03 +0200 +Subject: common: Reformat some comments in iobuf.c +Origin: https://github.com/gpg/gnupg/commit/d61546521b71deb2ba89b31c71f963c76d51f19f + +-- + +Comments with stars on the left side are easier to read. Also a +long comment in the form + + if (...) + /* This is a comment + * for the next block */ + { + ... + } + +makes it hard to see the start of a block or hides a forgotten block. +In contrast to GNU common use we don't want this but put the comment +either into the block or with adjusted wording above the condition. +--- + common/iobuf.c | 297 +++++++++++++++++++++++++------------------------ + 1 file changed, 151 insertions(+), 146 deletions(-) + +diff --git a/common/iobuf.c b/common/iobuf.c +index 770b67c29d69..8a128b3f6c5d 100644 +--- a/common/iobuf.c ++++ b/common/iobuf.c +@@ -1720,49 +1720,49 @@ iobuf_push_filter2 (iobuf_t a, + } + + /* We want to create a new filter and put it in front of A. A +- simple implementation would do: +- +- b = iobuf_alloc (...); +- b->chain = a; +- return a; +- +- This is a bit problematic: A is the head of the pipeline and +- there are potentially many pointers to it. Requiring the caller +- to update all of these pointers is a burden. +- +- An alternative implementation would add a level of indirection. +- For instance, we could use a pipeline object, which contains a +- pointer to the first filter in the pipeline. This is not what we +- do either. +- +- Instead, we allocate a new buffer (B) and copy the first filter's +- state into that and use the initial buffer (A) for the new +- filter. One limitation of this approach is that it is not +- practical to maintain a pointer to a specific filter's state. +- +- Before: +- +- A +- | +- v 0x100 0x200 +- +----------+ +----------+ +- | filter x |--------->| filter y |---->.... +- +----------+ +----------+ +- +- After: B +- | +- v 0x300 +- +----------+ +- A | filter x | +- | +----------+ +- v 0x100 ^ v 0x200 +- +----------+ +----------+ +- | filter w | | filter y |---->.... +- +----------+ +----------+ +- +- Note: filter x's address changed from 0x100 to 0x300, but A still +- points to the head of the pipeline. +- */ ++ * simple implementation would do: ++ * ++ * b = iobuf_alloc (...); ++ * b->chain = a; ++ * return a; ++ * ++ * This is a bit problematic: A is the head of the pipeline and ++ * there are potentially many pointers to it. Requiring the caller ++ * to update all of these pointers is a burden. ++ * ++ * An alternative implementation would add a level of indirection. ++ * For instance, we could use a pipeline object, which contains a ++ * pointer to the first filter in the pipeline. This is not what we ++ * do either. ++ * ++ * Instead, we allocate a new buffer (B) and copy the first filter's ++ * state into that and use the initial buffer (A) for the new ++ * filter. One limitation of this approach is that it is not ++ * practical to maintain a pointer to a specific filter's state. ++ * ++ * Before: ++ * ++ * A ++ * | ++ * v 0x100 0x200 ++ * +----------+ +----------+ ++ * | filter x |--------->| filter y |---->.... ++ * +----------+ +----------+ ++ * ++ * After: B ++ * | ++ * v 0x300 ++ * +----------+ ++ * A | filter x | ++ * | +----------+ ++ * v 0x100 ^ v 0x200 ++ * +----------+ +----------+ ++ * | filter w | | filter y |---->.... ++ * +----------+ +----------+ ++ * ++ * Note: filter x's address changed from 0x100 to 0x300, but A still ++ * points to the head of the pipeline. ++ */ + + b = xmalloc (sizeof *b); + memcpy (b, a, sizeof *b); +@@ -1776,51 +1776,51 @@ iobuf_push_filter2 (iobuf_t a, + a->filter_ov_owner = 0; + a->filter_eof = 0; + if (a->use == IOBUF_OUTPUT_TEMP) +- /* A TEMP filter buffers any data sent to it; it does not forward +- any data down the pipeline. If we add a new filter to the +- pipeline, it shouldn't also buffer data. It should send it +- downstream to be buffered. Thus, the correct type for a filter +- added in front of an IOBUF_OUTPUT_TEMP filter is IOBUF_OUPUT, not +- IOBUF_OUTPUT_TEMP. */ + { ++ /* A TEMP filter buffers any data sent to it; it does not ++ * forward any data down the pipeline. If we add a new filter ++ * to the pipeline, it shouldn't also buffer data. It should ++ * send it downstream to be buffered. Thus, the correct type ++ * for a filter added in front of an IOBUF_OUTPUT_TEMP filter is ++ * IOBUF_OUPUT, not IOBUF_OUTPUT_TEMP. */ + a->use = IOBUF_OUTPUT; + + /* When pipeline is written to, the temp buffer's size is +- increased accordingly. We don't need to allocate a 10 MB +- buffer for a non-terminal filter. Just use the default +- size. */ ++ * increased accordingly. We don't need to allocate a 10 MB ++ * buffer for a non-terminal filter. Just use the default ++ * size. */ + a->d.size = iobuf_buffer_size; + } + else if (a->use == IOBUF_INPUT_TEMP) +- /* Same idea as above. */ + { ++ /* Same idea as above. */ + a->use = IOBUF_INPUT; + a->d.size = iobuf_buffer_size; + } + + /* The new filter (A) gets a new buffer. +- +- If the pipeline is an output or temp pipeline, then giving the +- buffer to the new filter means that data that was written before +- the filter was pushed gets sent to the filter. That's clearly +- wrong. +- +- If the pipeline is an input pipeline, then giving the buffer to +- the new filter (A) means that data that has read from (B), but +- not yet read from the pipeline won't be processed by the new +- filter (A)! That's certainly not what we want. */ ++ * ++ * If the pipeline is an output or temp pipeline, then giving the ++ * buffer to the new filter means that data that was written before ++ * the filter was pushed gets sent to the filter. That's clearly ++ * wrong. ++ * ++ * If the pipeline is an input pipeline, then giving the buffer to ++ * the new filter (A) means that data that has read from (B), but ++ * not yet read from the pipeline won't be processed by the new ++ * filter (A)! That's certainly not what we want. */ + a->d.buf = xmalloc (a->d.size); + a->d.len = 0; + a->d.start = 0; + +- /* disable nlimit for the new stream */ ++ /* Disable nlimit for the new stream. */ + a->ntotal = b->ntotal + b->nbytes; + a->nlimit = a->nbytes = 0; + a->nofast = 0; +- /* make a link from the new stream to the original stream */ ++ /* Make a link from the new stream to the original stream. */ + a->chain = b; + +- /* setup the function on the new stream */ ++ /* Setup the function on the new stream. */ + a->filter = f; + a->filter_ov = ov; + a->filter_ov_owner = rel_ov; +@@ -1835,13 +1835,14 @@ iobuf_push_filter2 (iobuf_t a, + print_chain (a); + } + +- /* now we can initialize the new function if we have one */ ++ /* Now we can initialize the new function if we have one. */ + if (a->filter && (rc = a->filter (a->filter_ov, IOBUFCTRL_INIT, a->chain, + NULL, &dummy_len))) + log_error ("IOBUFCTRL_INIT failed: %s\n", gpg_strerror (rc)); + return rc; + } + ++ + /**************** + * Remove an i/o filter. + */ +@@ -1865,7 +1866,7 @@ iobuf_pop_filter (iobuf_t a, int (*f) (void *opaque, int control, + return 0; + } + if (!a->filter) +- { /* this is simple */ ++ { /* (this is simple) */ + b = a->chain; + log_assert (b); + xfree (a->d.buf); +@@ -1880,14 +1881,14 @@ iobuf_pop_filter (iobuf_t a, int (*f) (void *opaque, int control, + if (!b) + log_bug ("iobuf_pop_filter(): filter function not found\n"); + +- /* flush this stream if it is an output stream */ ++ /* Flush this stream if it is an output stream ... */ + if (a->use == IOBUF_OUTPUT && (rc = filter_flush (b))) + { + log_error ("filter_flush failed in iobuf_pop_filter: %s\n", + gpg_strerror (rc)); + return rc; + } +- /* and tell the filter to free it self */ ++ /* and tell the filter to free it self */ + if (b->filter && (rc = b->filter (b->filter_ov, IOBUFCTRL_FREE, b->chain, + NULL, &dummy_len))) + { +@@ -1905,10 +1906,9 @@ iobuf_pop_filter (iobuf_t a, int (*f) (void *opaque, int control, + if (a == b && !b->chain) + log_bug ("can't remove the last filter from the chain\n"); + else if (a == b) +- { /* remove the first iobuf from the chain */ +- /* everything from b is copied to a. This is save because +- * a flush has been done on the to be removed entry +- */ ++ { /* Remove the first iobuf from the chain. ++ * Everything from B is copied to A. This is save because ++ * a flush has been done on the to be removed entry. */ + b = a->chain; + xfree (a->d.buf); + xfree (a->real_fname); +@@ -1918,11 +1918,11 @@ iobuf_pop_filter (iobuf_t a, int (*f) (void *opaque, int control, + log_debug ("iobuf-%d.%d: popped filter\n", a->no, a->subno); + } + else if (!b->chain) +- { /* remove the last iobuf from the chain */ ++ { /* Remove the last iobuf from the chain. */ + log_bug ("Ohh jeee, trying to remove a head filter\n"); + } + else +- { /* remove an intermediate iobuf from the chain */ ++ { /* Remove an intermediate iobuf from the chain. */ + log_bug ("Ohh jeee, trying to remove an intermediate filter\n"); + } + +@@ -1958,17 +1958,19 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target) + (int) (a->d.size - (a->d.len - a->d.start))); + + if (a->use == IOBUF_INPUT_TEMP) +- /* By definition, there isn't more data to read into the +- buffer. */ +- return -1; ++ { ++ /* By definition, there isn't more data to read into the ++ buffer. */ ++ return -1; ++ } + + log_assert (a->use == IOBUF_INPUT); + + a->e_d.used = 0; + + /* If there is still some buffered data, then move it to the start +- of the buffer and try to fill the end of the buffer. (This is +- useful if we are called from iobuf_peek().) */ ++ * of the buffer and try to fill the end of the buffer. (This is ++ * useful if we are called from iobuf_peek().) */ + log_assert (a->d.start <= a->d.len); + a->d.len -= a->d.start; + if (a->d.len) +@@ -1976,11 +1978,11 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target) + a->d.start = 0; + + if (a->d.len < target && a->filter_eof) +- /* The last time we tried to read from this filter, we got an EOF. +- We couldn't return the EOF, because there was buffered data. +- Since there is no longer any buffered data, return the +- error. */ + { ++ /* The last time we tried to read from this filter, we got an ++ * EOF. We couldn't return the EOF, because there was buffered ++ * data. Since there is no longer any buffered data, return the ++ * error. */ + if (DBG_IOBUF) + log_debug ("iobuf-%d.%d: underflow: eof (pending eof)\n", + a->no, a->subno); +@@ -1988,8 +1990,8 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target) + return -1; + + if (a->chain) +- /* A filter follows this one. Free this filter. */ + { ++ /* A filter follows this one. Free this filter. */ + iobuf_t b = a->chain; + if (DBG_IOBUF) + log_debug ("iobuf-%d.%d: filter popped (pending EOF returned)\n", +@@ -2006,11 +2008,11 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target) + } + + if (a->d.len == 0 && a->error) +- /* The last time we tried to read from this filter, we got an +- error. We couldn't return the error, because there was +- buffered data. Since there is no longer any buffered data, +- return the error. */ + { ++ /* The last time we tried to read from this filter, we got an ++ * error. We couldn't return the error, because there was ++ * buffered data. Since there is no longer any buffered data, ++ * return the error. */ + if (DBG_IOBUF) + log_debug ("iobuf-%d.%d: pending error (%s) returned\n", + a->no, a->subno, gpg_strerror (a->error)); +@@ -2018,10 +2020,10 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target) + } + + if (a->filter && ! a->filter_eof && ! a->error) +- /* We have a filter function and the last time we tried to read we +- didn't get an EOF or an error. Try to fill the buffer. */ + { +- /* Be careful to account for any buffered data. */ ++ /* We have a filter function and the last time we tried to read ++ * we didn't get an EOF or an error. Try to fill the buffer. ++ * Be careful to account for any buffered data. */ + len = a->d.size - a->d.len; + + if (a->e_d.preferred && a->d.len < IOBUF_ZEROCOPY_THRESHOLD_SIZE +@@ -2034,51 +2036,54 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target) + } + + if (len == 0) +- /* There is no space for more data. Don't bother calling +- A->FILTER. */ +- rc = 0; ++ { ++ /* There is no space for more data. Don't bother calling ++ * A->FILTER. */ ++ rc = 0; ++ } + else +- { +- /* If no buffered data and drain buffer has been setup, and drain +- * buffer is largish, read data directly to drain buffer. */ +- if (a->d.len == 0 +- && a->e_d.buf +- && a->e_d.len >= IOBUF_ZEROCOPY_THRESHOLD_SIZE) +- { +- len = a->e_d.len; +- +- if (DBG_IOBUF) +- log_debug ("iobuf-%d.%d: underflow: A->FILTER (%lu bytes, to external drain)\n", +- a->no, a->subno, (ulong)len); ++ { ++ /* If no buffered data and drain buffer has been setup, and ++ * drain buffer is largish, read data directly to drain buffer. */ ++ if (a->d.len == 0 ++ && a->e_d.buf ++ && a->e_d.len >= IOBUF_ZEROCOPY_THRESHOLD_SIZE) ++ { ++ len = a->e_d.len; + +- rc = a->filter (a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain, +- a->e_d.buf, &len); +- a->e_d.used = len; +- len = 0; +- } +- else +- { +- if (DBG_IOBUF) +- log_debug ("iobuf-%d.%d: underflow: A->FILTER (%lu bytes)\n", +- a->no, a->subno, (ulong)len); ++ if (DBG_IOBUF) ++ log_debug ("iobuf-%d.%d: underflow:" ++ " A->FILTER (%lu bytes, to external drain)\n", ++ a->no, a->subno, (ulong)len); ++ ++ rc = a->filter (a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain, ++ a->e_d.buf, &len); ++ a->e_d.used = len; ++ len = 0; ++ } ++ else ++ { ++ if (DBG_IOBUF) ++ log_debug ("iobuf-%d.%d: underflow: A->FILTER (%lu bytes)\n", ++ a->no, a->subno, (ulong)len); + +- rc = a->filter (a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain, +- &a->d.buf[a->d.len], &len); +- } +- } ++ rc = a->filter (a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain, ++ &a->d.buf[a->d.len], &len); ++ } ++ } + a->d.len += len; + + if (DBG_IOBUF) +- log_debug ("iobuf-%d.%d: A->FILTER() returned rc=%d (%s), read %lu bytes%s\n", ++ log_debug ("iobuf-%d.%d: A->FILTER() returned rc=%d (%s)," ++ " read %lu bytes%s\n", + a->no, a->subno, + rc, rc == 0 ? "ok" : rc == -1 ? "EOF" : gpg_strerror (rc), + (ulong)(a->e_d.used ? a->e_d.used : len), + a->e_d.used ? " (to external buffer)" : ""); +-/* if( a->no == 1 ) */ +-/* log_hexdump (" data:", a->d.buf, len); */ ++ /* if ( a->no == 1 ) */ ++ /* log_hexdump (" data:", a->d.buf, len); */ + +- if (rc == -1) +- /* EOF. */ ++ if (rc == -1) /* EOF. */ + { + size_t dummy_len = 0; + +@@ -2096,39 +2101,40 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target) + + if (clear_pending_eof && a->d.len == 0 && a->e_d.used == 0 + && a->chain) +- /* We don't need to keep this filter around at all: +- +- - we got an EOF +- - we have no buffered data +- - a filter follows this one. +- +- Unlink this filter. */ + { ++ /* We don't need to keep this filter around at all: ++ * ++ * - we got an EOF ++ * - we have no buffered data ++ * - a filter follows this one. ++ * ++ * Unlink this filter. */ + iobuf_t b = a->chain; + if (DBG_IOBUF) +- log_debug ("iobuf-%d.%d: pop in underflow (nothing buffered, got EOF)\n", +- a->no, a->subno); ++ log_debug ("iobuf-%d.%d: pop in underflow" ++ " (nothing buffered, got EOF)\n", a->no, a->subno); + xfree (a->d.buf); + xfree (a->real_fname); + memcpy (a, b, sizeof *a); + xfree (b); + + print_chain (a); +- + return -1; + } + else if (a->d.len == 0 && a->e_d.used == 0) +- /* We can't unlink this filter (it is the only one in the +- pipeline), but we can immediately return EOF. */ +- return -1; ++ { ++ /* We can't unlink this filter (it is the only one in ++ * the pipeline), but we can immediately return EOF. */ ++ return -1; ++ } ++ + } +- else if (rc) +- /* Record the error. */ ++ else if (rc) /* Record the error. */ + { + a->error = rc; + ++ /* If there is no buffered data, immediately return EOF. */ + if (a->d.len == 0 && a->e_d.used == 0) +- /* There is no buffered data. Immediately return EOF. */ + return -1; + } + } +@@ -2139,8 +2145,7 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target) + if (a->d.start < a->d.len) + return a->d.buf[a->d.start++]; + +- /* EOF. */ +- return -1; ++ return -1; /* EOF. */ + } + + +@@ -2156,7 +2161,7 @@ filter_flush (iobuf_t a) + a->e_d.used = 0; + + if (a->use == IOBUF_OUTPUT_TEMP) +- { /* increase the temp buffer */ ++ { /* Increase the temp buffer. */ + size_t newsize = a->d.size + iobuf_buffer_size; + + if (DBG_IOBUF) +-- +2.51.0 + diff -Nru gnupg2-2.4.8/debian/patches/gpg-Fix-possible-memory-corruption-in-the-armor-pars.patch gnupg2-2.4.8/debian/patches/gpg-Fix-possible-memory-corruption-in-the-armor-pars.patch --- gnupg2-2.4.8/debian/patches/gpg-Fix-possible-memory-corruption-in-the-armor-pars.patch 1970-01-01 01:00:00.000000000 +0100 +++ gnupg2-2.4.8/debian/patches/gpg-Fix-possible-memory-corruption-in-the-armor-pars.patch 2025-12-28 22:13:44.000000000 +0100 @@ -0,0 +1,107 @@ +From: Werner Koch <[email protected]> +Date: Thu, 23 Oct 2025 11:36:04 +0200 +Subject: gpg: Fix possible memory corruption in the armor parser. +Origin: https://github.com/gpg/gnupg/commit/115d138ba599328005c5321c0ef9f00355838ca9 +Bug-Debian: https://bugs.debian.org/1124221 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2025-68973 + +* g10/armor.c (armor_filter): Fix faulty double increment. + +* common/iobuf.c (underflow_target): Assert that the filter +implementations behave well. +-- + +This fixes a bug in a code path which can only be reached with special +crafted input data and would then error out at an upper layer due to +corrupt input (every second byte in the buffer is unitialized +garbage). No fuzzing has yet hit this case and we don't have a test +case for this code path. However memory corruption can never be +tolerated as it always has the protential for remode code execution. + +Reported-by: 8b79fe4dd0581c1cd000e1fbecba9f39e16a396a +Fixes-commit: c27c7416d5148865a513e007fb6f0a34993a6073 +which fixed +Fixes-commit: 7d0efec7cf5ae110c99511abc32587ff0c45b14f + +The bug was introduced on 1999-01-07 by me: +* armor.c: Rewrote large parts. +which I fixed on 1999-03-02 but missed to fix the other case: +* armor.c (armor_filter): Fixed armor bypassing. + +Below is base64+gzipped test data which can be used with valgrind to +show access to uninitalized memory in write(2) in the unpatched code. + +--8<---------------cut here---------------start------------->8--- +H4sICIDd+WgCA3h4AO3QMQ6CQBCG0djOKbY3G05gscYFSRAJt/AExp6Di0cQG0ze +a//MV0zOq3Pt+jFN3ZTKfLvP9ZLafqifJUe8juOjeZbVtSkbRPmRgICAgICAgICA +gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA +gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA +gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA +gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA +gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA +gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA +gICAgICAgICAgICAgICAgICAgICAgICAgMCXF6dYDgAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7E14AAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwZ94aieId3+8EAA== +--8<---------------cut here---------------end--------------->8--- +--- + common/iobuf.c | 6 ++++++ + g10/armor.c | 4 ++-- + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/common/iobuf.c b/common/iobuf.c +index 8a128b3f6c5d..769df958ded3 100644 +--- a/common/iobuf.c ++++ b/common/iobuf.c +@@ -2043,6 +2043,8 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target) + } + else + { ++ size_t tmplen; ++ + /* If no buffered data and drain buffer has been setup, and + * drain buffer is largish, read data directly to drain buffer. */ + if (a->d.len == 0 +@@ -2056,8 +2058,10 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target) + " A->FILTER (%lu bytes, to external drain)\n", + a->no, a->subno, (ulong)len); + ++ tmplen = len; /* Used to check for bugs in the filter. */ + rc = a->filter (a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain, + a->e_d.buf, &len); ++ log_assert (len <= tmplen); + a->e_d.used = len; + len = 0; + } +@@ -2067,8 +2071,10 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target) + log_debug ("iobuf-%d.%d: underflow: A->FILTER (%lu bytes)\n", + a->no, a->subno, (ulong)len); + ++ tmplen = len; + rc = a->filter (a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain, + &a->d.buf[a->d.len], &len); ++ log_assert (len <= tmplen); + } + } + a->d.len += len; +diff --git a/g10/armor.c b/g10/armor.c +index 036b72772717..59a6202aa4bc 100644 +--- a/g10/armor.c ++++ b/g10/armor.c +@@ -1312,8 +1312,8 @@ armor_filter( void *opaque, int control, + n = 0; + if( afx->buffer_len ) { + /* Copy the data from AFX->BUFFER to BUF. */ +- for(; n < size && afx->buffer_pos < afx->buffer_len; n++ ) +- buf[n++] = afx->buffer[afx->buffer_pos++]; ++ for(; n < size && afx->buffer_pos < afx->buffer_len;) ++ buf[n++] = afx->buffer[afx->buffer_pos++]; + if( afx->buffer_pos >= afx->buffer_len ) + afx->buffer_len = 0; + } +-- +2.51.0 + diff -Nru gnupg2-2.4.8/debian/patches/series gnupg2-2.4.8/debian/patches/series --- gnupg2-2.4.8/debian/patches/series 2025-10-22 22:39:23.000000000 +0200 +++ gnupg2-2.4.8/debian/patches/series 2025-12-28 22:13:56.000000000 +0100 @@ -43,3 +43,5 @@ debian-packaging/no-keyboxd.patch gpgv-Avoid-Assuan-and-NPth-dependencies.patch nl.po.update.diff +common-Reformat-some-comments-in-iobuf.c.patch +gpg-Fix-possible-memory-corruption-in-the-armor-pars.patch

