Details: https://nvd.nist.gov/vuln/detail/CVE-2021-29157

Backport the patch that it used by Debian[1] to fix this CVE.

[1]: 
https://sources.debian.org/src/dovecot/1%3A2.3.13%2Bdfsg1-2%2Bdeb11u1/debian/patches
Signed-off-by: Gyorgy Sarvari <[email protected]>
---
 .../dovecot/dovecot/CVE-2021-29157.patch      | 152 ++++++++++++++++++
 .../recipes-support/dovecot/dovecot_2.3.14.bb |   1 +
 2 files changed, 153 insertions(+)
 create mode 100644 
meta-networking/recipes-support/dovecot/dovecot/CVE-2021-29157.patch

diff --git 
a/meta-networking/recipes-support/dovecot/dovecot/CVE-2021-29157.patch 
b/meta-networking/recipes-support/dovecot/dovecot/CVE-2021-29157.patch
new file mode 100644
index 0000000000..cb0cba6f98
--- /dev/null
+++ b/meta-networking/recipes-support/dovecot/dovecot/CVE-2021-29157.patch
@@ -0,0 +1,152 @@
+From 1ee6540ef6ffa8cefade0161f4dcd47d82a1d10b Mon Sep 17 00:00:00 2001
+From: Gyorgy Sarvari <[email protected]>
+Date: Fri, 27 Feb 2026 16:10:35 +0100
+Subject: [PATCH] Fix CVE-2021-29157
+
+CVE: CVE-2021-29157
+Upstream-Status: Backport [the patch was taken from Debian: 
https://sources.debian.org/src/dovecot/1%3A2.3.13%2Bdfsg1-2%2Bdeb11u1/debian/patches/CVE-2021-29157.patch]
+Signed-off-by: Gyorgy Sarvari <[email protected]>
+---
+ src/lib-dict-extra/dict-fs.c     | 29 ++++++++++++++++
+ src/lib-oauth2/oauth2-jwt.c      | 58 ++++++++++++++++++--------------
+ src/lib-oauth2/test-oauth2-jwt.c |  2 +-
+ 3 files changed, 62 insertions(+), 27 deletions(-)
+
+diff --git a/src/lib-dict-extra/dict-fs.c b/src/lib-dict-extra/dict-fs.c
+index 31af578..f39c86c 100644
+--- a/src/lib-dict-extra/dict-fs.c
++++ b/src/lib-dict-extra/dict-fs.c
+@@ -68,8 +68,37 @@ static void fs_dict_deinit(struct dict *_dict)
+       i_free(dict);
+ }
+ 
++/* Remove unsafe paths */
++static const char *fs_dict_escape_key(const char *key)
++{
++      const char *ptr;
++      string_t *new_key = NULL;
++      /* we take the slow path always if we see potential
++         need for escaping */
++      while ((ptr = strstr(key, "/.")) != NULL) {
++              /* move to the first dot */
++              const char *ptr2 = ptr + 1;
++              /* find position of non-dot */
++              while (*ptr2 == '.') ptr2++;
++              if (new_key == NULL)
++                      new_key = t_str_new(strlen(key));
++              str_append_data(new_key, key, ptr - key);
++              /* if ptr2 is / or end of string, escape */
++              if (*ptr2 == '/' || *ptr2 == '\0')
++                      str_append(new_key, "/...");
++              else
++                      str_append(new_key, "/.");
++              key = ptr + 2;
++      }
++      if (new_key == NULL)
++              return key;
++      str_append(new_key, key);
++      return str_c(new_key);
++}
++
+ static const char *fs_dict_get_full_key(struct fs_dict *dict, const char *key)
+ {
++      key = fs_dict_escape_key(key);
+       if (str_begins(key, DICT_PATH_SHARED))
+               return key + strlen(DICT_PATH_SHARED);
+       else if (str_begins(key, DICT_PATH_PRIVATE)) {
+diff --git a/src/lib-oauth2/oauth2-jwt.c b/src/lib-oauth2/oauth2-jwt.c
+index 83b241c..8e43cf9 100644
+--- a/src/lib-oauth2/oauth2-jwt.c
++++ b/src/lib-oauth2/oauth2-jwt.c
+@@ -277,6 +277,34 @@ oauth2_jwt_copy_fields(ARRAY_TYPE(oauth2_field) *fields, 
struct json_tree *tree)
+       }
+ }
+ 
++/* Escapes '/' and '%' in identifier to %hex */
++static const char *escape_identifier(const char *identifier)
++{
++      size_t pos = strcspn(identifier, "/%");
++      /* nothing to escape */
++      if (identifier[pos] == '\0')
++              return identifier;
++
++      size_t len = strlen(identifier);
++      string_t *new_id = t_str_new(len);
++      str_append_data(new_id, identifier, pos);
++
++      for (size_t i = pos; i < len; i++) {
++              switch (identifier[i]) {
++              case '/':
++                      str_append(new_id, "%2f");
++                      break;
++              case '%':
++                      str_append(new_id, "%25");
++                      break;
++              default:
++                      str_append_c(new_id, identifier[i]);
++                      break;
++              }
++      }
++      return str_c(new_id);
++}
++
+ static int
+ oauth2_jwt_header_process(struct json_tree *tree, const char **alg_r,
+                         const char **kid_r, const char **error_r)
+@@ -377,6 +405,8 @@ oauth2_jwt_body_process(const struct oauth2_settings *set, 
const char *alg,
+       const char *azp = get_field(tree, "azp");
+       if (azp == NULL)
+               azp = "default";
++      else
++              azp = escape_identifier(azp);
+ 
+       if (oauth2_validate_signature(set, azp, alg, kid, blobs, error_r) < 0)
+               return -1;
+@@ -429,32 +459,8 @@ int oauth2_try_parse_jwt(const struct oauth2_settings 
*set,
+       else if (*kid == '\0') {
+               *error_r = "'kid' field is empty";
+               return -1;
+-      }
+-
+-      size_t pos = strcspn(kid, "./%");
+-      if (pos < strlen(kid)) {
+-              /* sanitize kid, cannot allow dots or / in it, so we encode them
+-               */
+-              string_t *new_kid = t_str_new(strlen(kid));
+-              /* put initial data */
+-              str_append_data(new_kid, kid, pos);
+-              for (const char *c = kid+pos; *c != '\0'; c++) {
+-                      switch (*c) {
+-                      case '.':
+-                              str_append(new_kid, "%2e");
+-                              break;
+-                      case '/':
+-                              str_append(new_kid, "%2f");
+-                              break;
+-                      case '%':
+-                              str_append(new_kid, "%25");
+-                              break;
+-                      default:
+-                              str_append_c(new_kid, *c);
+-                              break;
+-                      }
+-              }
+-              kid = str_c(new_kid);
++      } else {
++              kid = escape_identifier(kid);
+       }
+ 
+       /* parse body */
+diff --git a/src/lib-oauth2/test-oauth2-jwt.c 
b/src/lib-oauth2/test-oauth2-jwt.c
+index 4cfba64..1706a96 100644
+--- a/src/lib-oauth2/test-oauth2-jwt.c
++++ b/src/lib-oauth2/test-oauth2-jwt.c
+@@ -577,7 +577,7 @@ static void test_jwt_kid_escape(void)
+        random_fill(ptr, 32);
+        buffer_t *b64_key = t_base64_encode(0, SIZE_MAX,
+                                            secret->data, secret->used);
+-       save_key_to("HS256", "hello%2eworld%2f%25", str_c(b64_key));
++       save_key_to("HS256", "hello.world%2f%25", str_c(b64_key));
+       /* make a token */
+       buffer_t *tokenbuf = create_jwt_token_kid("HS256", "hello.world/%");
+       /* sign it */
diff --git a/meta-networking/recipes-support/dovecot/dovecot_2.3.14.bb 
b/meta-networking/recipes-support/dovecot/dovecot_2.3.14.bb
index c1fa702eaa..14303b4c08 100644
--- a/meta-networking/recipes-support/dovecot/dovecot_2.3.14.bb
+++ b/meta-networking/recipes-support/dovecot/dovecot_2.3.14.bb
@@ -13,6 +13,7 @@ SRC_URI = 
"http://dovecot.org/releases/2.3/dovecot-${PV}.tar.gz \
            
file://0001-m4-Check-for-libunwind-instead-of-libunwind-generic.patch \
            
file://0001-auth-Fix-handling-passdbs-with-identical-driver-args.patch \
            
file://0001-lib-smtp-smtp-server-connection-Fix-STARTTLS-command.patch \
+           file://CVE-2021-29157.patch \
            "
 
 SRC_URI[md5sum] = "2f03532cec3280ae45a101a7a55ccef5"
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#124760): 
https://lists.openembedded.org/g/openembedded-devel/message/124760
Mute This Topic: https://lists.openembedded.org/mt/118031977/21656
Group Owner: [email protected]
Unsubscribe: https://lists.openembedded.org/g/openembedded-devel/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to