rpmRC headerCheck(rpmts ts, const void * uh, size_t uc, char ** msg) { rpmRC rc = RPMRC_FAIL; rpmVSFlags vsflags = rpmtsVSFlags(ts); rpmKeyring keyring = rpmtsGetKeyring(ts, 1); struct hdrblob_s blob; if (hdrblobInit(uh, uc, 0, 0, &blob, msg) == RPMRC_OK) { rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0); rc = headerSigVerify(keyring, vsflags, &blob, msg); rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), uc); if (rc == RPMRC_NOTFOUND && msg != NULL && *msg == NULL) rasprintf(msg, "Header sanity check: OK"); } rpmKeyringFree(keyring); return rc; }
static rpmRC headerVerify(rpmKeyring keyring, rpmVSFlags vsflags, const void * uh, size_t uc, char ** msg) { char *buf = NULL; int32_t * ei = (int32_t *) uh; int32_t il = ntohl(ei[0]); int32_t dl = ntohl(ei[1]); entryInfo pe = (entryInfo) &ei[2]; int32_t pvlen = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl; unsigned char * dataStart = (unsigned char *) (pe + il); struct indexEntry_s entry; struct entryInfo_s info; int32_t ril = 0; unsigned char * regionEnd = NULL; rpmRC rc = RPMRC_FAIL; /* assume failure */ /* Is the blob the right size? */ if (uc > 0 && pvlen != uc) { rasprintf(&buf, _("blob size(%d): BAD, 8 + 16 * il(%d) + dl(%d)\n"), (int)uc, (int)il, (int)dl); goto exit; } memset(&entry, 0, sizeof(entry)); memset(&info, 0, sizeof(info)); /* Check (and convert) the 1st tag element. */ if (headerVerifyInfo(1, dl, pe, &entry.info, 0) != -1) { rasprintf(&buf, _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"), 0, entry.info.tag, entry.info.type, entry.info.offset, entry.info.count); goto exit; } /* Is there an immutable header region tag? */ if (!(entry.info.tag == RPMTAG_HEADERIMMUTABLE && entry.info.type == RPM_BIN_TYPE && entry.info.count == REGION_TAG_COUNT)) { rc = RPMRC_NOTFOUND; goto exit; } /* Is the trailer within the data area? */ if (entry.info.offset + REGION_TAG_COUNT > dl) { rasprintf(&buf, _("region offset: BAD, tag %d type %d offset %d count %d\n"), entry.info.tag, entry.info.type, entry.info.offset, entry.info.count); goto exit; } /* Is there an immutable header region tag trailer? */ regionEnd = dataStart + entry.info.offset; (void) memcpy(&info, regionEnd, REGION_TAG_COUNT); regionEnd += REGION_TAG_COUNT; if (headerVerifyInfo(1, dl, &info, &entry.info, 1) != -1 || !(entry.info.tag == RPMTAG_HEADERIMMUTABLE && entry.info.type == RPM_BIN_TYPE && entry.info.count == REGION_TAG_COUNT)) { rasprintf(&buf, _("region trailer: BAD, tag %d type %d offset %d count %d\n"), entry.info.tag, entry.info.type, entry.info.offset, entry.info.count); goto exit; } memset(&info, 0, sizeof(info)); /* Is the no. of tags in the region less than the total no. of tags? */ ril = entry.info.offset/sizeof(*pe); if ((entry.info.offset % sizeof(*pe)) || ril > il) { rasprintf(&buf, _("region size: BAD, ril(%d) > il(%d)\n"), ril, il); goto exit; } /* Verify header-only digest/signature if there is one we can use. */ rc = headerSigVerify(keyring, vsflags, il, dl, ril, (regionEnd - dataStart), pe, dataStart, &buf); exit: /* If no header-only digest/signature, then do simple sanity check. */ if (rc == RPMRC_NOTFOUND) { int xx = headerVerifyInfo(ril-1, dl, pe+1, &entry.info, 0); if (xx != -1) { rasprintf(&buf, _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"), xx+1, entry.info.tag, entry.info.type, entry.info.offset, entry.info.count); rc = RPMRC_FAIL; } else { rasprintf(&buf, "Header sanity check: OK\n"); rc = RPMRC_OK; } } if (msg) *msg = buf; else free(buf); return rc; }