diff options
author | Panu Matilainen <pmatilai@redhat.com> | 2016-11-15 14:26:10 +0200 |
---|---|---|
committer | Panu Matilainen <pmatilai@redhat.com> | 2016-11-15 14:26:10 +0200 |
commit | 1545e71d87d0580b12af29b8af70088cb3229582 (patch) | |
tree | 0462a485d9917b68a5c8e8aa2b2e41f511d0ef05 | |
parent | ffeed045ad0a022b55215b9ec040fc0471826a60 (diff) | |
download | rpm-1545e71d87d0580b12af29b8af70088cb3229582.tar.gz |
Validate string data lengths too on headerVerifyInfo()
For this we need to pass dataStart into headerVerifyInfo(), and
then we can actually just call dataLength() to do the hard work.
There's a non-trivial cost involved of course, especially since we
now do this twice, but better slow than sorry. We can always
make things smarter later on, and this closes down a major hole
in how rpm deals with header data.
-rw-r--r-- | lib/header.c | 25 | ||||
-rw-r--r-- | lib/header_internal.h | 4 | ||||
-rw-r--r-- | lib/package.c | 6 | ||||
-rw-r--r-- | lib/signature.c | 2 |
4 files changed, 21 insertions, 16 deletions
diff --git a/lib/header.c b/lib/header.c index 73b5217fb..885d41448 100644 --- a/lib/header.c +++ b/lib/header.c @@ -118,6 +118,9 @@ static const size_t headerMaxbytes = (256*1024*1024); (((_e)->info.tag >= RPMTAG_HEADERIMAGE) && ((_e)->info.tag < RPMTAG_HEADERREGIONS)) #define ENTRY_IN_REGION(_e) ((_e)->info.offset < 0) +static int dataLength(rpm_tagtype_t type, rpm_constdata_t p, rpm_count_t count, + int onDisk, rpm_constdata_t pend); + #ifndef htonll /* Convert a 64bit value to network byte order. */ RPM_GNUC_CONST @@ -203,11 +206,13 @@ Header headerNew(void) return headerCreate(NULL, 0, 0); } -int headerVerifyInfo(int il, int dl, const struct entryInfo_s * pe, +int headerVerifyInfo(int il, int dl, + const struct entryInfo_s * pe, const void *dataStart, struct entryInfo_s * info, char **emsg) { - int i, tsize; + int i, len = 0; int32_t end = 0; + const char *ds = dataStart; for (i = 0; i < il; i++) { ei2h(&pe[i], info); @@ -221,22 +226,20 @@ int headerVerifyInfo(int il, int dl, const struct entryInfo_s * pe, if (hdrchkAlign(info->type, info->offset)) return i; - /* For string types we can only check the array size is sane */ - tsize = typeSizes[info->type]; - if (tsize < 1) - tsize = 1; - /* Verify the data actually fits */ - end = info->offset + (info->count * tsize); - if (hdrchkRange(dl, end)) + len = dataLength(info->type, ds + info->offset, + info->count, 1, ds + dl); + end = info->offset + len; + if (hdrchkRange(dl, end) || len <= 0) goto err; } i = -1; /* Everything ok */ err: if (i >= 0 && emsg) { - rasprintf(emsg, _("tag[%d]: BAD, tag %d type %d offset %d count %d"), - i, info->tag, info->type, info->offset, info->count); + rasprintf(emsg, + _("tag[%d]: BAD, tag %d type %d offset %d count %d len %d"), + i, info->tag, info->type, info->offset, info->count, len); } return i; diff --git a/lib/header_internal.h b/lib/header_internal.h index d9edd69bf..3f7c882c9 100644 --- a/lib/header_internal.h +++ b/lib/header_internal.h @@ -75,12 +75,14 @@ rpmRC headerVerifyRegion(rpmTagVal regionTag, * @param il no. of tags in header * @param dl no. of bytes in header data. * @param pe 1st element in tag array, big-endian + * @param dataStart start of data area * @retval info failing (or last) tag element, host-endian * @retvar emsg possible error message (malloced) or NULL to disable * @return -1 on success, otherwise failing tag element index */ RPM_GNUC_INTERNAL -int headerVerifyInfo(int il, int dl, const struct entryInfo_s * pe, +int headerVerifyInfo(int il, int dl, + const struct entryInfo_s * pe, const void *dataStart, struct entryInfo_s * info, char **emsg); diff --git a/lib/package.c b/lib/package.c index 11cac96a8..bbd72c504 100644 --- a/lib/package.c +++ b/lib/package.c @@ -179,7 +179,7 @@ static rpmRC headerSigVerify(rpmKeyring keyring, rpmVSFlags vsflags, /* Find a header-only digest/signature tag. */ for (int i = ril; i < il; i++) { - if (headerVerifyInfo(1, dl, pe+i, &einfo, buf) != -1) + if (headerVerifyInfo(1, dl, pe+i, dataStart, &einfo, buf) != -1) goto exit; switch (einfo.tag) { @@ -272,7 +272,7 @@ rpmRC headerVerifyRegion(rpmTagVal regionTag, } /* Check (and convert) the 1st tag element. */ - if (headerVerifyInfo(1, dl, pe, &einfo, buf) != -1) + if (headerVerifyInfo(1, dl, pe, dataStart, &einfo, buf) != -1) goto exit; /* Is there an immutable header region tag? */ @@ -372,7 +372,7 @@ static rpmRC headerVerify(rpmKeyring keyring, rpmVSFlags vsflags, /* Sanity check the rest of the header structure. */ if (rc != RPMRC_FAIL) { struct entryInfo_s info; - if (headerVerifyInfo(ril-1, dl, pe+1, &info, &buf) != -1) + if (headerVerifyInfo(ril-1, dl, pe+1, dataStart, &info, &buf) != -1) rc = RPMRC_FAIL; } diff --git a/lib/signature.c b/lib/signature.c index 95d3be576..02ba4102f 100644 --- a/lib/signature.c +++ b/lib/signature.c @@ -197,7 +197,7 @@ rpmRC rpmReadSignature(FD_t fd, Header * sighp, char ** msg) /* Sanity check signature tags */ for (i = 1; i < il; i++) { struct entryInfo_s info; - if (headerVerifyInfo(1, dl, pe+i, &info, &buf) != -1) + if (headerVerifyInfo(1, dl, pe+i, dataStart, &info, &buf) != -1) goto exit; } |