From f0f71a721ccd7ab9e40b8b6b028b59632c0cc648 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 9 Feb 2015 15:46:00 +0100 Subject: [PATCH] gpg: Prevent an invalid memory read using a garbled keyring. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * g10/keyring.c (keyring_get_keyblock): Whitelist allowed packet types. * g10/keydb.c (parse_keyblock_image): Ditto. -- The keyring DB code did not reject packets which don't belong into a keyring. If for example the keyblock contains a literal data packet it is expected that the processing code stops at the data packet and reads from the input stream which is referenced from the data packets. Obviously the keyring processing code does not and cannot do that. However, when exporting this messes up the IOBUF and leads to an invalid read of sizeof (int). We now skip all packets which are not allowed in a keyring. Reported-by: Hanno Böck Test data: gpg2 --no-default-keyring --keyring FILE --export >/dev/null With this unpacked data for FILE: -----BEGIN PGP ARMORED FILE----- mI0EVNP2zQEEALvETPVDCJDBXkegF4esiV1fqlne40yJnCmJeDEJYocwFPXfFA86 sSGjInzgDbpbC9gQPwq91Qe9x3Vy81CkyVonPOejhINlzfpzqAAa3A6viJccZTwt DJ8E/I9jg53sbYW8q+VgfLn1hlggH/XQRT0HkXMP5y9ClURYnTsNwJhXABEBAAGs CXRlc3QgdGVzdIi5BBMBCgAjBQJU0/bNAhsDBwsJCAcDAgEGFQgCCQoLBBYCAwEC HgECF4AACgkQlsmuCapsqYLvtQP/byY0tM0Lc3moftbHQZ2eHj9ykLjsCjeMDfPx kZUUtUS3HQaqgZLZOeqPjM7XgGh5hJsd9pfhmRWJ0x+iGB47XQNpRTtdLBV/WMCS l5z3uW7e9Md7QVUVuSlJnBgQHTS6EgP8JQadPkAiF+jgpJZXP+gFs2j3gobS0qUF eyTtxs+wAgAD =uIt9 -----END PGP ARMORED FILE----- Signed-off-by: Werner Koch --- g10/keydb.c | 27 ++++++++++++++++++--------- g10/keyring.c | 27 +++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/g10/keydb.c b/g10/keydb.c index 401478a1d..cf422a879 100644 --- a/g10/keydb.c +++ b/g10/keydb.c @@ -771,21 +771,30 @@ parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no, err = gpg_error (GPG_ERR_INV_KEYRING); break; } - if (pkt->pkttype == PKT_COMPRESSED) + + /* Filter allowed packets. */ + switch (pkt->pkttype) { - log_error ("skipped compressed packet in keybox blob\n"); - free_packet(pkt); - init_packet(pkt); - continue; - } - if (pkt->pkttype == PKT_RING_TRUST) - { - log_info ("skipped ring trust packet in keybox blob\n"); + case PKT_PUBLIC_KEY: + case PKT_PUBLIC_SUBKEY: + case PKT_SECRET_KEY: + case PKT_SECRET_SUBKEY: + case PKT_USER_ID: + case PKT_ATTRIBUTE: + case PKT_SIGNATURE: + break; /* Allowed per RFC. */ + + default: + /* Note that can't allow ring trust packets here and some of + the other GPG specific packets don't make sense either. */ + log_error ("skipped packet of type %d in keybox\n", + (int)pkt->pkttype); free_packet(pkt); init_packet(pkt); continue; } + /* Other sanity checks. */ if (!in_cert && pkt->pkttype != PKT_PUBLIC_KEY) { log_error ("parse_keyblock_image: first packet in a keybox blob " diff --git a/g10/keyring.c b/g10/keyring.c index 6060f0894..ee76e8a33 100644 --- a/g10/keyring.c +++ b/g10/keyring.c @@ -406,12 +406,31 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb) rc = GPG_ERR_INV_KEYRING; break; } - if (pkt->pkttype == PKT_COMPRESSED) { - log_error ("skipped compressed packet in keyring\n"); + + /* Filter allowed packets. */ + switch (pkt->pkttype) + { + case PKT_PUBLIC_KEY: + case PKT_PUBLIC_SUBKEY: + case PKT_SECRET_KEY: + case PKT_SECRET_SUBKEY: + case PKT_USER_ID: + case PKT_ATTRIBUTE: + case PKT_SIGNATURE: + break; /* Allowed per RFC. */ + case PKT_RING_TRUST: + case PKT_OLD_COMMENT: + case PKT_COMMENT: + case PKT_GPG_CONTROL: + break; /* Allowed by us. */ + + default: + log_error ("skipped packet of type %d in keyring\n", + (int)pkt->pkttype); free_packet(pkt); init_packet(pkt); continue; - } + } if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY || pkt->pkttype == PKT_SECRET_KEY)) { @@ -478,7 +497,7 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb) if (rc || !ret_kb) release_kbnode (keyblock); else { - /*(duplicated form the loop body)*/ + /*(duplicated from the loop body)*/ if ( pkt && pkt->pkttype == PKT_RING_TRUST && lastnode && lastnode->pkt->pkttype == PKT_SIGNATURE