From 8740452fb2459ab7e6103bc90b09915360c076da Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Tue, 14 Jul 2020 09:04:38 +0200 Subject: [PATCH 1/7] Add digest list patches --- Add-digest-list-plugin.patch | 579 +++++++++++++++++++++++++++++++++++ Generate-digest-lists.patch | 306 ++++++++++++++++++ rpm.spec | 8 +- 3 files changed, 892 insertions(+), 1 deletion(-) create mode 100644 Add-digest-list-plugin.patch create mode 100644 Generate-digest-lists.patch diff --git a/Add-digest-list-plugin.patch b/Add-digest-list-plugin.patch new file mode 100644 index 0000000..f19c9aa --- /dev/null +++ b/Add-digest-list-plugin.patch @@ -0,0 +1,579 @@ +From fa0b33ce1ff569ab55b46cdbcc47f2da6db3fb1a Mon Sep 17 00:00:00 2001 +From: Roberto Sassu +Date: Wed, 26 Feb 2020 15:54:24 +0100 +Subject: [PATCH 2/2] Add digest list plugin + +--- + macros.in | 1 + + plugins/Makefile.am | 4 + + plugins/digest_list.c | 534 ++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 539 insertions(+) + create mode 100644 plugins/digest_list.c + +diff --git a/macros.in b/macros.in +index 402749362..8619c1323 100644 +--- a/macros.in ++++ b/macros.in +@@ -1184,6 +1184,7 @@ package or when debugging this package.\ + %__transaction_ima %{__plugindir}/ima.so + %__transaction_prioreset %{__plugindir}/prioreset.so + %__transaction_audit %{__plugindir}/audit.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 d4ef039ed..07aa3585b 100644 +--- a/plugins/Makefile.am ++++ b/plugins/Makefile.am +@@ -48,3 +48,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/plugins/digest_list.c b/plugins/digest_list.c +new file mode 100644 +index 000000000..62aae06dd +--- /dev/null ++++ b/plugins/digest_list.c +@@ -0,0 +1,534 @@ ++#include "system.h" ++#include "errno.h" ++ ++#include ++#include ++#include ++#include ++#include "lib/rpmplugin.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "debug.h" ++ ++#define IMA_DIR "/sys/kernel/security/ima" ++#define DIGEST_LIST_DATA_PATH IMA_DIR "/digest_list_data" ++#define DIGEST_LIST_DATA_DEL_PATH IMA_DIR "/digest_list_data_del" ++#define DIGEST_LIST_COUNT IMA_DIR "/digests_count" ++#define DIGEST_LIST_DEFAULT_PATH "/etc/ima/digest_lists" ++#define RPM_PARSER "/usr/libexec/rpm_parser" ++#define WRITE_RPM_PGP_SIG "/usr/bin/write_rpm_pgp_sig" ++ ++#define DIGEST_LIST_OP_ADD 0 ++#define DIGEST_LIST_OP_DEL 1 ++ ++enum hash_algo { ++ HASH_ALGO_MD4, ++ HASH_ALGO_MD5, ++ HASH_ALGO_SHA1, ++ HASH_ALGO_RIPE_MD_160, ++ HASH_ALGO_SHA256, ++ HASH_ALGO_SHA384, ++ HASH_ALGO_SHA512, ++ HASH_ALGO_SHA224, ++ HASH_ALGO_RIPE_MD_128, ++ HASH_ALGO_RIPE_MD_256, ++ HASH_ALGO_RIPE_MD_320, ++ HASH_ALGO_WP_256, ++ HASH_ALGO_WP_384, ++ HASH_ALGO_WP_512, ++ HASH_ALGO_TGR_128, ++ HASH_ALGO_TGR_160, ++ HASH_ALGO_TGR_192, ++ HASH_ALGO_SM3_256, ++ HASH_ALGO__LAST ++}; ++ ++enum pgp_hash_algo { ++ PGP_HASH_MD5 = 1, ++ PGP_HASH_SHA1 = 2, ++ PGP_HASH_RIPE_MD_160 = 3, ++ PGP_HASH_SHA256 = 8, ++ PGP_HASH_SHA384 = 9, ++ PGP_HASH_SHA512 = 10, ++ PGP_HASH_SHA224 = 11, ++ PGP_HASH__LAST ++}; ++ ++enum hash_algo pgp_algo_mapping[PGP_HASH__LAST] = { ++ [PGP_HASH_MD5] = HASH_ALGO_MD5, ++ [PGP_HASH_SHA1] = HASH_ALGO_SHA1, ++ [PGP_HASH_SHA224] = HASH_ALGO_SHA224, ++ [PGP_HASH_SHA256] = HASH_ALGO_SHA256, ++ [PGP_HASH_SHA384] = HASH_ALGO_SHA384, ++ [PGP_HASH_SHA512] = HASH_ALGO_SHA512, ++}; ++ ++/* from integrity.h */ ++enum evm_ima_xattr_type { ++ IMA_XATTR_DIGEST = 0x01, ++ EVM_XATTR_HMAC, ++ EVM_IMA_XATTR_DIGSIG, ++ IMA_XATTR_DIGEST_NG, ++ EVM_XATTR_PORTABLE_DIGSIG, ++ EVM_IMA_XATTR_DIGEST_LIST, ++ IMA_XATTR_LAST ++}; ++ ++struct evm_ima_xattr_data { ++ uint8_t type; ++ uint8_t digest[SHA512_DIGEST_LENGTH + 1]; ++} __attribute__((packed)); ++ ++struct signature_v2_hdr { ++ uint8_t type; /* xattr type */ ++ uint8_t version; /* signature format version */ ++ uint8_t hash_algo; /* Digest algorithm [enum hash_algo] */ ++ __be32 keyid; /* IMA key identifier - not X509/PGP specific */ ++ __be16 sig_size; /* signature size */ ++ uint8_t sig[0]; /* signature payload */ ++} __attribute__((packed)); ++ ++static int disable_plugin; ++ ++static int upload_digest_list(char *path, int type, int digest_list_signed) ++{ ++ size_t size; ++ char buf[21]; ++ const char *ima_path = DIGEST_LIST_DATA_PATH; ++ pid_t pid; ++ int ret = 0, fd; ++ ++ if (type == TR_REMOVED) ++ ima_path = DIGEST_LIST_DATA_DEL_PATH; ++ ++ /* First determine if kernel interface can accept new digest lists */ ++ fd = open(DIGEST_LIST_COUNT, O_RDONLY); ++ if (fd < 0) { ++ rpmlog(RPMLOG_ERR, "digest_list: could not open IMA interface " ++ "'%s': %s\n", DIGEST_LIST_COUNT, strerror(errno)); ++ return -EACCES; ++ } ++ ++ ret = read(fd, buf, sizeof(buf)); ++ close(fd); ++ ++ if (ret <= 0) { ++ rpmlog(RPMLOG_ERR, "digest_list: could not read from IMA " ++ "interface '%s': %s\n", DIGEST_LIST_COUNT, ++ strerror(errno)); ++ return -EACCES; ++ } ++ ++ /* Last character is newline */ ++ buf[ret - 1] = '\0'; ++ ++ rpmlog(RPMLOG_DEBUG, "digest_list: digests count %s\n", buf); ++ ++ if (*buf == '0') { ++ rpmlog(RPMLOG_DEBUG, "digest_list: not uploading '%s' to IMA " ++ "interface '%s'\n", path, ima_path); ++ return RPMRC_OK; ++ } ++ ++ /* If the digest list is not signed, execute the RPM parser */ ++ if (!digest_list_signed) { ++ if ((pid = fork()) == 0) { ++ execlp(RPM_PARSER, RPM_PARSER, (type == TR_ADDED) ? ++ "add" : "del", path, NULL); ++ _exit(EXIT_FAILURE); ++ } ++ ++ waitpid(pid, &ret, 0); ++ if (ret != 0) ++ rpmlog(RPMLOG_ERR, "digest_list: %s returned %d\n", ++ RPM_PARSER, ret); ++ return 0; ++ } ++ ++ fd = open(ima_path, O_WRONLY); ++ if (fd < 0) { ++ rpmlog(RPMLOG_ERR, "digest_list: could not open IMA interface " ++ "'%s': %s\n", ima_path, strerror(errno)); ++ return -EACCES; ++ } ++ ++ /* Write the path of the digest list to securityfs */ ++ size = write(fd, path, strlen(path)); ++ if (size != strlen(path)) { ++ rpmlog(RPMLOG_ERR, "digest_list: could not write '%s' to IMA " ++ "interface '%s': %s\n", path, ima_path, strerror(errno)); ++ ret = -EIO; ++ goto out; ++ } ++ ++ rpmlog(RPMLOG_DEBUG, "digest_list: written '%s' to '%s'\n", path, ++ ima_path); ++out: ++ close(fd); ++ return ret; ++} ++ ++static int add_ima_xattr(const char *path, int algo, ++ const unsigned char *digest, int digest_len) ++{ ++ struct evm_ima_xattr_data ima_xattr; ++ int ret; ++ ++ ima_xattr.type = IMA_XATTR_DIGEST_NG; ++ ima_xattr.digest[0] = pgp_algo_mapping[algo]; ++ memcpy(&ima_xattr.digest[1], digest, digest_len); ++ ++ ret = lsetxattr(path, XATTR_NAME_IMA, (uint8_t *)&ima_xattr, ++ digest_len + 2, 0); ++ if (ret < 0) ++ rpmlog(RPMLOG_ERR, "digest_list: could not apply security.ima " ++ "on '%s': %s\n", path, strerror(errno)); ++ else ++ rpmlog(RPMLOG_DEBUG, "digest_list: security.ima successfully " ++ "applied on '%s'\n", path); ++ return ret; ++} ++ ++static int add_evm_digest_list_xattr(const char *path, int algo) ++{ ++ struct signature_v2_hdr hdr; ++ int ret; ++ ++ hdr.type = EVM_IMA_XATTR_DIGEST_LIST, ++ hdr.version = 2; ++ hdr.hash_algo = pgp_algo_mapping[algo]; ++ ++ ret = lsetxattr(path, XATTR_NAME_EVM, (uint8_t *)&hdr, ++ offsetof(struct signature_v2_hdr, keyid), 0); ++ if (ret < 0) ++ rpmlog(RPMLOG_ERR, "digest_list: could not apply security.evm " ++ "on '%s': %s\n", path, strerror(errno)); ++ else ++ rpmlog(RPMLOG_DEBUG, "digest_list: security.evm successfully " ++ "applied on '%s'\n", path); ++ return ret; ++} ++ ++static int add_evm_xattr(char *path, char *path_sig) ++{ ++ unsigned char sig[2048]; ++ size_t sig_len; ++ struct stat st; ++ int ret, fd; ++ ++ if (stat(path_sig, &st) == -1) ++ return -EACCES; ++ ++ if (st.st_size > sizeof(sig)) { ++ rpmlog(RPMLOG_ERR, "digest_list: signature in %s too big\n", ++ path); ++ return -ENOMEM; ++ } ++ ++ fd = open(path_sig, O_RDONLY); ++ if (fd < 0) { ++ rpmlog(RPMLOG_ERR, "digest_list: could not open '%s': %s\n", ++ path_sig, strerror(errno)); ++ return -EACCES; ++ } ++ ++ sig_len = read(fd, sig, sizeof(sig)); ++ if (sig_len != st.st_size) { ++ rpmlog(RPMLOG_ERR, "digest_list: could not read '%s': %s\n", ++ path_sig, strerror(errno)); ++ ret = -EIO; ++ goto out; ++ } ++ ++ rpmlog(RPMLOG_DEBUG, "digest_list: read signature of %ld bytes from " ++ "'%s'\n", sig_len, path_sig); ++ ++ ret = lsetxattr(path, XATTR_NAME_EVM, sig, sig_len, 0); ++ if (ret < 0) ++ rpmlog(RPMLOG_ERR, "digest_list: could not apply security.evm " ++ "on '%s': %s\n", path, strerror(errno)); ++ else ++ rpmlog(RPMLOG_DEBUG, "digest_list: security.evm successfully " ++ "applied on '%s'\n", path); ++out: ++ close(fd); ++ return ret; ++} ++ ++static int write_rpm_digest_list(rpmte te, char *path) ++{ ++ FD_t fd; ++ ssize_t written; ++ Header rpm = rpmteHeader(te); ++ rpmtd immutable; ++ int ret = 0; ++ ++ immutable = rpmtdNew(); ++ headerGet(rpm, RPMTAG_HEADERIMMUTABLE, immutable, 0); ++ ++ fd = Fopen(path, "w.ufdio"); ++ if (fd == NULL || Ferror(fd)) { ++ ret = -EACCES; ++ goto out; ++ } ++ ++ written = Fwrite(rpm_header_magic, sizeof(uint8_t), ++ sizeof(rpm_header_magic), fd); ++ ++ if (written != sizeof(rpm_header_magic)) { ++ ret = -EIO; ++ goto out; ++ } ++ ++ written = Fwrite(immutable->data, sizeof(uint8_t), ++ immutable->count, fd); ++ if (written != immutable->count || Ferror(fd)) ++ ret = -EIO; ++out: ++ Fclose(fd); ++ rpmtdFree(immutable); ++ return ret; ++} ++ ++static int write_rpm_digest_list_sig(rpmte te, char *rpm_path, char *sig_path) ++{ ++ rpmtd signature; ++ ssize_t written; ++ Header rpm = rpmteHeader(te); ++ FD_t fd; ++ pid_t pid; ++ int ret = 0; ++ ++ signature = rpmtdNew(); ++ headerGet(rpm, RPMTAG_RSAHEADER, signature, 0); ++ if (!signature->count) ++ goto out; ++ ++ fd = Fopen(sig_path, "w.ufdio"); ++ if (fd == NULL || Ferror(fd)) { ++ ret = -EACCES; ++ goto out; ++ } ++ ++ written = Fwrite(signature->data, sizeof(uint8_t), ++ signature->count, fd); ++ if (written != signature->count || Ferror(fd)) { ++ ret = -EIO; ++ Fclose(fd); ++ goto out_unlink; ++ } ++ ++ Fclose(fd); ++ ++ if ((pid = fork()) == 0) { ++ execlp(WRITE_RPM_PGP_SIG, WRITE_RPM_PGP_SIG, ++ rpm_path, sig_path, NULL); ++ _exit(EXIT_FAILURE); ++ } ++ ++ waitpid(pid, &ret, 0); ++ if (ret != 0) ++ rpmlog(RPMLOG_ERR, "digest_list: %s returned %d\n", ++ WRITE_RPM_PGP_SIG, ret); ++out_unlink: ++ unlink(sig_path); ++out: ++ rpmtdFree(signature); ++ return ret; ++} ++ ++static int process_digest_list(rpmte te, int parser) ++{ ++ char *path = NULL, *path_sig = NULL; ++ int digest_list_signed = 0; ++ struct stat st; ++ ssize_t size; ++ rpmRC ret = RPMRC_OK; ++ ++ path = malloc(PATH_MAX); ++ if (!path) { ++ ret = RPMRC_FAIL; ++ goto out; ++ } ++ ++ path_sig = malloc(PATH_MAX); ++ if (!path_sig) { ++ ret = RPMRC_FAIL; ++ goto out; ++ } ++ ++ if (parser) ++ snprintf(path_sig, PATH_MAX, ++ "%s.sig/0-parser_list-compact-libexec.sig", ++ DIGEST_LIST_DEFAULT_PATH); ++ else ++ snprintf(path_sig, PATH_MAX, ++ "%s.sig/0-metadata_list-compact-%s-%s-%s.%s.sig", ++ DIGEST_LIST_DEFAULT_PATH, rpmteN(te), rpmteV(te), ++ rpmteR(te), rpmteA(te)); ++ ++ if (!stat(path_sig, &st)) { ++ digest_list_signed = 1; ++ } else { ++ if (stat(WRITE_RPM_PGP_SIG, &st) == -1 || ++ stat(RPM_PARSER, &st) == -1) { ++ rpmlog(RPMLOG_DEBUG, "digest_list: " ++ "digest-list-tools not installed\n"); ++ goto out; ++ } ++ } ++ ++ if (parser) ++ snprintf(path, PATH_MAX, "%s/0-parser_list-compact-libexec", ++ DIGEST_LIST_DEFAULT_PATH); ++ else ++ snprintf(path, PATH_MAX, ++ "%s/0-metadata_list-compact-%s-%s-%s.%s", ++ DIGEST_LIST_DEFAULT_PATH, rpmteN(te), rpmteV(te), ++ rpmteR(te), rpmteA(te)); ++ ++ if (stat(path, &st) == -1) ++ goto out; ++ ++ if (!parser && !digest_list_signed) { ++ snprintf(path, PATH_MAX, "%s/0-metadata_list-rpm-%s-%s-%s.%s", ++ DIGEST_LIST_DEFAULT_PATH, rpmteN(te), rpmteV(te), ++ rpmteR(te), rpmteA(te)); ++ ++ /* RPM digest lists don't have security.evm */ ++ size = lgetxattr(path, XATTR_NAME_IMA, NULL, 0); ++ } else { ++ size = lgetxattr(path, XATTR_NAME_EVM, NULL, 0); ++ } ++ ++ /* Don't upload again if digest list was already processed */ ++ if ((rpmteType(te) == TR_ADDED && size > 0) || ++ (rpmteType(te) == TR_REMOVED && size < 0)) { ++ rpmlog(RPMLOG_DEBUG, "digest_list: '%s' already processed, " ++ "nothing to do\n", path); ++ goto out; ++ } ++ ++ if (rpmteType(te) == TR_ADDED) { ++ if (!digest_list_signed) { ++ /* Write RPM header to the disk */ ++ ret = write_rpm_digest_list(te, path); ++ if (ret < 0) { ++ ret = RPMRC_FAIL; ++ goto out; ++ } ++ ++ /* Write RPM header sig to security.ima */ ++ ret = write_rpm_digest_list_sig(te, path, path_sig); ++ if (ret < 0) { ++ ret = RPMRC_FAIL; ++ goto out; ++ } ++ } else { ++ add_evm_xattr(path, path_sig); ++ } ++ } ++ ++ /* Upload digest list to securityfs */ ++ upload_digest_list(path, rpmteType(te), digest_list_signed); ++ ++ if (rpmteType(te) == TR_REMOVED) { ++ if (!digest_list_signed) { ++ unlink(path); ++ goto out; ++ } ++ ++ ret = lremovexattr(path, XATTR_NAME_EVM); ++ if (ret < 0) ++ rpmlog(RPMLOG_ERR, "digest_list: cannot remove " ++ "security.evm from '%s'\n", path); ++ else ++ rpmlog(RPMLOG_DEBUG, "digest_list: security.evm " ++ "successfully removed from '%s'\n", path); ++ } ++out: ++ free(path); ++ free(path_sig); ++ return ret; ++} ++ ++static rpmRC digest_list_psm_pre(rpmPlugin plugin, rpmte te) ++{ ++ struct stat st; ++ ++ if (disable_plugin) ++ return RPMRC_OK; ++ ++ if (stat(DIGEST_LIST_DATA_PATH, &st) == -1) { ++ rpmlog(RPMLOG_DEBUG, "digest_list: IMA interface '%s' not " ++ "found, disabling plugin\n", DIGEST_LIST_DATA_PATH); ++ disable_plugin = 1; ++ return RPMRC_OK; ++ } ++ ++ process_digest_list(te, 0); ++ if (!strcmp(rpmteN(te), "digest-list-tools")) ++ process_digest_list(te, 1); ++ ++ return RPMRC_OK; ++} ++ ++static rpmRC digest_list_psm_post(rpmPlugin plugin, rpmte te, int res) ++{ ++ if (disable_plugin) ++ return RPMRC_OK; ++ ++ if (res != RPMRC_OK) ++ return RPMRC_OK; ++ ++ process_digest_list(te, 0); ++ if (!strcmp(rpmteN(te), "digest-list-tools")) ++ process_digest_list(te, 1); ++ ++ return RPMRC_OK; ++} ++ ++static rpmRC digest_list_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, ++ const char *path, ++ const char *dest, ++ mode_t file_mode, rpmFsmOp op) ++{ ++ const unsigned char *fdigest = NULL; ++ size_t len; ++ int algo; ++ rpmFileAction action = XFO_ACTION(op); ++ ++ if (disable_plugin) ++ return RPMRC_OK; ++ ++ /* Ignore skipped files and unowned directories */ ++ if (XFA_SKIPPING(action) || (op & FAF_UNOWNED)) ++ goto exit; ++ ++ /* Ignore non-regular files */ ++ if (!S_ISREG(file_mode)) ++ goto exit; ++ ++ fdigest = rpmfiFDigest(fi, &algo, &len); ++ if (!fdigest) ++ goto exit; ++ ++ /* Assume that the hash algorithm used by evmctl and RPMs is the same */ ++ add_ima_xattr(path, algo, fdigest, len); ++ if (strncmp(path, DIGEST_LIST_DEFAULT_PATH, ++ sizeof(DIGEST_LIST_DEFAULT_PATH) - 1)) ++ add_evm_digest_list_xattr(path, algo); ++exit: ++ return RPMRC_OK; ++} ++ ++struct rpmPluginHooks_s digest_list_hooks = { ++ .psm_pre = digest_list_psm_pre, ++ .psm_post = digest_list_psm_post, ++ .fsm_file_prepare = digest_list_fsm_file_prepare, ++}; +-- +2.27.GIT + diff --git a/Generate-digest-lists.patch b/Generate-digest-lists.patch new file mode 100644 index 0000000..9cb7d1a --- /dev/null +++ b/Generate-digest-lists.patch @@ -0,0 +1,306 @@ +From 99d243a37d50155bc3e9b4ef8d1457a73016c9c0 Mon Sep 17 00:00:00 2001 +From: Roberto Sassu +Date: Thu, 12 Mar 2020 17:29:55 +0100 +Subject: [PATCH 1/2] Generate digest lists + +--- + build/files.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 159 insertions(+), 7 deletions(-) + +diff --git a/build/files.c b/build/files.c +index 6dfd801c8..3dd8f0246 100644 +--- a/build/files.c ++++ b/build/files.c +@@ -50,6 +50,7 @@ + #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" + + #undef HASHTYPE + #undef HTKEYTYPE +@@ -129,6 +130,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 +196,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)); +@@ -984,11 +991,13 @@ static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc) + { + FileListRec flp; + char buf[BUFSIZ]; ++ char file_info[BUFSIZ]; ++ char file_digest[128 * 2 + 1]; + int i, npaths = 0; + uint32_t defaultalgo = PGPHASHALGO_MD5, digestalgo; + rpm_loff_t totalFileSize = 0; + Header h = pkg->header; /* just a shortcut */ +- int override_date = 0; ++ int override_date = 0, processed = 0; + time_t source_date_epoch; + char *srcdate = getenv("SOURCE_DATE_EPOCH"); + +@@ -1058,8 +1067,9 @@ static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc) + + pkg->dpaths = xmalloc((fl->files.used + 1) * sizeof(*pkg->dpaths)); + ++process_files: + /* Generate the header. */ +- for (i = 0, flp = fl->files.recs; i < fl->files.used; i++, flp++) { ++ for (i = processed, flp = fl->files.recs + processed; i < fl->files.used; i++, flp++) { + rpm_ino_t fileid = flp - fl->files.recs; + + /* Merge duplicate entries. */ +@@ -1190,7 +1200,8 @@ static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc) + (void) rpmDoDigest(digestalgo, flp->diskPath, 1, + (unsigned char *)buf); + headerPutString(h, RPMTAG_FILEDIGESTS, buf); +- ++ snprintf(file_digest, sizeof(file_digest), "%s", buf); ++ + buf[0] = '\0'; + if (S_ISLNK(flp->fl_mode)) { + ssize_t llen = readlink(flp->diskPath, buf, BUFSIZ-1); +@@ -1230,7 +1241,33 @@ static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc) + flp->flags &= PARSEATTR_MASK; + + headerPutUint32(h, RPMTAG_FILEFLAGS, &(flp->flags) ,1); ++ ++ if (!processed && 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 (!processed) { ++ if (genDigestList(pkg->header, fl, check_fileList_bin_pkg) > 0) { ++ fl->processingFailed = 1; ++ } else if (i < fl->files.used) { ++ pkg->dpaths = xrealloc(pkg->dpaths, ++ (fl->files.used + 1) * sizeof(*pkg->dpaths)); ++ processed = i; ++ goto process_files; ++ } + } ++ + pkg->dpaths[npaths] = NULL; + + if (totalFileSize < UINT32_MAX) { +@@ -1343,8 +1380,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]; +@@ -1355,6 +1392,8 @@ 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; + rpmRC rc = RPMRC_FAIL; /* assume failure */ + + /* Strip trailing slash. The special case of '/' path is handled below. */ +@@ -1390,6 +1429,27 @@ 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; ++ } ++ + /* + * Unless recursing, we dont have stat() info at hand. Handle the + * various cases, preserving historical behavior wrt %dev(): +@@ -1547,6 +1607,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 +@@ -2556,6 +2642,58 @@ 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; ++ ++ 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) + { +@@ -2569,6 +2707,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)); + +@@ -2630,6 +2772,7 @@ exit: + FileListFree(&fl); + specialDirFree(specialDoc); + specialDirFree(specialLic); ++ freeStringBuf(check_fileList_bin_pkg); + return fl.processingFailed ? RPMRC_FAIL : RPMRC_OK; + } + +@@ -3092,6 +3235,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; +@@ -3108,7 +3252,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) { +@@ -3214,6 +3365,7 @@ exit: + check_fileList = freeStringBuf(check_fileList); + _free(buildroot); + _free(uniquearch); +- ++ _free(digest_list_dir); ++ + return rc; + } +-- +2.27.GIT + diff --git a/rpm.spec b/rpm.spec index d597c69..a5b92d4 100644 --- a/rpm.spec +++ b/rpm.spec @@ -1,6 +1,6 @@ Name: rpm Version: 4.15.1 -Release: 16 +Release: 17 Summary: RPM Package Manager License: GPLv2+ URL: http://www.rpm.org/ @@ -287,6 +287,12 @@ make check || (cat tests/rpmtests.log; exit 0) %{_mandir}/man1/gendiff.1* %changelog +* Tue Jul 14 2020 Roberto Sassu - 4.15.1-17 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:add support for digest lists + * Fri May 22 2020 openEuler Buildteam - 4.15.1-16 - Type:bugfix - ID:NA From e3018fd4d007a2990c58702bdb15bee80ced2fbc Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Tue, 14 Jul 2020 16:00:08 +0200 Subject: [PATCH 2/7] Add missing patches to rpm.spec --- rpm.spec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rpm.spec b/rpm.spec index a5b92d4..e658f88 100644 --- a/rpm.spec +++ b/rpm.spec @@ -19,6 +19,8 @@ Patch9: bugfix-rpm-4.11.3-add-aarch64_ilp32-arch.patch Patch10: bugfix-rpm-4.14.2-fix-tty-failed.patch Patch11: bugfix-rpm-4.14.2-wait-once-get-rpmlock-fail.patch Patch12: Use-common-error-logic-regardless-of-setexecfilecon-.patch +Patch13: Generate-digest-lists.patch +Patch14: Add-digest-list-plugin.patch BuildRequires: gcc autoconf automake libtool make gawk popt-devel openssl-devel readline-devel libdb-devel BuildRequires: zlib-devel libzstd-devel xz-devel bzip2-devel libarchive-devel ima-evm-utils-devel From 4423f5283006fd58473670dda3bad818094f9b1b Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Fri, 24 Jul 2020 00:06:48 +0200 Subject: [PATCH 3/7] Add Don-t-add-dist-to-release-if-it-is-already-there.patch and modify Add-digest-list-plugin.patch --- Add-digest-list-plugin.patch | 415 ++++++++++++++++++----------------- Generate-digest-lists.patch | 45 ++-- rpm.spec | 1 + 3 files changed, 241 insertions(+), 220 deletions(-) diff --git a/Add-digest-list-plugin.patch b/Add-digest-list-plugin.patch index f19c9aa..cba3807 100644 --- a/Add-digest-list-plugin.patch +++ b/Add-digest-list-plugin.patch @@ -1,13 +1,15 @@ -From fa0b33ce1ff569ab55b46cdbcc47f2da6db3fb1a Mon Sep 17 00:00:00 2001 +From c3b5c61440a40b4a159e050e25f4b3736f7d0343 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Wed, 26 Feb 2020 15:54:24 +0100 -Subject: [PATCH 2/2] Add digest list plugin +Subject: [PATCH 2/3] Add digest list plugin --- macros.in | 1 + plugins/Makefile.am | 4 + - plugins/digest_list.c | 534 ++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 539 insertions(+) + plugins/digest_list.c | 495 ++++++++++++++++++++++++++++++++++++++++++ + rpmio/digest.h | 1 + + rpmio/rpmpgp.c | 3 + + 5 files changed, 504 insertions(+) create mode 100644 plugins/digest_list.c diff --git a/macros.in b/macros.in @@ -36,18 +38,21 @@ index d4ef039ed..07aa3585b 100644 +plugins_LTLIBRARIES += digest_list.la diff --git a/plugins/digest_list.c b/plugins/digest_list.c new file mode 100644 -index 000000000..62aae06dd +index 000000000..227ce141e --- /dev/null +++ b/plugins/digest_list.c -@@ -0,0 +1,534 @@ +@@ -0,0 +1,495 @@ +#include "system.h" +#include "errno.h" + +#include +#include +#include ++#include ++#include +#include +#include "lib/rpmplugin.h" ++#include +#include +#include +#include @@ -63,7 +68,6 @@ index 000000000..62aae06dd +#define DIGEST_LIST_COUNT IMA_DIR "/digests_count" +#define DIGEST_LIST_DEFAULT_PATH "/etc/ima/digest_lists" +#define RPM_PARSER "/usr/libexec/rpm_parser" -+#define WRITE_RPM_PGP_SIG "/usr/bin/write_rpm_pgp_sig" + +#define DIGEST_LIST_OP_ADD 0 +#define DIGEST_LIST_OP_DEL 1 @@ -90,24 +94,14 @@ index 000000000..62aae06dd + HASH_ALGO__LAST +}; + -+enum pgp_hash_algo { -+ PGP_HASH_MD5 = 1, -+ PGP_HASH_SHA1 = 2, -+ PGP_HASH_RIPE_MD_160 = 3, -+ PGP_HASH_SHA256 = 8, -+ PGP_HASH_SHA384 = 9, -+ PGP_HASH_SHA512 = 10, -+ PGP_HASH_SHA224 = 11, -+ PGP_HASH__LAST -+}; -+ -+enum hash_algo pgp_algo_mapping[PGP_HASH__LAST] = { -+ [PGP_HASH_MD5] = HASH_ALGO_MD5, -+ [PGP_HASH_SHA1] = HASH_ALGO_SHA1, -+ [PGP_HASH_SHA224] = HASH_ALGO_SHA224, -+ [PGP_HASH_SHA256] = HASH_ALGO_SHA256, -+ [PGP_HASH_SHA384] = HASH_ALGO_SHA384, -+ [PGP_HASH_SHA512] = HASH_ALGO_SHA512, ++#define PGPHASHALGO__LAST PGPHASHALGO_SHA224 + 1 ++enum hash_algo pgp_algo_mapping[PGPHASHALGO__LAST] = { ++ [PGPHASHALGO_MD5] = HASH_ALGO_MD5, ++ [PGPHASHALGO_SHA1] = HASH_ALGO_SHA1, ++ [PGPHASHALGO_SHA224] = HASH_ALGO_SHA224, ++ [PGPHASHALGO_SHA256] = HASH_ALGO_SHA256, ++ [PGPHASHALGO_SHA384] = HASH_ALGO_SHA384, ++ [PGPHASHALGO_SHA512] = HASH_ALGO_SHA512, +}; + +/* from integrity.h */ @@ -135,19 +129,21 @@ index 000000000..62aae06dd + uint8_t sig[0]; /* signature payload */ +} __attribute__((packed)); + -+static int disable_plugin; -+ +static int upload_digest_list(char *path, int type, int digest_list_signed) +{ + size_t size; + char buf[21]; + const char *ima_path = DIGEST_LIST_DATA_PATH; ++ struct stat st; + pid_t pid; + int ret = 0, fd; + + if (type == TR_REMOVED) + ima_path = DIGEST_LIST_DATA_DEL_PATH; + ++ if (stat(ima_path, &st) == -1) ++ return 0; ++ + /* First determine if kernel interface can accept new digest lists */ + fd = open(DIGEST_LIST_COUNT, O_RDONLY); + if (fd < 0) { @@ -215,93 +211,6 @@ index 000000000..62aae06dd + return ret; +} + -+static int add_ima_xattr(const char *path, int algo, -+ const unsigned char *digest, int digest_len) -+{ -+ struct evm_ima_xattr_data ima_xattr; -+ int ret; -+ -+ ima_xattr.type = IMA_XATTR_DIGEST_NG; -+ ima_xattr.digest[0] = pgp_algo_mapping[algo]; -+ memcpy(&ima_xattr.digest[1], digest, digest_len); -+ -+ ret = lsetxattr(path, XATTR_NAME_IMA, (uint8_t *)&ima_xattr, -+ digest_len + 2, 0); -+ if (ret < 0) -+ rpmlog(RPMLOG_ERR, "digest_list: could not apply security.ima " -+ "on '%s': %s\n", path, strerror(errno)); -+ else -+ rpmlog(RPMLOG_DEBUG, "digest_list: security.ima successfully " -+ "applied on '%s'\n", path); -+ return ret; -+} -+ -+static int add_evm_digest_list_xattr(const char *path, int algo) -+{ -+ struct signature_v2_hdr hdr; -+ int ret; -+ -+ hdr.type = EVM_IMA_XATTR_DIGEST_LIST, -+ hdr.version = 2; -+ hdr.hash_algo = pgp_algo_mapping[algo]; -+ -+ ret = lsetxattr(path, XATTR_NAME_EVM, (uint8_t *)&hdr, -+ offsetof(struct signature_v2_hdr, keyid), 0); -+ if (ret < 0) -+ rpmlog(RPMLOG_ERR, "digest_list: could not apply security.evm " -+ "on '%s': %s\n", path, strerror(errno)); -+ else -+ rpmlog(RPMLOG_DEBUG, "digest_list: security.evm successfully " -+ "applied on '%s'\n", path); -+ return ret; -+} -+ -+static int add_evm_xattr(char *path, char *path_sig) -+{ -+ unsigned char sig[2048]; -+ size_t sig_len; -+ struct stat st; -+ int ret, fd; -+ -+ if (stat(path_sig, &st) == -1) -+ return -EACCES; -+ -+ if (st.st_size > sizeof(sig)) { -+ rpmlog(RPMLOG_ERR, "digest_list: signature in %s too big\n", -+ path); -+ return -ENOMEM; -+ } -+ -+ fd = open(path_sig, O_RDONLY); -+ if (fd < 0) { -+ rpmlog(RPMLOG_ERR, "digest_list: could not open '%s': %s\n", -+ path_sig, strerror(errno)); -+ return -EACCES; -+ } -+ -+ sig_len = read(fd, sig, sizeof(sig)); -+ if (sig_len != st.st_size) { -+ rpmlog(RPMLOG_ERR, "digest_list: could not read '%s': %s\n", -+ path_sig, strerror(errno)); -+ ret = -EIO; -+ goto out; -+ } -+ -+ rpmlog(RPMLOG_DEBUG, "digest_list: read signature of %ld bytes from " -+ "'%s'\n", sig_len, path_sig); -+ -+ ret = lsetxattr(path, XATTR_NAME_EVM, sig, sig_len, 0); -+ if (ret < 0) -+ rpmlog(RPMLOG_ERR, "digest_list: could not apply security.evm " -+ "on '%s': %s\n", path, strerror(errno)); -+ else -+ rpmlog(RPMLOG_DEBUG, "digest_list: security.evm successfully " -+ "applied on '%s'\n", path); -+out: -+ close(fd); -+ return ret; -+} -+ +static int write_rpm_digest_list(rpmte te, char *path) +{ + FD_t fd; @@ -337,49 +246,164 @@ index 000000000..62aae06dd + return ret; +} + -+static int write_rpm_digest_list_sig(rpmte te, char *rpm_path, char *sig_path) ++static int write_rpm_digest_list_ima_xattr(rpmte te, char *path) +{ + rpmtd signature; + ssize_t written; ++ uint8_t sig[2048] = { 0 }; ++ pgpDigParams sigp = NULL; ++ struct signature_v2_hdr *sig_hdr = (struct signature_v2_hdr *)sig; + Header rpm = rpmteHeader(te); + FD_t fd; -+ pid_t pid; -+ int ret = 0; ++ int ret = 0, sig_size, sig_size_rounded; + + signature = rpmtdNew(); + headerGet(rpm, RPMTAG_RSAHEADER, signature, 0); -+ if (!signature->count) -+ goto out; ++ ret = pgpPrtParams(signature->data, signature->count, ++ PGPTAG_SIGNATURE, &sigp); + -+ fd = Fopen(sig_path, "w.ufdio"); ++ if (ret) { ++ ret = -ENOENT; ++ goto out; ++ } ++ ++ fd = Fopen(path, "a.ufdio"); + if (fd == NULL || Ferror(fd)) { + ret = -EACCES; + goto out; + } + -+ written = Fwrite(signature->data, sizeof(uint8_t), -+ signature->count, fd); -+ if (written != signature->count || Ferror(fd)) { ++ written = Fwrite(sigp->hash, sizeof(uint8_t), ++ sigp->hashlen, fd); ++ if (written != sigp->hashlen || Ferror(fd)) { + ret = -EIO; -+ Fclose(fd); -+ goto out_unlink; ++ goto out; ++ } ++ ++ if (sigp->version == 4) { ++ /* V4 trailer is six octets long (rfc4880) */ ++ uint8_t trailer[6]; ++ uint32_t nb = sigp->hashlen; ++ nb = htonl(nb); ++ trailer[0] = sigp->version; ++ trailer[1] = 0xff; ++ memcpy(trailer+2, &nb, 4); ++ ++ written = Fwrite(trailer, sizeof(uint8_t), sizeof(trailer), fd); ++ if (written != sizeof(trailer) || Ferror(fd)) { ++ ret = -EIO; ++ goto out; ++ } + } + + Fclose(fd); + -+ if ((pid = fork()) == 0) { -+ execlp(WRITE_RPM_PGP_SIG, WRITE_RPM_PGP_SIG, -+ rpm_path, sig_path, NULL); -+ _exit(EXIT_FAILURE); ++ sig_hdr->type = EVM_IMA_XATTR_DIGSIG; ++ sig_hdr->version = 2; ++ sig_hdr->hash_algo = pgp_algo_mapping[sigp->hash_algo]; ++ memcpy((void *)&sig_hdr->keyid, sigp->signid + sizeof(uint32_t), ++ sizeof(uint32_t)); ++ ++ sig_size = (pgpMpiBits(sigp->data) + 7) >> 3; ++ if (sizeof(sig_hdr) + sig_size > sizeof(sig)) { ++ rpmlog(RPMLOG_ERR, ++ "digest_list: signature in %s too big\n", path); ++ ret = -E2BIG; ++ goto out; + } + -+ waitpid(pid, &ret, 0); -+ if (ret != 0) -+ rpmlog(RPMLOG_ERR, "digest_list: %s returned %d\n", -+ WRITE_RPM_PGP_SIG, ret); -+out_unlink: -+ unlink(sig_path); ++ sig_size_rounded = ((sig_size + 7) >> 3) * 8; ++ sig_hdr->sig_size = __cpu_to_be16(sig_size_rounded); ++ ++ memcpy(sig_hdr->sig + sig_size_rounded - sig_size, ++ (uint8_t *)sigp->data + 2, sig_size); ++ ++ ret = lsetxattr(path, XATTR_NAME_IMA, ++ sig, sizeof(*sig_hdr) + sig_size_rounded, 0); ++ if (ret < 0) ++ rpmlog(RPMLOG_ERR, "digest_list: could not apply security.ima " ++ "on '%s': %s\n", path, strerror(errno)); ++ else ++ rpmlog(RPMLOG_DEBUG, "digest_list: security.ima successfully " ++ "applied on '%s'\n", path); +out: ++ pgpDigParamsFree(sigp); ++ rpmtdFree(signature); ++ return ret; ++} ++ ++static int write_digest_list_ima_xattr(rpmte te, char *path, char *path_sig) ++{ ++ rpmtd signature; ++ uint8_t sig[2048] = { 0 }; ++ pgpDigParams sigp = NULL; ++ struct signature_v2_hdr *sig_hdr = (struct signature_v2_hdr *)sig; ++ Header rpm = rpmteHeader(te); ++ FD_t fd; ++ struct stat st; ++ int ret = 0, sig_size; ++ ++ signature = rpmtdNew(); ++ headerGet(rpm, RPMTAG_RSAHEADER, signature, 0); ++ ret = pgpPrtParams(signature->data, signature->count, ++ PGPTAG_SIGNATURE, &sigp); ++ ++ if (ret) { ++ ret = -ENOENT; ++ goto out; ++ } ++ ++ sig_hdr->type = EVM_IMA_XATTR_DIGSIG; ++ sig_hdr->version = 2; ++ sig_hdr->hash_algo = HASH_ALGO_SHA256; ++ memcpy((void *)&sig_hdr->keyid, sigp->signid + sizeof(uint32_t), ++ sizeof(uint32_t)); ++ ++ if (stat(path_sig, &st) == -1) { ++ ret = -EACCES; ++ goto out; ++ } ++ ++ if (sizeof(sig_hdr) + st.st_size > sizeof(sig)) { ++ rpmlog(RPMLOG_ERR, "digest_list: signature in %s too big\n", ++ path); ++ ret = -E2BIG; ++ goto out; ++ } ++ ++ fd = Fopen(path_sig, "r.ufdio"); ++ if (fd < 0) { ++ rpmlog(RPMLOG_ERR, "digest_list: could not open '%s': %s\n", ++ path_sig, strerror(errno)); ++ ret = -EACCES; ++ goto out; ++ } ++ ++ sig_size = Fread(sig_hdr->sig, sizeof(uint8_t), st.st_size, fd); ++ if (sig_size != st.st_size || Ferror(fd)) { ++ rpmlog(RPMLOG_ERR, "digest_list: could not read '%s': %s\n", ++ path_sig, strerror(errno)); ++ Fclose(fd); ++ ret = -EIO; ++ goto out; ++ } ++ ++ sig_hdr->sig_size = __cpu_to_be16(sig_size); ++ ++ rpmlog(RPMLOG_DEBUG, ++ "digest_list: read signature of %d bytes from '%s'\n", ++ sig_size, path_sig); ++ ++ ret = lsetxattr(path, XATTR_NAME_IMA, ++ sig, sizeof(*sig_hdr) + sig_size, 0); ++ if (ret < 0) ++ rpmlog(RPMLOG_ERR, "digest_list: could not apply security.ima " ++ "on '%s': %s\n", path, strerror(errno)); ++ else ++ rpmlog(RPMLOG_DEBUG, "digest_list: security.ima successfully " ++ "applied on '%s'\n", path); ++out: ++ pgpDigParamsFree(sigp); + rpmtdFree(signature); + return ret; +} @@ -414,16 +438,8 @@ index 000000000..62aae06dd + DIGEST_LIST_DEFAULT_PATH, rpmteN(te), rpmteV(te), + rpmteR(te), rpmteA(te)); + -+ if (!stat(path_sig, &st)) { ++ if (!stat(path_sig, &st)) + digest_list_signed = 1; -+ } else { -+ if (stat(WRITE_RPM_PGP_SIG, &st) == -1 || -+ stat(RPM_PARSER, &st) == -1) { -+ rpmlog(RPMLOG_DEBUG, "digest_list: " -+ "digest-list-tools not installed\n"); -+ goto out; -+ } -+ } + + if (parser) + snprintf(path, PATH_MAX, "%s/0-parser_list-compact-libexec", @@ -437,16 +453,12 @@ index 000000000..62aae06dd + if (stat(path, &st) == -1) + goto out; + -+ if (!parser && !digest_list_signed) { ++ if (!parser && !digest_list_signed) + snprintf(path, PATH_MAX, "%s/0-metadata_list-rpm-%s-%s-%s.%s", + DIGEST_LIST_DEFAULT_PATH, rpmteN(te), rpmteV(te), + rpmteR(te), rpmteA(te)); + -+ /* RPM digest lists don't have security.evm */ -+ size = lgetxattr(path, XATTR_NAME_IMA, NULL, 0); -+ } else { -+ size = lgetxattr(path, XATTR_NAME_EVM, NULL, 0); -+ } ++ size = lgetxattr(path, XATTR_NAME_IMA, NULL, 0); + + /* Don't upload again if digest list was already processed */ + if ((rpmteType(te) == TR_ADDED && size > 0) || @@ -466,13 +478,14 @@ index 000000000..62aae06dd + } + + /* Write RPM header sig to security.ima */ -+ ret = write_rpm_digest_list_sig(te, path, path_sig); -+ if (ret < 0) { -+ ret = RPMRC_FAIL; -+ goto out; -+ } ++ ret = write_rpm_digest_list_ima_xattr(te, path); + } else { -+ add_evm_xattr(path, path_sig); ++ ret = write_digest_list_ima_xattr(te, path, path_sig); ++ } ++ ++ if (ret < 0) { ++ ret = RPMRC_FAIL; ++ goto out; + } + } + @@ -501,18 +514,6 @@ index 000000000..62aae06dd + +static rpmRC digest_list_psm_pre(rpmPlugin plugin, rpmte te) +{ -+ struct stat st; -+ -+ if (disable_plugin) -+ return RPMRC_OK; -+ -+ if (stat(DIGEST_LIST_DATA_PATH, &st) == -1) { -+ rpmlog(RPMLOG_DEBUG, "digest_list: IMA interface '%s' not " -+ "found, disabling plugin\n", DIGEST_LIST_DATA_PATH); -+ disable_plugin = 1; -+ return RPMRC_OK; -+ } -+ + process_digest_list(te, 0); + if (!strcmp(rpmteN(te), "digest-list-tools")) + process_digest_list(te, 1); @@ -522,9 +523,6 @@ index 000000000..62aae06dd + +static rpmRC digest_list_psm_post(rpmPlugin plugin, rpmte te, int res) +{ -+ if (disable_plugin) -+ return RPMRC_OK; -+ + if (res != RPMRC_OK) + return RPMRC_OK; + @@ -535,45 +533,50 @@ index 000000000..62aae06dd + return RPMRC_OK; +} + -+static rpmRC digest_list_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, -+ const char *path, -+ const char *dest, -+ mode_t file_mode, rpmFsmOp op) -+{ -+ const unsigned char *fdigest = NULL; -+ size_t len; -+ int algo; -+ rpmFileAction action = XFO_ACTION(op); -+ -+ if (disable_plugin) -+ return RPMRC_OK; -+ -+ /* Ignore skipped files and unowned directories */ -+ if (XFA_SKIPPING(action) || (op & FAF_UNOWNED)) -+ goto exit; -+ -+ /* Ignore non-regular files */ -+ if (!S_ISREG(file_mode)) -+ goto exit; -+ -+ fdigest = rpmfiFDigest(fi, &algo, &len); -+ if (!fdigest) -+ goto exit; -+ -+ /* Assume that the hash algorithm used by evmctl and RPMs is the same */ -+ add_ima_xattr(path, algo, fdigest, len); -+ if (strncmp(path, DIGEST_LIST_DEFAULT_PATH, -+ sizeof(DIGEST_LIST_DEFAULT_PATH) - 1)) -+ add_evm_digest_list_xattr(path, algo); -+exit: -+ return RPMRC_OK; -+} -+ +struct rpmPluginHooks_s digest_list_hooks = { + .psm_pre = digest_list_psm_pre, + .psm_post = digest_list_psm_post, -+ .fsm_file_prepare = digest_list_fsm_file_prepare, +}; +diff --git a/rpmio/digest.h b/rpmio/digest.h +index 9e0cde3b9..01ca10d92 100644 +--- a/rpmio/digest.h ++++ b/rpmio/digest.h +@@ -24,6 +24,7 @@ struct pgpDigAlg_s { + struct pgpDigParams_s { + char * userid; + uint8_t * hash; ++ const uint8_t * data; + uint8_t tag; + + uint8_t version; /*!< version number. */ +diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c +index 46cd0f31a..3c6b18b53 100644 +--- a/rpmio/rpmpgp.c ++++ b/rpmio/rpmpgp.c +@@ -600,6 +600,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, + } + + p = ((uint8_t *)v) + sizeof(*v); ++ _digp->data = p; + rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen, _digp); + } break; + case 4: +@@ -658,6 +659,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, + if (p > (h + hlen)) + return 1; + ++ _digp->data = p; + rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen, _digp); + } break; + default: +@@ -745,6 +747,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; -- 2.27.GIT diff --git a/Generate-digest-lists.patch b/Generate-digest-lists.patch index 9cb7d1a..cc74351 100644 --- a/Generate-digest-lists.patch +++ b/Generate-digest-lists.patch @@ -1,14 +1,14 @@ -From 99d243a37d50155bc3e9b4ef8d1457a73016c9c0 Mon Sep 17 00:00:00 2001 +From 4d1801825c754171962050ee9c36c2d69c630ece Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Thu, 12 Mar 2020 17:29:55 +0100 -Subject: [PATCH 1/2] Generate digest lists +Subject: [PATCH 1/3] Generate digest lists --- - build/files.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++--- - 1 file changed, 159 insertions(+), 7 deletions(-) + build/files.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 169 insertions(+), 7 deletions(-) diff --git a/build/files.c b/build/files.c -index 6dfd801c8..3dd8f0246 100644 +index 6dfd801c8..ab6938d8c 100644 --- a/build/files.c +++ b/build/files.c @@ -50,6 +50,7 @@ @@ -120,16 +120,18 @@ index 6dfd801c8..3dd8f0246 100644 { size_t plen = strlen(diskPath); char buf[plen + 1]; -@@ -1355,6 +1392,8 @@ static rpmRC addFile(FileList fl, const char * diskPath, +@@ -1355,6 +1392,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. */ -@@ -1390,6 +1429,27 @@ static rpmRC addFile(FileList fl, const char * diskPath, +@@ -1390,6 +1431,33 @@ static rpmRC addFile(FileList fl, const char * diskPath, if (*cpioPath == '\0') cpioPath = "/"; @@ -152,12 +154,27 @@ index 6dfd801c8..3dd8f0246 100644 + } + + 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(): -@@ -1547,6 +1607,32 @@ exit: +@@ -1527,6 +1595,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; + +@@ -1547,6 +1617,32 @@ exit: return rc; } @@ -190,7 +207,7 @@ index 6dfd801c8..3dd8f0246 100644 /** * Add directory (and all of its files) to the package manifest. * @param fl package file tree walk data -@@ -2556,6 +2642,58 @@ static void addPackageFileList (struct FileList_s *fl, Package pkg, +@@ -2556,6 +2652,58 @@ static void addPackageFileList (struct FileList_s *fl, Package pkg, argvFree(fileNames); } @@ -249,7 +266,7 @@ index 6dfd801c8..3dd8f0246 100644 static rpmRC processPackageFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags, Package pkg, int didInstall, int test) { -@@ -2569,6 +2707,10 @@ static rpmRC processPackageFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags, +@@ -2569,6 +2717,10 @@ static rpmRC processPackageFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags, if (readFilesManifest(spec, pkg, *fp)) return RPMRC_FAIL; } @@ -260,7 +277,7 @@ index 6dfd801c8..3dd8f0246 100644 /* Init the file list structure */ memset(&fl, 0, sizeof(fl)); -@@ -2630,6 +2772,7 @@ exit: +@@ -2630,6 +2782,7 @@ exit: FileListFree(&fl); specialDirFree(specialDoc); specialDirFree(specialLic); @@ -268,7 +285,7 @@ index 6dfd801c8..3dd8f0246 100644 return fl.processingFailed ? RPMRC_FAIL : RPMRC_OK; } -@@ -3092,6 +3235,7 @@ static void addPackageDeps(Package from, Package to, enum rpmTag_e tag) +@@ -3092,6 +3245,7 @@ static void addPackageDeps(Package from, Package to, enum rpmTag_e tag) rpmRC processBinaryFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags, int didInstall, int test) { @@ -276,7 +293,7 @@ index 6dfd801c8..3dd8f0246 100644 Package pkg; rpmRC rc = RPMRC_OK; char *buildroot; -@@ -3108,7 +3252,14 @@ rpmRC processBinaryFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags, +@@ -3108,7 +3262,14 @@ rpmRC processBinaryFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags, check_fileList = newStringBuf(); genSourceRpmName(spec); buildroot = rpmGenPath(spec->rootDir, spec->buildRoot, NULL); @@ -292,7 +309,7 @@ index 6dfd801c8..3dd8f0246 100644 if (rpmExpandNumeric("%{?_debuginfo_subpackages}")) { maindbg = findDebuginfoPackage(spec); if (maindbg) { -@@ -3214,6 +3365,7 @@ exit: +@@ -3214,6 +3375,7 @@ exit: check_fileList = freeStringBuf(check_fileList); _free(buildroot); _free(uniquearch); diff --git a/rpm.spec b/rpm.spec index e658f88..59d5562 100644 --- a/rpm.spec +++ b/rpm.spec @@ -21,6 +21,7 @@ Patch11: bugfix-rpm-4.14.2-wait-once-get-rpmlock-fail.patch Patch12: Use-common-error-logic-regardless-of-setexecfilecon-.patch Patch13: Generate-digest-lists.patch Patch14: Add-digest-list-plugin.patch +Patch15: Don-t-add-dist-to-release-if-it-is-already-there.patch BuildRequires: gcc autoconf automake libtool make gawk popt-devel openssl-devel readline-devel libdb-devel BuildRequires: zlib-devel libzstd-devel xz-devel bzip2-devel libarchive-devel ima-evm-utils-devel From d85b3deb27873ae52eb3da99260075d88a294d79 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Sun, 26 Jul 2020 15:09:01 +0200 Subject: [PATCH 4/7] Replace security.evm with security.ima in digest list plugin --- Add-digest-list-plugin.patch | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/Add-digest-list-plugin.patch b/Add-digest-list-plugin.patch index cba3807..08f3b5b 100644 --- a/Add-digest-list-plugin.patch +++ b/Add-digest-list-plugin.patch @@ -1,4 +1,4 @@ -From c3b5c61440a40b4a159e050e25f4b3736f7d0343 Mon Sep 17 00:00:00 2001 +From 9b592f7c093d1161aad6abdc9ae00e42b72f15ba Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Wed, 26 Feb 2020 15:54:24 +0100 Subject: [PATCH 2/3] Add digest list plugin @@ -6,10 +6,10 @@ Subject: [PATCH 2/3] Add digest list plugin --- macros.in | 1 + plugins/Makefile.am | 4 + - plugins/digest_list.c | 495 ++++++++++++++++++++++++++++++++++++++++++ + plugins/digest_list.c | 490 ++++++++++++++++++++++++++++++++++++++++++ rpmio/digest.h | 1 + rpmio/rpmpgp.c | 3 + - 5 files changed, 504 insertions(+) + 5 files changed, 499 insertions(+) create mode 100644 plugins/digest_list.c diff --git a/macros.in b/macros.in @@ -38,10 +38,10 @@ index d4ef039ed..07aa3585b 100644 +plugins_LTLIBRARIES += digest_list.la diff --git a/plugins/digest_list.c b/plugins/digest_list.c new file mode 100644 -index 000000000..227ce141e +index 000000000..607987947 --- /dev/null +++ b/plugins/digest_list.c -@@ -0,0 +1,495 @@ +@@ -0,0 +1,490 @@ +#include "system.h" +#include "errno.h" + @@ -493,17 +493,12 @@ index 000000000..227ce141e + upload_digest_list(path, rpmteType(te), digest_list_signed); + + if (rpmteType(te) == TR_REMOVED) { -+ if (!digest_list_signed) { -+ unlink(path); -+ goto out; -+ } -+ -+ ret = lremovexattr(path, XATTR_NAME_EVM); ++ ret = lremovexattr(path, XATTR_NAME_IMA); + if (ret < 0) + rpmlog(RPMLOG_ERR, "digest_list: cannot remove " -+ "security.evm from '%s'\n", path); ++ "security.ima from '%s'\n", path); + else -+ rpmlog(RPMLOG_DEBUG, "digest_list: security.evm " ++ rpmlog(RPMLOG_DEBUG, "digest_list: security.ima " + "successfully removed from '%s'\n", path); + } +out: From aca04b8503675f666148f6a5eca611cf34d80ba9 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Sun, 26 Jul 2020 23:29:09 +0200 Subject: [PATCH 5/7] Add Don-t-add-dist-to-release-if-it-is-already-there.patch --- ...st-to-release-if-it-is-already-there.patch | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Don-t-add-dist-to-release-if-it-is-already-there.patch diff --git a/Don-t-add-dist-to-release-if-it-is-already-there.patch b/Don-t-add-dist-to-release-if-it-is-already-there.patch new file mode 100644 index 0000000..11bff23 --- /dev/null +++ b/Don-t-add-dist-to-release-if-it-is-already-there.patch @@ -0,0 +1,26 @@ +From 90b01a63c7c3312c25d2c3b74508a98b51e703fa Mon Sep 17 00:00:00 2001 +From: Roberto Sassu +Date: Wed, 22 Jul 2020 17:24:58 +0200 +Subject: [PATCH 3/3] Don't add dist to release if it is already there + +--- + build/parsePreamble.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/build/parsePreamble.c b/build/parsePreamble.c +index 147059bb5..c3d898b4c 100644 +--- a/build/parsePreamble.c ++++ b/build/parsePreamble.c +@@ -810,7 +810,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, WHITELIST_VERREL)) +-- +2.27.GIT + From 4c6fa874b6aadb42ce31004c6d0b6fcc67e3010f Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Sun, 26 Jul 2020 23:29:14 +0200 Subject: [PATCH 6/7] Don't process parser digest list if it is not signed --- Add-digest-list-plugin.patch | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Add-digest-list-plugin.patch b/Add-digest-list-plugin.patch index 08f3b5b..16d725d 100644 --- a/Add-digest-list-plugin.patch +++ b/Add-digest-list-plugin.patch @@ -1,4 +1,4 @@ -From 9b592f7c093d1161aad6abdc9ae00e42b72f15ba Mon Sep 17 00:00:00 2001 +From 7b446e502dc35d02ede0cde4499878e43ec498d9 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Wed, 26 Feb 2020 15:54:24 +0100 Subject: [PATCH 2/3] Add digest list plugin @@ -6,10 +6,10 @@ Subject: [PATCH 2/3] Add digest list plugin --- macros.in | 1 + plugins/Makefile.am | 4 + - plugins/digest_list.c | 490 ++++++++++++++++++++++++++++++++++++++++++ + plugins/digest_list.c | 493 ++++++++++++++++++++++++++++++++++++++++++ rpmio/digest.h | 1 + rpmio/rpmpgp.c | 3 + - 5 files changed, 499 insertions(+) + 5 files changed, 502 insertions(+) create mode 100644 plugins/digest_list.c diff --git a/macros.in b/macros.in @@ -38,10 +38,10 @@ index d4ef039ed..07aa3585b 100644 +plugins_LTLIBRARIES += digest_list.la diff --git a/plugins/digest_list.c b/plugins/digest_list.c new file mode 100644 -index 000000000..607987947 +index 000000000..465f95997 --- /dev/null +++ b/plugins/digest_list.c -@@ -0,0 +1,490 @@ +@@ -0,0 +1,493 @@ +#include "system.h" +#include "errno.h" + @@ -441,6 +441,9 @@ index 000000000..607987947 + if (!stat(path_sig, &st)) + digest_list_signed = 1; + ++ if (parser && !digest_list_signed) ++ goto out; ++ + if (parser) + snprintf(path, PATH_MAX, "%s/0-parser_list-compact-libexec", + DIGEST_LIST_DEFAULT_PATH); From 4b81801d7ee98c6b10a13429adeb2a41bdd3cf11 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Tue, 28 Jul 2020 23:53:47 +0200 Subject: [PATCH 7/7] Remove old rpm digest list --- Add-digest-list-plugin.patch | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Add-digest-list-plugin.patch b/Add-digest-list-plugin.patch index 16d725d..f79c1fe 100644 --- a/Add-digest-list-plugin.patch +++ b/Add-digest-list-plugin.patch @@ -1,4 +1,4 @@ -From 7b446e502dc35d02ede0cde4499878e43ec498d9 Mon Sep 17 00:00:00 2001 +From e49074a4e4bd0699d2c4a5bb3a0dc5ca45e19e12 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Wed, 26 Feb 2020 15:54:24 +0100 Subject: [PATCH 2/3] Add digest list plugin @@ -6,10 +6,10 @@ Subject: [PATCH 2/3] Add digest list plugin --- macros.in | 1 + plugins/Makefile.am | 4 + - plugins/digest_list.c | 493 ++++++++++++++++++++++++++++++++++++++++++ + plugins/digest_list.c | 498 ++++++++++++++++++++++++++++++++++++++++++ rpmio/digest.h | 1 + rpmio/rpmpgp.c | 3 + - 5 files changed, 502 insertions(+) + 5 files changed, 507 insertions(+) create mode 100644 plugins/digest_list.c diff --git a/macros.in b/macros.in @@ -38,10 +38,10 @@ index d4ef039ed..07aa3585b 100644 +plugins_LTLIBRARIES += digest_list.la diff --git a/plugins/digest_list.c b/plugins/digest_list.c new file mode 100644 -index 000000000..465f95997 +index 000000000..beb397309 --- /dev/null +++ b/plugins/digest_list.c -@@ -0,0 +1,493 @@ +@@ -0,0 +1,498 @@ +#include "system.h" +#include "errno.h" + @@ -496,6 +496,11 @@ index 000000000..465f95997 + upload_digest_list(path, rpmteType(te), digest_list_signed); + + if (rpmteType(te) == TR_REMOVED) { ++ if (!digest_list_signed) { ++ unlink(path); ++ goto out; ++ } ++ + ret = lremovexattr(path, XATTR_NAME_IMA); + if (ret < 0) + rpmlog(RPMLOG_ERR, "digest_list: cannot remove "