summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwang biao <biao716.wang@samsung.com>2023-02-23 15:03:36 +0800
committerwang biao <biao716.wang@samsung.com>2023-02-23 16:15:25 +0800
commit4fbbeefc813b53bb3c9690a321c522991058a483 (patch)
tree5106942b6ac85a6cda6839f820dd22257e2d9c07
parent5746c1980a7000e123edd6837284dd5af3a12c9a (diff)
downloadrpm-4fbbeefc813b53bb3c9690a321c522991058a483.tar.gz
rpm-4fbbeefc813b53bb3c9690a321c522991058a483.tar.bz2
rpm-4fbbeefc813b53bb3c9690a321c522991058a483.zip
Fix CVE-2021-20266: hdrblobInit() needs bounds checks toosubmit/tizen_7.0_base/20230222.163040accepted/tizen/7.0/base/tool/20230227.052649
https://github.com/rpm-software-management/rpm/commit/8f4b3c3cab8922a2022b9e47c71f1ecf906077ef Fix CVE-2021-3521: Validate and require subkey binding signatures on PGP public keys https://github.com/rpm-software-management/rpm/commit/bd36c5dc9fb6d90c46fbfed8c2d67516fc571ec8 Change-Id: I3daeff22a4f7240923cb1eb82bc9822cd3737d86 Signed-off-by: wang biao <biao716.wang@samsung.com>
-rw-r--r--lib/header.c48
-rw-r--r--rpmio/rpmpgp.c108
-rw-r--r--tests/Makefile.am3
-rwxr-xr-xtests/data/keys/CVE-2021-3521-badbind.asc25
-rwxr-xr-xtests/data/keys/CVE-2021-3521-nosubsig-last.asc25
-rwxr-xr-xtests/data/keys/CVE-2021-3521-nosubsig.asc37
-rw-r--r--tests/rpmsigdig.at28
7 files changed, 249 insertions, 25 deletions
diff --git a/lib/header.c b/lib/header.c
index 0f6efe485..0d50f0daf 100644
--- a/lib/header.c
+++ b/lib/header.c
@@ -11,6 +11,7 @@
#include "system.h"
#include <netdb.h>
#include <errno.h>
+#include <inttypes.h>
#include <rpm/rpmtypes.h>
#include <rpm/rpmstring.h>
#include "lib/header_internal.h"
@@ -1851,6 +1852,25 @@ exit:
return rc;
}
+
+static rpmRC hdrblobVerifyLengths(rpmTagVal regionTag, uint32_t il, uint32_t dl,
+ char **emsg) {
+ uint32_t il_max = HEADER_TAGS_MAX;
+ uint32_t dl_max = HEADER_DATA_MAX;
+ if (regionTag == RPMTAG_HEADERSIGNATURES) {
+ il_max = 32;
+ dl_max = 64 * 1024 * 1024;
+ }
+ if (hdrchkRange(il_max, il)) {
+ rasprintf(emsg, _("hdr tags: BAD, no. of tags(%" PRIu32 ") out of range"), il);
+ return RPMRC_FAIL;
+ }
+ if (hdrchkRange(dl_max, dl)) {
+ rasprintf(emsg, _("hdr data: BAD, no. of bytes(%" PRIu32 ") out of range"), dl);
+ return RPMRC_FAIL;
+ }
+ return RPMRC_OK;
+}
rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrblob blob, char **emsg)
{
int32_t block[4];
@@ -1863,13 +1883,6 @@ rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrbl
size_t nb;
rpmRC rc = RPMRC_FAIL; /* assume failure */
int xx;
- int32_t il_max = HEADER_TAGS_MAX;
- int32_t dl_max = HEADER_DATA_MAX;
-
- if (regionTag == RPMTAG_HEADERSIGNATURES) {
- il_max = 32;
- dl_max = 8192;
- }
memset(block, 0, sizeof(block));
if ((xx = Freadall(fd, bs, blen)) != blen) {
@@ -1882,15 +1895,9 @@ rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrbl
goto exit;
}
il = ntohl(block[2]);
- if (hdrchkRange(il_max, il)) {
- rasprintf(emsg, _("hdr tags: BAD, no. of tags(%d) out of range"), il);
- goto exit;
- }
dl = ntohl(block[3]);
- if (hdrchkRange(dl_max, dl)) {
- rasprintf(emsg, _("hdr data: BAD, no. of bytes(%d) out of range"), dl);
+ if (hdrblobVerifyLengths(regionTag, il, dl, emsg))
goto exit;
- }
nb = (il * sizeof(struct entryInfo_s)) + dl;
uc = sizeof(il) + sizeof(dl) + nb;
@@ -1934,11 +1941,18 @@ rpmRC hdrblobInit(const void *uh, size_t uc,
struct hdrblob_s *blob, char **emsg)
{
rpmRC rc = RPMRC_FAIL;
-
memset(blob, 0, sizeof(*blob));
+ if (uc && uc < 8) {
+ rasprintf(emsg, _("hdr length: BAD"));
+ goto exit;
+ }
+
blob->ei = (int32_t *) uh; /* discards const */
- blob->il = ntohl(blob->ei[0]);
- blob->dl = ntohl(blob->ei[1]);
+ blob->il = ntohl((uint32_t)(blob->ei[0]));
+ blob->dl = ntohl((uint32_t)(blob->ei[1]));
+ if (hdrblobVerifyLengths(regionTag, blob->il, blob->dl, emsg) != RPMRC_OK)
+ goto exit;
+
blob->pe = (entryInfo) &(blob->ei[2]);
blob->pvlen = sizeof(blob->il) + sizeof(blob->dl) +
(blob->il * sizeof(*blob->pe)) + blob->dl;
diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c
index 061751a4d..15cce2275 100644
--- a/rpmio/rpmpgp.c
+++ b/rpmio/rpmpgp.c
@@ -999,36 +999,128 @@ unsigned int pgpDigParamsAlgo(pgpDigParams digp, unsigned int algotype)
return algo;
}
+static pgpDigParams pgpDigParamsNew(uint8_t tag)
+{
+ pgpDigParams digp = xcalloc(1, sizeof(*digp));
+ digp->tag = tag;
+ return digp;
+}
+
+static int hashKey(DIGEST_CTX hash, const struct pgpPkt *pkt, int exptag)
+{
+ int rc = -1;
+ if (pkt->tag == exptag) {
+ uint8_t head[] = {
+ 0x99,
+ (pkt->blen >> 8),
+ (pkt->blen ),
+ };
+
+ rpmDigestUpdate(hash, head, 3);
+ rpmDigestUpdate(hash, pkt->body, pkt->blen);
+ rc = 0;
+ }
+ return rc;
+}
+
+static int pgpVerifySelf(pgpDigParams key, pgpDigParams selfsig,
+ const struct pgpPkt *all, int i)
+{
+ int rc = -1;
+ DIGEST_CTX hash = NULL;
+
+ switch (selfsig->sigtype) {
+ case PGPSIGTYPE_SUBKEY_BINDING:
+ hash = rpmDigestInit(selfsig->hash_algo, 0);
+ if (hash) {
+ rc = hashKey(hash, &all[0], PGPTAG_PUBLIC_KEY);
+ if (!rc)
+ rc = hashKey(hash, &all[i-1], PGPTAG_PUBLIC_SUBKEY);
+ }
+ break;
+ default:
+ /* ignore types we can't handle */
+ rc = 0;
+ break;
+ }
+
+ if (hash && rc == 0)
+ rc = pgpVerifySignature(key, selfsig, hash);
+
+ rpmDigestFinal(hash, NULL, NULL, 0);
+
+ return rc;
+}
+
int pgpPrtParams(const uint8_t * pkts, size_t pktlen, unsigned int pkttype,
pgpDigParams * ret)
{
const uint8_t *p = pkts;
const uint8_t *pend = pkts + pktlen;
pgpDigParams digp = NULL;
- struct pgpPkt pkt;
+ pgpDigParams selfsig = NULL;
+ int i = 0;
+ int alloced = 16; /* plenty for normal cases */
+ struct pgpPkt *all = xmalloc(alloced * sizeof(*all));
int rc = -1; /* assume failure */
+ int expect = 0;
+ int prevtag = 0;
while (p < pend) {
- if (decodePkt(p, (pend - p), &pkt))
+ struct pgpPkt *pkt = &all[i];
+ if (decodePkt(p, (pend - p), pkt))
break;
if (digp == NULL) {
- if (pkttype && pkt.tag != pkttype) {
+ if (pkttype && pkt->tag != pkttype) {
break;
} else {
- digp = xcalloc(1, sizeof(*digp));
- digp->tag = pkt.tag;
+ digp = pgpDigParamsNew(pkt->tag);
}
}
- if (pgpPrtPkt(&pkt, digp))
+ if (expect) {
+ if (pkt->tag != expect)
+ break;
+ selfsig = pgpDigParamsNew(pkt->tag);
+ }
+
+ if (pgpPrtPkt(pkt, selfsig ? selfsig : digp))
break;
- p += (pkt.body - pkt.head) + pkt.blen;
+ if (selfsig) {
+ /* subkeys must be followed by binding signature */
+ if (prevtag == PGPTAG_PUBLIC_SUBKEY) {
+ if (selfsig->sigtype != PGPSIGTYPE_SUBKEY_BINDING)
+ break;
+ }
+
+ int xx = pgpVerifySelf(digp, selfsig, all, i);
+
+ selfsig = pgpDigParamsFree(selfsig);
+ if (xx)
+ break;
+ expect = 0;
+ }
+
+ if (pkt->tag == PGPTAG_PUBLIC_SUBKEY)
+ expect = PGPTAG_SIGNATURE;
+ prevtag = pkt->tag;
+
+ i++;
+ p += (pkt->body - pkt->head) + pkt->blen;
+ if (pkttype == PGPTAG_SIGNATURE)
+ break;
+
+ if (alloced <= i) {
+ alloced *= 2;
+ all = xrealloc(all, alloced * sizeof(*all));
+ }
}
- rc = (digp && (p == pend)) ? 0 : -1;
+ rc = (digp && (p == pend) && expect == 0) ? 0 : -1;
+ free(all);
if (ret && rc == 0) {
*ret = digp;
} else {
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f2bdb7bae..bd5d4d71d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -86,6 +86,9 @@ EXTRA_DIST += data/SPECS/hello-config-buildid.spec
EXTRA_DIST += data/SPECS/hello-cd.spec
EXTRA_DIST += data/keys/rpm.org-rsa-2048-test.pub
EXTRA_DIST += data/keys/rpm.org-rsa-2048-test.secret
+EXTRA_DIST += data/keys/CVE-2021-3521-badbind.asc
+EXTRA_DIST += data/keys/CVE-2021-3521-nosubsig.asc
+EXTRA_DIST += data/keys/CVE-2021-3521-nosubsig-last.asc
# testsuite voodoo
AUTOTEST = $(AUTOM4TE) --language=autotest
diff --git a/tests/data/keys/CVE-2021-3521-badbind.asc b/tests/data/keys/CVE-2021-3521-badbind.asc
new file mode 100755
index 000000000..aea00f9d7
--- /dev/null
+++ b/tests/data/keys/CVE-2021-3521-badbind.asc
@@ -0,0 +1,25 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: rpm-4.17.90 (NSS-3)
+
+mQENBFjmORgBCAC7TMEk6wnjSs8Dr4yqSScWdU2pjcqrkTxuzdWvowcIUPZI0w/g
+HkRqGd4apjvY2V15kjL10gk3QhFP3pZ/9p7zh8o8NHX7aGdSGDK7NOq1eFaErPRY
+91LW9RiZ0lbOjXEzIL0KHxUiTQEmdXJT43DJMFPyW9fkCWg0OltiX618FUdWWfI8
+eySdLur1utnqBvdEbCUvWK2RX3vQZQdvEBODnNk2pxqTyV0w6VPQ96W++lF/5Aas
+7rUv3HIyIXxIggc8FRrnH+y9XvvHDonhTIlGnYZN4ubm9i4y3gOkrZlGTrEw7elQ
+1QeMyG2QQEbze8YjpTm4iLABCBrRfPRaQpwrABEBAAG0IXJwbS5vcmcgUlNBIHRl
+c3RrZXkgPHJzYUBycG0ub3JnPokBNwQTAQgAIQUCWOY5GAIbAwULCQgHAgYVCAkK
+CwIEFgIDAQIeAQIXgAAKCRBDRFkeGWTF/MxxCACnjqFL+MmPh9W9JQKT2DcLbBzf
+Cqo6wcEBoCOcwgRSk8dSikhARoteoa55JRJhuMyeKhhEAogE9HRmCPFdjezFTwgB
+BDVBpO2dZ023mLXDVCYX3S8pShOgCP6Tn4wqCnYeAdLcGg106N4xcmgtcssJE+Pr
+XzTZksbZsrTVEmL/Ym+R5w5jBfFnGk7Yw7ndwfQsfNXQb5AZynClFxnX546lcyZX
+fEx3/e6ezw57WNOUK6WT+8b+EGovPkbetK/rGxNXuWaP6X4A/QUm8O98nCuHYFQq
++mvNdsCBqGf7mhaRGtpHk/JgCn5rFvArMDqLVrR9hX0LdCSsH7EGE+bR3r7wuQEN
+BFjmORgBCACk+vDZrIXQuFXEYToZVwb2attzbbJJCqD71vmZTLsW0QxuPKRgbcYY
+zp4K4lVBnHhFrF8MOUOxJ7kQWIJZMZFt+BDcptCYurbD2H4W2xvnWViiC+LzCMzz
+iMJT6165uefL4JHTDPxC2fFiM9yrc72LmylJNkM/vepT128J5Qv0gRUaQbHiQuS6
+Dm/+WRnUfx3i89SV4mnBxb/Ta93GVqoOciWwzWSnwEnWYAvOb95JL4U7c5J5f/+c
+KnQDHsW7sIiIdscsWzvgf6qs2Ra1Zrt7Fdk4+ZS2f/adagLhDO1C24sXf5XfMk5m
+L0OGwZSr9m5s17VXxfspgU5ugc8kBJfzABEBAAE=
+=WCfs
+-----END PGP PUBLIC KEY BLOCK-----
+
diff --git a/tests/data/keys/CVE-2021-3521-nosubsig-last.asc b/tests/data/keys/CVE-2021-3521-nosubsig-last.asc
new file mode 100755
index 000000000..aea00f9d7
--- /dev/null
+++ b/tests/data/keys/CVE-2021-3521-nosubsig-last.asc
@@ -0,0 +1,25 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: rpm-4.17.90 (NSS-3)
+
+mQENBFjmORgBCAC7TMEk6wnjSs8Dr4yqSScWdU2pjcqrkTxuzdWvowcIUPZI0w/g
+HkRqGd4apjvY2V15kjL10gk3QhFP3pZ/9p7zh8o8NHX7aGdSGDK7NOq1eFaErPRY
+91LW9RiZ0lbOjXEzIL0KHxUiTQEmdXJT43DJMFPyW9fkCWg0OltiX618FUdWWfI8
+eySdLur1utnqBvdEbCUvWK2RX3vQZQdvEBODnNk2pxqTyV0w6VPQ96W++lF/5Aas
+7rUv3HIyIXxIggc8FRrnH+y9XvvHDonhTIlGnYZN4ubm9i4y3gOkrZlGTrEw7elQ
+1QeMyG2QQEbze8YjpTm4iLABCBrRfPRaQpwrABEBAAG0IXJwbS5vcmcgUlNBIHRl
+c3RrZXkgPHJzYUBycG0ub3JnPokBNwQTAQgAIQUCWOY5GAIbAwULCQgHAgYVCAkK
+CwIEFgIDAQIeAQIXgAAKCRBDRFkeGWTF/MxxCACnjqFL+MmPh9W9JQKT2DcLbBzf
+Cqo6wcEBoCOcwgRSk8dSikhARoteoa55JRJhuMyeKhhEAogE9HRmCPFdjezFTwgB
+BDVBpO2dZ023mLXDVCYX3S8pShOgCP6Tn4wqCnYeAdLcGg106N4xcmgtcssJE+Pr
+XzTZksbZsrTVEmL/Ym+R5w5jBfFnGk7Yw7ndwfQsfNXQb5AZynClFxnX546lcyZX
+fEx3/e6ezw57WNOUK6WT+8b+EGovPkbetK/rGxNXuWaP6X4A/QUm8O98nCuHYFQq
++mvNdsCBqGf7mhaRGtpHk/JgCn5rFvArMDqLVrR9hX0LdCSsH7EGE+bR3r7wuQEN
+BFjmORgBCACk+vDZrIXQuFXEYToZVwb2attzbbJJCqD71vmZTLsW0QxuPKRgbcYY
+zp4K4lVBnHhFrF8MOUOxJ7kQWIJZMZFt+BDcptCYurbD2H4W2xvnWViiC+LzCMzz
+iMJT6165uefL4JHTDPxC2fFiM9yrc72LmylJNkM/vepT128J5Qv0gRUaQbHiQuS6
+Dm/+WRnUfx3i89SV4mnBxb/Ta93GVqoOciWwzWSnwEnWYAvOb95JL4U7c5J5f/+c
+KnQDHsW7sIiIdscsWzvgf6qs2Ra1Zrt7Fdk4+ZS2f/adagLhDO1C24sXf5XfMk5m
+L0OGwZSr9m5s17VXxfspgU5ugc8kBJfzABEBAAE=
+=WCfs
+-----END PGP PUBLIC KEY BLOCK-----
+
diff --git a/tests/data/keys/CVE-2021-3521-nosubsig.asc b/tests/data/keys/CVE-2021-3521-nosubsig.asc
new file mode 100755
index 000000000..3a2e7417f
--- /dev/null
+++ b/tests/data/keys/CVE-2021-3521-nosubsig.asc
@@ -0,0 +1,37 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: rpm-4.17.90 (NSS-3)
+
+mQENBFjmORgBCAC7TMEk6wnjSs8Dr4yqSScWdU2pjcqrkTxuzdWvowcIUPZI0w/g
+HkRqGd4apjvY2V15kjL10gk3QhFP3pZ/9p7zh8o8NHX7aGdSGDK7NOq1eFaErPRY
+91LW9RiZ0lbOjXEzIL0KHxUiTQEmdXJT43DJMFPyW9fkCWg0OltiX618FUdWWfI8
+eySdLur1utnqBvdEbCUvWK2RX3vQZQdvEBODnNk2pxqTyV0w6VPQ96W++lF/5Aas
+7rUv3HIyIXxIggc8FRrnH+y9XvvHDonhTIlGnYZN4ubm9i4y3gOkrZlGTrEw7elQ
+1QeMyG2QQEbze8YjpTm4iLABCBrRfPRaQpwrABEBAAG0IXJwbS5vcmcgUlNBIHRl
+c3RrZXkgPHJzYUBycG0ub3JnPokBNwQTAQgAIQUCWOY5GAIbAwULCQgHAgYVCAkK
+CwIEFgIDAQIeAQIXgAAKCRBDRFkeGWTF/MxxCACnjqFL+MmPh9W9JQKT2DcLbBzf
+Cqo6wcEBoCOcwgRSk8dSikhARoteoa55JRJhuMyeKhhEAogE9HRmCPFdjezFTwgB
+BDVBpO2dZ023mLXDVCYX3S8pShOgCP6Tn4wqCnYeAdLcGg106N4xcmgtcssJE+Pr
+XzTZksbZsrTVEmL/Ym+R5w5jBfFnGk7Yw7ndwfQsfNXQb5AZynClFxnX546lcyZX
+fEx3/e6ezw57WNOUK6WT+8b+EGovPkbetK/rGxNXuWaP6X4A/QUm8O98nCuHYFQq
++mvNdsCBqGf7mhaRGtpHk/JgCn5rFvArMDqLVrR9hX0LdCSsH7EGE+bR3r7wuQEN
+BFjmORgBCACk+vDZrIXQuFXEYToZVwb2attzbbJJCqD71vmZTLsW0QxuPKRgbcYY
+zp4K4lVBnHhFrF8MOUOxJ7kQWIJZMZFt+BDcptCYurbD2H4W2xvnWViiC+LzCMzz
+iMJT6165uefL4JHTDPxC2fFiM9yrc72LmylJNkM/vepT128J5Qv0gRUaQbHiQuS6
+Dm/+WRnUfx3i89SV4mnBxb/Ta93GVqoOciWwzWSnwEnWYAvOb95JL4U7c5J5f/+c
+KnQDHsW7sIiIdscsWzvgf6qs2Ra1Zrt7Fdk4+ZS2f/adagLhDO1C24sXf5XfMk5m
+L0OGwZSr9m5s17VXxfspgU5ugc8kBJfzABEBAAG5AQ0EWOY5GAEIAKT68NmshdC4
+VcRhOhlXBvZq23NtskkKoPvW+ZlMuxbRDG48pGBtxhjOngriVUGceEWsXww5Q7En
+uRBYglkxkW34ENym0Ji6tsPYfhbbG+dZWKIL4vMIzPOIwlPrXrm558vgkdMM/ELZ
+8WIz3KtzvYubKUk2Qz+96lPXbwnlC/SBFRpBseJC5LoOb/5ZGdR/HeLz1JXiacHF
+v9Nr3cZWqg5yJbDNZKfASdZgC85v3kkvhTtzknl//5wqdAMexbuwiIh2xyxbO+B/
+qqzZFrVmu3sV2Tj5lLZ/9p1qAuEM7ULbixd/ld8yTmYvQ4bBlKv2bmzXtVfF+ymB
+Tm6BzyQEl/MAEQEAAYkBHwQYAQgACQUCWOY5GAIbDAAKCRBDRFkeGWTF/PANB/9j
+mifmj6z/EPe0PJFhrpISt9PjiUQCt0IPtiL5zKAkWjHePIzyi+0kCTBF6DDLFxos
+3vN4bWnVKT1kBhZAQlPqpJTg+m74JUYeDGCdNx9SK7oRllATqyu+5rncgxjWVPnQ
+zu/HRPlWJwcVFYEVXYL8xzfantwQTqefjmcRmBRdA2XJITK+hGWwAmrqAWx+q5xX
+Pa8wkNMxVzNS2rUKO9SoVuJ/wlUvfoShkJ/VJ5HDp3qzUqncADfdGN35TDzscngQ
+gHvnMwVBfYfSCABV1hNByoZcc/kxkrWMmsd/EnIyLd1Q1baKqc3cEDuC6E6/o4yJ
+E4XX4jtDmdZPreZALsiB
+=rRop
+-----END PGP PUBLIC KEY BLOCK-----
+
diff --git a/tests/rpmsigdig.at b/tests/rpmsigdig.at
index 9df3c5bd8..69382999f 100644
--- a/tests/rpmsigdig.at
+++ b/tests/rpmsigdig.at
@@ -191,6 +191,34 @@ UNW2iqnN3BA7guhOv6OMiROF1+I7Q5nWT63mQC7IgQ==
[])
AT_CLEANUP
+AT_SETUP([rpmkeys --import invalid keys])
+AT_KEYWORDS([rpmkeys import])
+RPMDB_INIT
+
+AT_CHECK([
+runroot rpmkeys --import /data/keys/CVE-2021-3521-badbind.asc
+],
+[1],
+[],
+[error: /data/keys/CVE-2021-3521-badbind.asc: key 1 import failed.]
+)
+AT_CHECK([
+runroot rpmkeys --import /data/keys/CVE-2021-3521-nosubsig.asc
+],
+[1],
+[],
+[error: /data/keys/CVE-2021-3521-nosubsig.asc: key 1 import failed.]
+)
+
+AT_CHECK([
+runroot rpmkeys --import /data/keys/CVE-2021-3521-nosubsig-last.asc
+],
+[1],
+[],
+[error: /data/keys/CVE-2021-3521-nosubsig-last.asc: key 1 import failed.]
+)
+AT_CLEANUP
+
# ------------------------------
# Test pre-built package verification
AT_SETUP([rpmkeys -K <signed> 1])