From ebbf0f0133c498d229e94ecf2ed0b41d6e6a142a Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Mon, 8 Feb 2021 16:05:01 -0500 Subject: [PATCH] hdrblobInit() needs bounds checks too Users can pass untrusted data to hdrblobInit() and it must be robust against this. Backported from commit 8f4b3c3cab8922a2022b9e47c71f1ecf906077ef Upstream-Status: Backport [https://github.com/rpm-software-management/rpm/pull/1587/commits/9646711891df851dfbf7ef54cc171574a0914b15] CVE: CVE-2021-20266 Signed-off-by: Ranjitsinh Rathod --- lib/header.c | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/lib/header.c b/lib/header.c index 5b09f8352..ad5b6dc57 100644 --- a/lib/header.c +++ b/lib/header.c @@ -11,6 +11,7 @@ #include "system.h" #include #include +#include #include #include #include "lib/header_internal.h" @@ -1890,6 +1891,25 @@ hdrblob hdrblobFree(hdrblob blob) return NULL; } +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 = 8192; + } + 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]; @@ -1902,13 +1922,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) { @@ -1921,15 +1934,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; @@ -1973,11 +1980,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;