summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPanu Matilainen <pmatilai@redhat.com>2016-11-15 14:26:10 +0200
committerPanu Matilainen <pmatilai@redhat.com>2016-11-15 14:26:10 +0200
commit1545e71d87d0580b12af29b8af70088cb3229582 (patch)
tree0462a485d9917b68a5c8e8aa2b2e41f511d0ef05
parentffeed045ad0a022b55215b9ec040fc0471826a60 (diff)
downloadrpm-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.c25
-rw-r--r--lib/header_internal.h4
-rw-r--r--lib/package.c6
-rw-r--r--lib/signature.c2
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;
}