|
| 1 | +From bc8e94b03af106b7f481abb36d8a8d5fdf723c77 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Werner Koch <wk@gnupg.org> |
| 3 | +Date: Thu, 23 Oct 2025 11:36:04 +0200 |
| 4 | +Subject: [PATCH] gpg: Fix possible memory corruption in the armor parser. |
| 5 | + |
| 6 | +* g10/armor.c (armor_filter): Fix faulty double increment. |
| 7 | + |
| 8 | +* common/iobuf.c (underflow_target): Assert that the filter |
| 9 | +implementations behave well. |
| 10 | +-- |
| 11 | + |
| 12 | +This fixes a bug in a code path which can only be reached with special |
| 13 | +crafted input data and would then error out at an upper layer due to |
| 14 | +corrupt input (every second byte in the buffer is unitialized |
| 15 | +garbage). No fuzzing has yet hit this case and we don't have a test |
| 16 | +case for this code path. However memory corruption can never be |
| 17 | +tolerated as it always has the protential for remode code execution. |
| 18 | + |
| 19 | +Reported-by: 8b79fe4dd0581c1cd000e1fbecba9f39e16a396a |
| 20 | +Fixes-commit: c27c7416d5148865a513e007fb6f0a34993a6073 |
| 21 | +which fixed |
| 22 | +Fixes-commit: 7d0efec7cf5ae110c99511abc32587ff0c45b14f |
| 23 | +Backported-from-master: 115d138ba599328005c5321c0ef9f00355838ca9 |
| 24 | + |
| 25 | +The bug was introduced on 1999-01-07 by me: |
| 26 | +* armor.c: Rewrote large parts. |
| 27 | +which I fixed on 1999-03-02 but missed to fix the other case: |
| 28 | +* armor.c (armor_filter): Fixed armor bypassing. |
| 29 | + |
| 30 | +Below is base64+gzipped test data which can be used with valgrind to |
| 31 | +show access to uninitalized memory in write(2) in the unpatched code. |
| 32 | + |
| 33 | +--8<---------------cut here---------------start------------->8--- |
| 34 | +H4sICIDd+WgCA3h4AO3QMQ6CQBCG0djOKbY3G05gscYFSRAJt/AExp6Di0cQG0ze |
| 35 | +a//MV0zOq3Pt+jFN3ZTKfLvP9ZLafqifJUe8juOjeZbVtSkbRPmRgICAgICAgICA |
| 36 | +gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA |
| 37 | +gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA |
| 38 | +gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA |
| 39 | +gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA |
| 40 | +gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA |
| 41 | +gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA |
| 42 | +gICAgICAgICAgICAgICAgICAgICAgICAgMCXF6dYDgAAAAAAAAAAAAAAAAAAAAAA |
| 43 | +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7E14AAAAA |
| 44 | +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
| 45 | +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
| 46 | +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
| 47 | +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwZ94aieId3+8EAA== |
| 48 | +--8<---------------cut here---------------end--------------->8--- |
| 49 | + |
| 50 | +Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> |
| 51 | +Upstream-reference: https://github.com/gpg/gnupg/commit/4ecc5122f20e10c17172ed72f4fa46c784b5fb48.patch |
| 52 | +--- |
| 53 | + common/iobuf.c | 8 +++++++- |
| 54 | + g10/armor.c | 4 ++-- |
| 55 | + 2 files changed, 9 insertions(+), 3 deletions(-) |
| 56 | + |
| 57 | +diff --git a/common/iobuf.c b/common/iobuf.c |
| 58 | +index 86bb296..368055b 100644 |
| 59 | +--- a/common/iobuf.c |
| 60 | ++++ b/common/iobuf.c |
| 61 | +@@ -1933,6 +1933,8 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target) |
| 62 | + rc = 0; |
| 63 | + else |
| 64 | + { |
| 65 | ++ size_t tmplen; |
| 66 | ++ |
| 67 | + /* If no buffered data and drain buffer has been setup, and drain |
| 68 | + * buffer is largish, read data directly to drain buffer. */ |
| 69 | + if (a->d.len == 0 |
| 70 | +@@ -1945,8 +1947,10 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target) |
| 71 | + log_debug ("iobuf-%d.%d: underflow: A->FILTER (%lu bytes, to external drain)\n", |
| 72 | + a->no, a->subno, (ulong)len); |
| 73 | + |
| 74 | +- rc = a->filter (a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain, |
| 75 | ++ tmplen = len; /* Used to check for bugs in the filter. */ |
| 76 | ++ rc = a->filter (a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain, |
| 77 | + a->e_d.buf, &len); |
| 78 | ++ log_assert (len <= tmplen); |
| 79 | + a->e_d.used = len; |
| 80 | + len = 0; |
| 81 | + } |
| 82 | +@@ -1956,8 +1960,10 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target) |
| 83 | + log_debug ("iobuf-%d.%d: underflow: A->FILTER (%lu bytes)\n", |
| 84 | + a->no, a->subno, (ulong)len); |
| 85 | + |
| 86 | ++ tmplen = len; /* Used to check for bugs in the filter. */ |
| 87 | + rc = a->filter (a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain, |
| 88 | + &a->d.buf[a->d.len], &len); |
| 89 | ++ log_assert (len <= tmplen); |
| 90 | + } |
| 91 | + } |
| 92 | + a->d.len += len; |
| 93 | +diff --git a/g10/armor.c b/g10/armor.c |
| 94 | +index b47c04a..39294e2 100644 |
| 95 | +--- a/g10/armor.c |
| 96 | ++++ b/g10/armor.c |
| 97 | +@@ -1302,8 +1302,8 @@ armor_filter( void *opaque, int control, |
| 98 | + n = 0; |
| 99 | + if( afx->buffer_len ) { |
| 100 | + /* Copy the data from AFX->BUFFER to BUF. */ |
| 101 | +- for(; n < size && afx->buffer_pos < afx->buffer_len; n++ ) |
| 102 | +- buf[n++] = afx->buffer[afx->buffer_pos++]; |
| 103 | ++ for(; n < size && afx->buffer_pos < afx->buffer_len;) |
| 104 | ++ buf[n++] = afx->buffer[afx->buffer_pos++]; |
| 105 | + if( afx->buffer_pos >= afx->buffer_len ) |
| 106 | + afx->buffer_len = 0; |
| 107 | + } |
| 108 | +-- |
| 109 | +2.45.4 |
| 110 | + |
0 commit comments