Add digest list patches
This commit is contained in:
parent
3a0f15f99d
commit
8740452fb2
579
Add-digest-list-plugin.patch
Normal file
579
Add-digest-list-plugin.patch
Normal file
@ -0,0 +1,579 @@
|
|||||||
|
From fa0b33ce1ff569ab55b46cdbcc47f2da6db3fb1a Mon Sep 17 00:00:00 2001
|
||||||
|
From: Roberto Sassu <roberto.sassu@huawei.com>
|
||||||
|
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 <rpm/rpmlog.h>
|
||||||
|
+#include <rpm/rpmts.h>
|
||||||
|
+#include <rpm/header.h>
|
||||||
|
+#include <rpm/rpmfileutil.h>
|
||||||
|
+#include "lib/rpmplugin.h"
|
||||||
|
+#include <sys/stat.h>
|
||||||
|
+#include <openssl/sha.h>
|
||||||
|
+#include <sys/xattr.h>
|
||||||
|
+#include <linux/xattr.h>
|
||||||
|
+#include <asm/byteorder.h>
|
||||||
|
+#include <sys/wait.h>
|
||||||
|
+
|
||||||
|
+#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
|
||||||
|
|
||||||
306
Generate-digest-lists.patch
Normal file
306
Generate-digest-lists.patch
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
From 99d243a37d50155bc3e9b4ef8d1457a73016c9c0 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Roberto Sassu <roberto.sassu@huawei.com>
|
||||||
|
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
|
||||||
|
|
||||||
8
rpm.spec
8
rpm.spec
@ -1,6 +1,6 @@
|
|||||||
Name: rpm
|
Name: rpm
|
||||||
Version: 4.15.1
|
Version: 4.15.1
|
||||||
Release: 16
|
Release: 17
|
||||||
Summary: RPM Package Manager
|
Summary: RPM Package Manager
|
||||||
License: GPLv2+
|
License: GPLv2+
|
||||||
URL: http://www.rpm.org/
|
URL: http://www.rpm.org/
|
||||||
@ -287,6 +287,12 @@ make check || (cat tests/rpmtests.log; exit 0)
|
|||||||
%{_mandir}/man1/gendiff.1*
|
%{_mandir}/man1/gendiff.1*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Jul 14 2020 Roberto Sassu <roberto.sassu@huawei.com> - 4.15.1-17
|
||||||
|
- Type:enhancement
|
||||||
|
- ID:NA
|
||||||
|
- SUG:NA
|
||||||
|
- DESC:add support for digest lists
|
||||||
|
|
||||||
* Fri May 22 2020 openEuler Buildteam <buildteam@openeuler.org> - 4.15.1-16
|
* Fri May 22 2020 openEuler Buildteam <buildteam@openeuler.org> - 4.15.1-16
|
||||||
- Type:bugfix
|
- Type:bugfix
|
||||||
- ID:NA
|
- ID:NA
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user