Projects
Mega:24.03:SP1:Everything
rpm
_service:tar_scm:Add-IMA-digest-list-support.patch
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:Add-IMA-digest-list-support.patch of Package rpm
From 773107eccfa7f0da8547b2c5efe8cce996a35a91 Mon Sep 17 00:00:00 2001 From: zhoushuiqing <zhoushuiqing2@huawei.com> Date: Fri, 16 Jun 2023 11:35:21 +0800 Subject: [PATCH] Add IMA digest list support Signed-off-by: xuce <xuce10@h-partners.com> --- build/files.c | 305 ++++++++++++++++++++++++++++++++++++++-- build/parsePreamble.c | 3 +- macros.in | 1 + plugins/Makefile.am | 4 + rpmio/rpmpgp_internal.c | 32 +---- rpmio/rpmpgp_internal.h | 29 ++++ 6 files changed, 334 insertions(+), 40 deletions(-) diff --git a/build/files.c b/build/files.c index 44ac155..53a26b2 100644 --- a/build/files.c +++ b/build/files.c @@ -50,6 +50,8 @@ #define DEBUG_LIB_PREFIX "/usr/lib/debug/" #define DEBUG_ID_DIR "/usr/lib/debug/.build-id" #define DEBUG_DWZ_DIR "/usr/lib/debug/.dwz" +#define DIGEST_LIST_DIR "/.digest_lists" +#define DEST_DIGEST_LIST_DIR "/etc/ima/digest_lists" #undef HASHTYPE #undef HTKEYTYPE @@ -129,6 +131,8 @@ typedef struct AttrRec_s { /* list of files */ static StringBuf check_fileList = NULL; +/* list of files per binary package */ +static StringBuf check_fileList_bin_pkg = NULL; typedef struct FileEntry_s { rpmfileAttrs attrFlags; @@ -193,6 +197,10 @@ typedef struct FileList_s { struct FileEntry_s cur; } * FileList; +static char *digest_list_dir; + +static int genDigestList(Header header, FileList fl, StringBuf fileList); + static void nullAttrRec(AttrRec ar) { memset(ar, 0, sizeof(*ar)); @@ -993,6 +1001,139 @@ static int seenHardLink(FileRecords files, FileListRec flp, rpm_ino_t *fileid) * @param pkg (sub) package * @param isSrc pass 1 for source packages 0 otherwise */ +static void genDigestListInput(FileList fl, Package pkg, int isSrc) +{ + FileListRec flp; + char buf[BUFSIZ]; + char file_info[BUFSIZ]; + char file_digest[128 * 2 + 1]; + int i, gen_digest_lists = 1; + uint32_t defaultalgo = PGPHASHALGO_MD5, digestalgo; + Header h = pkg->header; /* just a shortcut */ + + /* + * See if non-md5 file digest algorithm is requested. If not + * specified, quietly assume md5. Otherwise check if supported type. + */ + digestalgo = rpmExpandNumeric(isSrc ? "%{_source_filedigest_algorithm}" : + "%{_binary_filedigest_algorithm}"); + if (digestalgo == 0) { + digestalgo = defaultalgo; + } + + if (rpmDigestLength(digestalgo) == 0) { + rpmlog(RPMLOG_WARNING, + _("Unknown file digest algorithm %u, falling back to MD5\n"), + digestalgo); + digestalgo = defaultalgo; + } + + /* Sort the big list */ + if (fl->files.recs) { + qsort(fl->files.recs, fl->files.used, + sizeof(*(fl->files.recs)), compareFileListRecs); + } + + /* Generate the header. */ + for (i = 0, flp = fl->files.recs; i < fl->files.used; i++, flp++) { + /* Merge duplicate entries. */ + while (i < (fl->files.used - 1) && + rstreq(flp->cpioPath, flp[1].cpioPath)) { + + /* Two entries for the same file found, merge the entries. */ + /* Note that an %exclude is a duplication of a file reference */ + + /* file flags */ + flp[1].flags |= flp->flags; + + if (!(flp[1].flags & RPMFILE_EXCLUDE)) + rpmlog(RPMLOG_WARNING, _("File listed twice: %s\n"), + flp->cpioPath); + + /* file mode */ + if (S_ISDIR(flp->fl_mode)) { + if ((flp[1].specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)) < + (flp->specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE))) + flp[1].fl_mode = flp->fl_mode; + } else { + if ((flp[1].specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)) < + (flp->specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE))) + flp[1].fl_mode = flp->fl_mode; + } + + /* uid */ + if ((flp[1].specdFlags & (SPECD_UID | SPECD_DEFUID)) < + (flp->specdFlags & (SPECD_UID | SPECD_DEFUID))) + { + flp[1].fl_uid = flp->fl_uid; + flp[1].uname = flp->uname; + } + + /* gid */ + if ((flp[1].specdFlags & (SPECD_GID | SPECD_DEFGID)) < + (flp->specdFlags & (SPECD_GID | SPECD_DEFGID))) + { + flp[1].fl_gid = flp->fl_gid; + flp[1].gname = flp->gname; + } + + /* verify flags */ + if ((flp[1].specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)) < + (flp->specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY))) + flp[1].verifyFlags = flp->verifyFlags; + + /* XXX to-do: language */ + + flp++; i++; + } + + /* Skip files that were marked with %exclude. */ + if (flp->flags & RPMFILE_EXCLUDE) + { + argvAdd(&pkg->fileExcludeList, flp->cpioPath); + continue; + } + + buf[0] = '\0'; + if (S_ISREG(flp->fl_mode) && !(flp->flags & RPMFILE_GHOST)) + (void) rpmDoDigest(digestalgo, flp->diskPath, 1, + (unsigned char *)buf); + headerPutString(h, RPMTAG_FILEDIGESTS, buf); + snprintf(file_digest, sizeof(file_digest), "%s", buf); + + if (check_fileList_bin_pkg && S_ISREG(flp->fl_mode) && + !(flp->flags & RPMFILE_GHOST)) { + appendStringBuf(check_fileList_bin_pkg, "path="); + appendStringBuf(check_fileList_bin_pkg, flp->diskPath); + snprintf(file_info, sizeof(file_info), + "|digestalgopgp=%d|digest=%s|mode=%d" + "|uname=%s|gname=%s|caps=%s\n", + digestalgo, file_digest, flp->fl_mode, + rpmstrPoolStr(fl->pool, flp->uname), + rpmstrPoolStr(fl->pool, flp->gname), flp->caps && + strlen(flp->caps) ? flp->caps : ""); + appendStringBuf(check_fileList_bin_pkg, file_info); + } + + if (S_ISREG(flp->fl_mode) && + !strncmp(flp->cpioPath, DEST_DIGEST_LIST_DIR, + sizeof(DEST_DIGEST_LIST_DIR) - 1)) + gen_digest_lists = 0; + } + + if (gen_digest_lists && + genDigestList(pkg->header, fl, check_fileList_bin_pkg) > 0) + fl->processingFailed = 1; +} + +/** + * Add file entries to header. + * @todo Should directories have %doc/%config attributes? (#14531) + * @todo Remove RPMTAG_OLDFILENAMES, add dirname/basename instead. + * @param fl package file tree walk data + * @param pkg (sub) package + * @param isSrc pass 1 for source packages 0 otherwise + */ static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc) { FileListRec flp; @@ -1005,6 +1146,11 @@ static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc) int override_date = 0; time_t source_date_epoch = 0; char *srcdate = getenv("SOURCE_DATE_EPOCH"); + struct rpmtd_s oldfiledigests; + + headerGet(h, RPMTAG_FILEDIGESTS, &oldfiledigests, HEADERGET_ALLOC); + headerDel(h, RPMTAG_FILEDIGESTS); + rpmtdInit(&oldfiledigests); /* Limit the maximum date to SOURCE_DATE_EPOCH if defined * similar to the tar --clamp-mtime option @@ -1203,13 +1349,18 @@ static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc) if (fl->haveCaps) { headerPutString(h, RPMTAG_FILECAPS, flp->caps); } - + buf[0] = '\0'; - if (S_ISREG(flp->fl_mode) && !(flp->flags & RPMFILE_GHOST)) - (void) rpmDoDigest(digestalgo, flp->diskPath, 1, - (unsigned char *)buf); - headerPutString(h, RPMTAG_FILEDIGESTS, buf); - + if (strstr(flp->diskPath, DIGEST_LIST_DIR) || !oldfiledigests.count) { + if (S_ISREG(flp->fl_mode) && !(flp->flags & RPMFILE_GHOST)) + (void) rpmDoDigest(digestalgo, flp->diskPath, 1, + (unsigned char *)buf); + headerPutString(h, RPMTAG_FILEDIGESTS, buf); + } else { + headerPutString(h, RPMTAG_FILEDIGESTS, + rpmtdNextString(&oldfiledigests)); + } + buf[0] = '\0'; if (S_ISLNK(flp->fl_mode)) { ssize_t llen = readlink(flp->diskPath, buf, BUFSIZ-1); @@ -1250,6 +1401,7 @@ static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc) headerPutUint32(h, RPMTAG_FILEFLAGS, &(flp->flags) ,1); } + pkg->dpaths[npaths] = NULL; if (totalFileSize < UINT32_MAX) { @@ -1287,6 +1439,7 @@ static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc) /* Binary packages with dirNames cannot be installed by legacy rpm. */ (void) rpmlibNeedsFeature(pkg, "CompressedFileNames", "3.0.4-1"); } + rpmtdFreeData(&oldfiledigests); } static FileRecords FileRecordsFree(FileRecords files) @@ -1361,8 +1514,8 @@ static int validFilename(const char *fn) * @param statp file stat (possibly NULL) * @return RPMRC_OK on success */ -static rpmRC addFile(FileList fl, const char * diskPath, - struct stat * statp) +static rpmRC addFile_common(FileList fl, const char * diskPath, + struct stat * statp, int digest_list) { size_t plen = strlen(diskPath); char buf[plen + 1]; @@ -1373,6 +1526,10 @@ static rpmRC addFile(FileList fl, const char * diskPath, gid_t fileGid; const char *fileUname; const char *fileGname; + char realPath[PATH_MAX]; + int digest_list_prefix = 0; + struct stat st; + int exclude = 0; rpmRC rc = RPMRC_FAIL; /* assume failure */ /* Strip trailing slash. The special case of '/' path is handled below. */ @@ -1408,6 +1565,33 @@ static rpmRC addFile(FileList fl, const char * diskPath, if (*cpioPath == '\0') cpioPath = "/"; + snprintf(realPath, sizeof(realPath), "%s", diskPath); + rpmCleanPath(realPath); + + digest_list_prefix = (!strncmp(realPath, digest_list_dir, + strlen(digest_list_dir))); + + if ((!digest_list && digest_list_prefix) || + (digest_list && !digest_list_prefix)) { + rc = RPMRC_OK; + goto exit; + } + + if (digest_list) { + if (strncmp(cpioPath, DIGEST_LIST_DIR, sizeof(DIGEST_LIST_DIR) - 1)) { + rc = RPMRC_OK; + goto exit; + } + + cpioPath += sizeof(DIGEST_LIST_DIR) - 1; + + snprintf(realPath, sizeof(realPath), "%.*s%s", + (int)(strlen(digest_list_dir) - sizeof(DIGEST_LIST_DIR) + 1), + digest_list_dir, cpioPath); + if (!stat(realPath, &st)) + exclude = 1; + } + /* * Unless recursing, we dont have stat() info at hand. Handle the * various cases, preserving historical behavior wrt %dev(): @@ -1545,6 +1729,8 @@ static rpmRC addFile(FileList fl, const char * diskPath, } flp->flags = fl->cur.attrFlags; + if (exclude) + flp->flags |= RPMFILE_EXCLUDE; flp->specdFlags = fl->cur.specdFlags; flp->verifyFlags = fl->cur.verifyFlags; @@ -1565,6 +1751,32 @@ exit: return rc; } +/** + * Add a file to the package manifest. + * @param fl package file tree walk data + * @param diskPath path to file + * @param statp file stat (possibly NULL) + * @return RPMRC_OK on success + */ +static rpmRC addFile(FileList fl, const char * diskPath, + struct stat * statp) +{ + return addFile_common(fl, diskPath, statp, 0); +} + +/** + * Add a digest list to the package manifest. + * @param fl package file tree walk data + * @param diskPath path to digest list + * @param statp file stat (possibly NULL) + * @return RPMRC_OK on success + */ +static rpmRC addDigestList(FileList fl, const char * diskPath, + struct stat * statp) +{ + return addFile_common(fl, diskPath, statp, 1); +} + /** * Add directory (and all of its files) to the package manifest. * @param fl package file tree walk data @@ -2586,6 +2798,61 @@ static void addPackageFileList (struct FileList_s *fl, Package pkg, argvFree(fileNames); } +/** + * Generate digest lists list for current binary package. + * @header package header + * @fl file list + * @param fileList packaged file list + * @return -1 if skipped, 0 on OK, 1 on error + */ +static int genDigestList(Header header, FileList fl, StringBuf fileList) +{ + const char *errorString; + char *binFormat = rpmGetPath("%{_rpmfilename}", NULL); + char *binRpm = headerFormat(header, binFormat, &errorString); + static char * av_brp[] = { "%{?__brp_digest_list}", DIGEST_LIST_DIR + 1, NULL, NULL }; + StringBuf sb_stdout = NULL; + int rc = -1; + char * s = rpmExpand(av_brp[0], NULL); + + if (!(s && *s)) + goto exit; + + if (!strchr(binRpm, '/')) + goto exit; + + av_brp[2] = strchr(binRpm, '/') + 1; + rpmlog(RPMLOG_NOTICE, _("Generating digest list: %s\n"), s); + + rc = rpmfcExec(av_brp, fileList, &sb_stdout, 0, binRpm); + if (sb_stdout && getStringBuf(sb_stdout)) { + const char * t = getStringBuf(sb_stdout), *ptr; + char *digest_list_path; + + while((ptr = strchr(t, '\n'))) { + digest_list_path = strndup(t, ptr - t); + if (!digest_list_path) { + rc = -1; + goto exit; + } + FileEntryFree(&fl->cur); + resetPackageFilesDefaults(fl, fl->pkgFlags); + rc = addDigestList(fl, digest_list_path, NULL); + free(digest_list_path); + if (rc != RPMRC_OK) + break; + + t = ptr + 1; + } + } +exit: + free(binFormat); + free(binRpm); + free(s); + freeStringBuf(sb_stdout); + return rc; +} + static rpmRC processPackageFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags, Package pkg, int didInstall, int test) { @@ -2599,6 +2866,10 @@ static rpmRC processPackageFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags, if (readFilesManifest(spec, pkg, *fp)) return RPMRC_FAIL; } + + /* Init the buffer containing the list of packaged files */ + check_fileList_bin_pkg = newStringBuf(); + /* Init the file list structure */ memset(&fl, 0, sizeof(fl)); @@ -2654,12 +2925,17 @@ static rpmRC processPackageFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags, if (checkHardLinks(&fl.files)) (void) rpmlibNeedsFeature(pkg, "PartialHardlinkSets", "4.0.4-1"); + genDigestListInput(&fl, pkg, 0); + if (fl.processingFailed) + goto exit; + genCpioListAndHeader(&fl, pkg, 0); exit: FileListFree(&fl); specialDirFree(specialDoc); specialDirFree(specialLic); + freeStringBuf(check_fileList_bin_pkg); return fl.processingFailed ? RPMRC_FAIL : RPMRC_OK; } @@ -3128,6 +3404,7 @@ static void addPackageDeps(Package from, Package to, enum rpmTag_e tag) rpmRC processBinaryFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags, int didInstall, int test) { + struct stat st; Package pkg; rpmRC rc = RPMRC_OK; char *buildroot; @@ -3144,7 +3421,14 @@ rpmRC processBinaryFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags, check_fileList = newStringBuf(); genSourceRpmName(spec); buildroot = rpmGenPath(spec->rootDir, spec->buildRoot, NULL); - + + digest_list_dir = rpmGenPath(buildroot, DIGEST_LIST_DIR, NULL); + if (!digest_list_dir) + goto exit; + + if (!stat(digest_list_dir, &st)) + rpmlog(RPMLOG_NOTICE, _("Ignoring files in: %s\n"), digest_list_dir); + if (rpmExpandNumeric("%{?_debuginfo_subpackages}")) { maindbg = findDebuginfoPackage(spec); if (maindbg) { @@ -3250,6 +3534,7 @@ exit: check_fileList = freeStringBuf(check_fileList); _free(buildroot); _free(uniquearch); - + _free(digest_list_dir); + return rc; } diff --git a/build/parsePreamble.c b/build/parsePreamble.c index 729fd4f..306a029 100644 --- a/build/parsePreamble.c +++ b/build/parsePreamble.c @@ -801,7 +801,8 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag, SINGLE_TOKEN_ONLY; if (tag == RPMTAG_RELEASE) { char *dist = rpmExpand("%{?dist}",NULL); - rasprintf(&field,"%s%s",field,dist); + rasprintf(&field,"%s%s",field, + (dist && strstr(field, dist)) ? "" : dist); free(dist); } if (rpmCharCheck(spec, field, ALLOWED_CHARS_VERREL, NULL)) diff --git a/macros.in b/macros.in index 4c7073c..6093898 100644 --- a/macros.in +++ b/macros.in @@ -1155,6 +1155,7 @@ package or when debugging this package.\ %__transaction_prioreset %{__plugindir}/prioreset.so %__transaction_audit %{__plugindir}/audit.so %__transaction_dbus_announce %{__plugindir}/dbus_announce.so +%__transaction_digest_list %{__plugindir}/digest_list.so #------------------------------------------------------------------------------ # Macros for further automated spec %setup and patch application diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 822c7d2..161fe4c 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -69,3 +69,7 @@ audit_la_sources = audit.c audit_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la @WITH_AUDIT_LIB@ plugins_LTLIBRARIES += audit.la endif + +digest_list_la_sources = digest_list.c +digest_list_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la +plugins_LTLIBRARIES += digest_list.la diff --git a/rpmio/rpmpgp_internal.c b/rpmio/rpmpgp_internal.c index 0fcd220..63d065a 100644 --- a/rpmio/rpmpgp_internal.c +++ b/rpmio/rpmpgp_internal.c @@ -19,34 +19,6 @@ static int _print = 0; -/** \ingroup rpmio - * Values parsed from OpenPGP signature/pubkey packet(s). - */ -struct pgpDigParams_s { - char * userid; - uint8_t * hash; - uint8_t tag; - - uint8_t key_flags; /*!< key usage flags */ - uint8_t version; /*!< version number. */ - uint32_t time; /*!< key/signature creation time. */ - uint8_t pubkey_algo; /*!< public key algorithm. */ - - uint8_t hash_algo; - uint8_t sigtype; - uint32_t hashlen; - uint8_t signhash16[2]; - pgpKeyID_t signid; - uint8_t saved; /*!< Various flags. `PGPDIG_SAVED_*` are never reset. - * `PGPDIG_SIG_HAS_*` are reset for each signature. */ -#define PGPDIG_SAVED_TIME (1 << 0) -#define PGPDIG_SAVED_ID (1 << 1) -#define PGPDIG_SIG_HAS_CREATION_TIME (1 << 2) -#define PGPDIG_SIG_HAS_KEY_FLAGS (1 << 3) - - pgpDigAlg alg; -}; - /** \ingroup rpmio * Container for values parsed from an OpenPGP signature and public key. */ @@ -484,6 +456,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, } p = ((uint8_t *)v) + sizeof(*v); + _digp->data = p; rc = tag ? pgpPrtSigParams(tag, v->pubkey_algo, p, h, hlen, _digp) : 0; } break; case 4: @@ -545,7 +518,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, p += 2; if (p > hend) return 1; - + _digp->data = p; rc = tag ? pgpPrtSigParams(tag, v->pubkey_algo, p, h, hlen, _digp) : 0; } break; default: @@ -641,6 +614,7 @@ static int pgpPrtKey(pgpTag tag, const uint8_t *h, size_t hlen, } p = ((uint8_t *)v) + sizeof(*v); + _digp->data = p; rc = pgpPrtPubkeyParams(v->pubkey_algo, p, h, hlen, _digp); } } break; diff --git a/rpmio/rpmpgp_internal.h b/rpmio/rpmpgp_internal.h index 64b50de..67fecb0 100644 --- a/rpmio/rpmpgp_internal.h +++ b/rpmio/rpmpgp_internal.h @@ -10,6 +10,35 @@ typedef int (*verifyfunc)(pgpDigAlg pgpkey, pgpDigAlg pgpsig, uint8_t *hash, size_t hashlen, int hash_algo); typedef void (*freefunc)(pgpDigAlg digp); +/** \ingroup rpmio + * Values parsed from OpenPGP signature/pubkey packet(s). + */ +struct pgpDigParams_s { + char * userid; + uint8_t * hash; + const uint8_t * data; + uint8_t tag; + + uint8_t key_flags; /*!< key usage flags */ + uint8_t version; /*!< version number. */ + uint32_t time; /*!< key/signature creation time. */ + uint8_t pubkey_algo; /*!< public key algorithm. */ + + uint8_t hash_algo; + uint8_t sigtype; + uint32_t hashlen; + uint8_t signhash16[2]; + pgpKeyID_t signid; + uint8_t saved; /*!< Various flags. `PGPDIG_SAVED_*` are never reset. + * `PGPDIG_SIG_HAS_*` are reset for each signature. */ +#define PGPDIG_SAVED_TIME (1 << 0) +#define PGPDIG_SAVED_ID (1 << 1) +#define PGPDIG_SIG_HAS_CREATION_TIME (1 << 2) +#define PGPDIG_SIG_HAS_KEY_FLAGS (1 << 3) + + pgpDigAlg alg; +}; + struct pgpDigAlg_s { setmpifunc setmpi; verifyfunc verify; -- 2.43.0
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2