diff options
| author | Gyorgy Sarvari <skandigraun@gmail.com> | 2026-02-27 16:40:31 +0100 |
|---|---|---|
| committer | Gyorgy Sarvari <skandigraun@gmail.com> | 2026-02-27 17:00:35 +0100 |
| commit | 331ff3f94b22a65ae15a744cdeffd02771d8394f (patch) | |
| tree | fccc2cf349db68d43f4d4d4a2887ee0e75e38d23 | |
| parent | 7fd8cd657fe0836020116fd1633fe15cdb646df4 (diff) | |
| download | meta-openembedded-331ff3f94b22a65ae15a744cdeffd02771d8394f.tar.gz | |
dovecot: patch CVE-2021-29157
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 <skandigraun@gmail.com>
| -rw-r--r-- | meta-networking/recipes-support/dovecot/dovecot/CVE-2021-29157.patch | 152 | ||||
| -rw-r--r-- | meta-networking/recipes-support/dovecot/dovecot_2.3.14.bb | 1 |
2 files changed, 153 insertions, 0 deletions
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 @@ | |||
| 1 | From 1ee6540ef6ffa8cefade0161f4dcd47d82a1d10b Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Gyorgy Sarvari <skandigraun@gmail.com> | ||
| 3 | Date: Fri, 27 Feb 2026 16:10:35 +0100 | ||
| 4 | Subject: [PATCH] Fix CVE-2021-29157 | ||
| 5 | |||
| 6 | CVE: CVE-2021-29157 | ||
| 7 | 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] | ||
| 8 | Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com> | ||
| 9 | --- | ||
| 10 | src/lib-dict-extra/dict-fs.c | 29 ++++++++++++++++ | ||
| 11 | src/lib-oauth2/oauth2-jwt.c | 58 ++++++++++++++++++-------------- | ||
| 12 | src/lib-oauth2/test-oauth2-jwt.c | 2 +- | ||
| 13 | 3 files changed, 62 insertions(+), 27 deletions(-) | ||
| 14 | |||
| 15 | diff --git a/src/lib-dict-extra/dict-fs.c b/src/lib-dict-extra/dict-fs.c | ||
| 16 | index 31af578..f39c86c 100644 | ||
| 17 | --- a/src/lib-dict-extra/dict-fs.c | ||
| 18 | +++ b/src/lib-dict-extra/dict-fs.c | ||
| 19 | @@ -68,8 +68,37 @@ static void fs_dict_deinit(struct dict *_dict) | ||
| 20 | i_free(dict); | ||
| 21 | } | ||
| 22 | |||
| 23 | +/* Remove unsafe paths */ | ||
| 24 | +static const char *fs_dict_escape_key(const char *key) | ||
| 25 | +{ | ||
| 26 | + const char *ptr; | ||
| 27 | + string_t *new_key = NULL; | ||
| 28 | + /* we take the slow path always if we see potential | ||
| 29 | + need for escaping */ | ||
| 30 | + while ((ptr = strstr(key, "/.")) != NULL) { | ||
| 31 | + /* move to the first dot */ | ||
| 32 | + const char *ptr2 = ptr + 1; | ||
| 33 | + /* find position of non-dot */ | ||
| 34 | + while (*ptr2 == '.') ptr2++; | ||
| 35 | + if (new_key == NULL) | ||
| 36 | + new_key = t_str_new(strlen(key)); | ||
| 37 | + str_append_data(new_key, key, ptr - key); | ||
| 38 | + /* if ptr2 is / or end of string, escape */ | ||
| 39 | + if (*ptr2 == '/' || *ptr2 == '\0') | ||
| 40 | + str_append(new_key, "/..."); | ||
| 41 | + else | ||
| 42 | + str_append(new_key, "/."); | ||
| 43 | + key = ptr + 2; | ||
| 44 | + } | ||
| 45 | + if (new_key == NULL) | ||
| 46 | + return key; | ||
| 47 | + str_append(new_key, key); | ||
| 48 | + return str_c(new_key); | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | static const char *fs_dict_get_full_key(struct fs_dict *dict, const char *key) | ||
| 52 | { | ||
| 53 | + key = fs_dict_escape_key(key); | ||
| 54 | if (str_begins(key, DICT_PATH_SHARED)) | ||
| 55 | return key + strlen(DICT_PATH_SHARED); | ||
| 56 | else if (str_begins(key, DICT_PATH_PRIVATE)) { | ||
| 57 | diff --git a/src/lib-oauth2/oauth2-jwt.c b/src/lib-oauth2/oauth2-jwt.c | ||
| 58 | index 83b241c..8e43cf9 100644 | ||
| 59 | --- a/src/lib-oauth2/oauth2-jwt.c | ||
| 60 | +++ b/src/lib-oauth2/oauth2-jwt.c | ||
| 61 | @@ -277,6 +277,34 @@ oauth2_jwt_copy_fields(ARRAY_TYPE(oauth2_field) *fields, struct json_tree *tree) | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | +/* Escapes '/' and '%' in identifier to %hex */ | ||
| 66 | +static const char *escape_identifier(const char *identifier) | ||
| 67 | +{ | ||
| 68 | + size_t pos = strcspn(identifier, "/%"); | ||
| 69 | + /* nothing to escape */ | ||
| 70 | + if (identifier[pos] == '\0') | ||
| 71 | + return identifier; | ||
| 72 | + | ||
| 73 | + size_t len = strlen(identifier); | ||
| 74 | + string_t *new_id = t_str_new(len); | ||
| 75 | + str_append_data(new_id, identifier, pos); | ||
| 76 | + | ||
| 77 | + for (size_t i = pos; i < len; i++) { | ||
| 78 | + switch (identifier[i]) { | ||
| 79 | + case '/': | ||
| 80 | + str_append(new_id, "%2f"); | ||
| 81 | + break; | ||
| 82 | + case '%': | ||
| 83 | + str_append(new_id, "%25"); | ||
| 84 | + break; | ||
| 85 | + default: | ||
| 86 | + str_append_c(new_id, identifier[i]); | ||
| 87 | + break; | ||
| 88 | + } | ||
| 89 | + } | ||
| 90 | + return str_c(new_id); | ||
| 91 | +} | ||
| 92 | + | ||
| 93 | static int | ||
| 94 | oauth2_jwt_header_process(struct json_tree *tree, const char **alg_r, | ||
| 95 | const char **kid_r, const char **error_r) | ||
| 96 | @@ -377,6 +405,8 @@ oauth2_jwt_body_process(const struct oauth2_settings *set, const char *alg, | ||
| 97 | const char *azp = get_field(tree, "azp"); | ||
| 98 | if (azp == NULL) | ||
| 99 | azp = "default"; | ||
| 100 | + else | ||
| 101 | + azp = escape_identifier(azp); | ||
| 102 | |||
| 103 | if (oauth2_validate_signature(set, azp, alg, kid, blobs, error_r) < 0) | ||
| 104 | return -1; | ||
| 105 | @@ -429,32 +459,8 @@ int oauth2_try_parse_jwt(const struct oauth2_settings *set, | ||
| 106 | else if (*kid == '\0') { | ||
| 107 | *error_r = "'kid' field is empty"; | ||
| 108 | return -1; | ||
| 109 | - } | ||
| 110 | - | ||
| 111 | - size_t pos = strcspn(kid, "./%"); | ||
| 112 | - if (pos < strlen(kid)) { | ||
| 113 | - /* sanitize kid, cannot allow dots or / in it, so we encode them | ||
| 114 | - */ | ||
| 115 | - string_t *new_kid = t_str_new(strlen(kid)); | ||
| 116 | - /* put initial data */ | ||
| 117 | - str_append_data(new_kid, kid, pos); | ||
| 118 | - for (const char *c = kid+pos; *c != '\0'; c++) { | ||
| 119 | - switch (*c) { | ||
| 120 | - case '.': | ||
| 121 | - str_append(new_kid, "%2e"); | ||
| 122 | - break; | ||
| 123 | - case '/': | ||
| 124 | - str_append(new_kid, "%2f"); | ||
| 125 | - break; | ||
| 126 | - case '%': | ||
| 127 | - str_append(new_kid, "%25"); | ||
| 128 | - break; | ||
| 129 | - default: | ||
| 130 | - str_append_c(new_kid, *c); | ||
| 131 | - break; | ||
| 132 | - } | ||
| 133 | - } | ||
| 134 | - kid = str_c(new_kid); | ||
| 135 | + } else { | ||
| 136 | + kid = escape_identifier(kid); | ||
| 137 | } | ||
| 138 | |||
| 139 | /* parse body */ | ||
| 140 | diff --git a/src/lib-oauth2/test-oauth2-jwt.c b/src/lib-oauth2/test-oauth2-jwt.c | ||
| 141 | index 4cfba64..1706a96 100644 | ||
| 142 | --- a/src/lib-oauth2/test-oauth2-jwt.c | ||
| 143 | +++ b/src/lib-oauth2/test-oauth2-jwt.c | ||
| 144 | @@ -577,7 +577,7 @@ static void test_jwt_kid_escape(void) | ||
| 145 | random_fill(ptr, 32); | ||
| 146 | buffer_t *b64_key = t_base64_encode(0, SIZE_MAX, | ||
| 147 | secret->data, secret->used); | ||
| 148 | - save_key_to("HS256", "hello%2eworld%2f%25", str_c(b64_key)); | ||
| 149 | + save_key_to("HS256", "hello.world%2f%25", str_c(b64_key)); | ||
| 150 | /* make a token */ | ||
| 151 | buffer_t *tokenbuf = create_jwt_token_kid("HS256", "hello.world/%"); | ||
| 152 | /* 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 \ | |||
| 13 | file://0001-m4-Check-for-libunwind-instead-of-libunwind-generic.patch \ | 13 | file://0001-m4-Check-for-libunwind-instead-of-libunwind-generic.patch \ |
| 14 | file://0001-auth-Fix-handling-passdbs-with-identical-driver-args.patch \ | 14 | file://0001-auth-Fix-handling-passdbs-with-identical-driver-args.patch \ |
| 15 | file://0001-lib-smtp-smtp-server-connection-Fix-STARTTLS-command.patch \ | 15 | file://0001-lib-smtp-smtp-server-connection-Fix-STARTTLS-command.patch \ |
| 16 | file://CVE-2021-29157.patch \ | ||
| 16 | " | 17 | " |
| 17 | 18 | ||
| 18 | SRC_URI[md5sum] = "2f03532cec3280ae45a101a7a55ccef5" | 19 | SRC_URI[md5sum] = "2f03532cec3280ae45a101a7a55ccef5" |
