From 827d222f0289606b1d1bc466af177a445009d752 Mon Sep 17 00:00:00 2001 From: Huaxin Lu Date: Mon, 1 Jul 2024 17:41:03 +0800 Subject: [PATCH] IMA digest list plugin support signature within IMA header --- Add-digest-list-plugin.patch | 389 ++++++++++++------ Add-license-to-digest_list.c.patch | 34 -- Check-rpm-parser.patch | 29 -- Fix-digest_list_counter.patch | 81 ---- ...st-from-the-kernel-during-package-re.patch | 106 ----- ...ss_digest_list-after-files-are-added.patch | 115 ------ ...e-ima-xattr-of-parser-when-upgrading.patch | 35 -- fix-lsetxattr-error-in-container.patch | 64 --- rpm.spec | 28 +- 9 files changed, 286 insertions(+), 595 deletions(-) delete mode 100644 Add-license-to-digest_list.c.patch delete mode 100644 Check-rpm-parser.patch delete mode 100644 Fix-digest_list_counter.patch delete mode 100644 Remove-digest-list-from-the-kernel-during-package-re.patch delete mode 100644 call-process_digest_list-after-files-are-added.patch delete mode 100644 dont-remove-ima-xattr-of-parser-when-upgrading.patch delete mode 100644 fix-lsetxattr-error-in-container.patch diff --git a/Add-digest-list-plugin.patch b/Add-digest-list-plugin.patch index 2256824..b579fee 100644 --- a/Add-digest-list-plugin.patch +++ b/Add-digest-list-plugin.patch @@ -1,22 +1,56 @@ -From e49074a4e4bd0699d2c4a5bb3a0dc5ca45e19e12 Mon Sep 17 00:00:00 2001 +From a73dd3e60daf96ee2519495bce2c7d62134e582f 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 +Subject: [PATCH] Add digest list plugin +Add RPM plugin for IMA digest list uploading and removing. + +v1: +call process_digest_list after files are added + +v2: +fix lsetxattr error in container +The digest list plugin in rpm will set security.ima xattr to IMA digest lists +when installing or updating an rpm package. However, in a container without +CAP_SYS_ADMIN, we'll get error messages when calling lsetxattr. + +v3: +Add license to digest_list.c + +v4: +Check rpm parser + +v5: +fix lsetxattr error in container +The digest list plugin in rpm will set security.ima xattr to IMA digest lists +when installing or updating an rpm package. However, in a container without +CAP_SYS_ADMIN, we'll get error messages when calling lsetxattr. +This patch is to skip lsetxattr when CAP_SYS_ADMIN is missing. + +v6: +call process_digest_list after files are added + +v7: +dont remove ima xattr of parser when upgrading + +v8: +support add the signature within a IMA header + +Signed-off-by: Huaxin Lu --- macros.in | 1 + plugins/Makefile.am | 4 + - plugins/digest_list.c | 498 ++++++++++++++++++++++++++++++++++++++++++ + plugins/digest_list.c | 624 ++++++++++++++++++++++++++++++++++++++++++ rpmio/digest.h | 1 + rpmio/rpmpgp.c | 3 + - 5 files changed, 507 insertions(+) + 5 files changed, 633 insertions(+) create mode 100644 plugins/digest_list.c diff --git a/macros.in b/macros.in -index 402749362..8619c1323 100644 +index 4531fcb..643b02b 100644 --- a/macros.in +++ b/macros.in -@@ -1184,6 +1184,7 @@ package or when debugging this package.\ +@@ -1150,6 +1150,7 @@ package or when debugging this package.\ %__transaction_prioreset %{__plugindir}/prioreset.so %__transaction_audit %{__plugindir}/audit.so %__transaction_dbus_announce %{__plugindir}/dbus_announce.so @@ -25,10 +59,10 @@ index 402749362..8619c1323 100644 #------------------------------------------------------------------------------ # Macros for further automated spec %setup and patch application diff --git a/plugins/Makefile.am b/plugins/Makefile.am -index d4ef039ed..07aa3585b 100644 +index 3a929d0..fd9be81 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am -@@ -48,3 +48,7 @@ audit_la_sources = audit.c +@@ -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 @@ -38,10 +72,24 @@ 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..beb397309 +index 0000000..c1864c7 --- /dev/null +++ b/plugins/digest_list.c -@@ -0,0 +1,499 @@ +@@ -0,0 +1,624 @@ ++/* ++ * Copyright (C) 2020-2021 Huawei Technologies Duesseldorf GmbH ++ * ++ * Author: Roberto Sassu ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation, version 2 of the ++ * License. ++ * ++ * File: digest_list.c ++ * Plugin to load digest lists in the Linux kernel. ++ */ ++ +#include "system.h" +#include "errno.h" + @@ -57,6 +105,7 @@ index 000000000..beb397309 +#include +#include +#include ++#include +#include +#include +#include @@ -70,9 +119,6 @@ index 000000000..beb397309 +#define DIGEST_LIST_DEFAULT_PATH "/etc/ima/digest_lists" +#define RPM_PARSER "/usr/libexec/rpm_parser" + -+#define DIGEST_LIST_OP_ADD 0 -+#define DIGEST_LIST_OP_DEL 1 -+ +enum hash_algo { + HASH_ALGO_MD4, + HASH_ALGO_MD5, @@ -130,22 +176,11 @@ index 000000000..beb397309 + uint8_t sig[0]; /* signature payload */ +} __attribute__((packed)); + -+static int upload_digest_list(char *path, int type, int digest_list_signed) ++static int digest_list_count_is_zero(void) +{ -+ size_t size; -+ char buf[21]; -+ const char *ima_path = DIGEST_LIST_DATA_PATH; -+ struct stat st; -+ pid_t pid; -+ int ret = 0, fd; ++ int fd = 0, ret = 0; ++ char first = 0; + -+ 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) { + rpmlog(RPMLOG_ERR, "digest_list: could not open IMA interface " @@ -153,29 +188,50 @@ index 000000000..beb397309 + return -EACCES; + } + -+ ret = read(fd, buf, sizeof(buf)); -+ close(fd); -+ ++ ret = read(fd, &first, 1); + if (ret <= 0) { + rpmlog(RPMLOG_ERR, "digest_list: could not read from IMA " + "interface '%s': %s\n", DIGEST_LIST_COUNT, + strerror(errno)); ++ close(fd); + return -EACCES; + } + -+ /* Last character is newline */ -+ buf[ret - 1] = '\0'; ++ close(fd); ++ return (first == '\0'); ++} + -+ rpmlog(RPMLOG_DEBUG, "digest_list: digests count %s\n", buf); ++static int upload_digest_list(char *path, int type, int digest_list_signed) ++{ ++ int ret = 0, fd = 0; ++ pid_t pid = 0; ++ size_t size = 0; ++ struct stat st; ++ const char *ima_path = NULL; + -+ if (*buf == '0') { -+ rpmlog(RPMLOG_DEBUG, "digest_list: not uploading '%s' to IMA " -+ "interface '%s'\n", path, ima_path); ++ ima_path = (type == TR_REMOVED) ? DIGEST_LIST_DATA_DEL_PATH : ++ DIGEST_LIST_DATA_PATH; ++ if (stat(ima_path, &st) == -1) { ++ rpmlog(RPMLOG_DEBUG, "digest_list: '%s' interface " ++ "not exist\n", ima_path); ++ return RPMRC_OK; ++ } ++ ++ /* First determine if kernel interface can accept new digest lists */ ++ if (digest_list_count_is_zero()) { ++ rpmlog(RPMLOG_DEBUG, "digest_list: the count is 0, not " ++ "upload '%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 (stat(RPM_PARSER, &st) == -1) { ++ rpmlog(RPMLOG_DEBUG, "digest_list: %s not found, " ++ "not uploading digest list\n", RPM_PARSER); ++ return RPMRC_OK; ++ } ++ + if ((pid = fork()) == 0) { + execlp(RPM_PARSER, RPM_PARSER, (type == TR_ADDED) ? + "add" : "del", path, NULL); @@ -186,12 +242,13 @@ index 000000000..beb397309 + if (ret != 0) + rpmlog(RPMLOG_ERR, "digest_list: %s returned %d\n", + RPM_PARSER, ret); -+ return 0; ++ return RPMRC_OK; + } + ++ /* If the digest list is signed, write path to the IMA interface */ + fd = open(ima_path, O_WRONLY); + if (fd < 0) { -+ rpmlog(RPMLOG_ERR, "digest_list: could not open IMA interface " ++ rpmlog(RPMLOG_ERR, "digest_list: rcould not open IMA interface " + "'%s': %s\n", ima_path, strerror(errno)); + return -EACCES; + } @@ -215,12 +272,11 @@ index 000000000..beb397309 +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; ++ ssize_t written = 0; ++ Header rpm = rpmteHeader(te); ++ rpmtd immutable = rpmtdNew(); + -+ immutable = rpmtdNew(); + headerGet(rpm, RPMTAG_HEADERIMMUTABLE, immutable, 0); + + fd = Fopen(path, "w.ufdio"); @@ -231,7 +287,6 @@ index 000000000..beb397309 + + written = Fwrite(rpm_header_magic, sizeof(uint8_t), + sizeof(rpm_header_magic), fd); -+ + if (written != sizeof(rpm_header_magic)) { + ret = -EIO; + goto out; @@ -249,20 +304,18 @@ index 000000000..beb397309 + +static int write_rpm_digest_list_ima_xattr(rpmte te, char *path) +{ -+ rpmtd signature; -+ ssize_t written; ++ FD_t fd; ++ ssize_t written = 0; ++ int ret = 0, sig_size = 0, sig_size_rounded = 0; + 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; -+ int ret = 0, sig_size, sig_size_rounded; ++ rpmtd signature = rpmtdNew(); + -+ signature = rpmtdNew(); + headerGet(rpm, RPMTAG_RSAHEADER, signature, 0); + ret = pgpPrtParams(signature->data, signature->count, + PGPTAG_SIGNATURE, &sigp); -+ + if (ret) { + ret = -ENOENT; + goto out; @@ -333,22 +386,16 @@ index 000000000..beb397309 + return ret; +} + -+static int write_digest_list_ima_xattr(rpmte te, char *path, char *path_sig) ++static int fill_pgp_signature_header(rpmte te, struct signature_v2_hdr *sig_hdr) +{ -+ rpmtd signature; -+ uint8_t sig[2048] = { 0 }; ++ int ret = 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; ++ rpmtd signature = rpmtdNew(); + -+ signature = rpmtdNew(); + headerGet(rpm, RPMTAG_RSAHEADER, signature, 0); + ret = pgpPrtParams(signature->data, signature->count, + PGPTAG_SIGNATURE, &sigp); -+ + if (ret) { + ret = -ENOENT; + goto out; @@ -359,25 +406,42 @@ index 000000000..beb397309 + sig_hdr->hash_algo = HASH_ALGO_SHA256; + memcpy((void *)&sig_hdr->keyid, sigp->signid + sizeof(uint32_t), + sizeof(uint32_t)); ++out: ++ pgpDigParamsFree(sigp); ++ rpmtdFree(signature); ++ return ret; ++} + -+ if (stat(path_sig, &st) == -1) { -+ ret = -EACCES; -+ goto out; ++static int write_digest_list_ima_xattr(rpmte te, char *path, char *path_sig) ++{ ++ FD_t fd; ++ struct stat st; ++ int ret = 0, sig_size, hdr_exist; ++ uint8_t sig[2048] = { 0 }; ++ struct signature_v2_hdr *sig_hdr = (struct signature_v2_hdr *)sig; ++ ++ if (stat(path_sig, &st) == -1) ++ return -EACCES; ++ ++ /* Check if the signature has already included a header */ ++ hdr_exist = (sig_size - sizeof(sig_hdr) % 128) == 0 ? 0 : 1; ++ if (!hdr_exist) { ++ ret = fill_pgp_signature_header(te, sig_hdr); ++ if (ret < 0) ++ return ret; + } + + 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; ++ return -E2BIG; + } + + 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; ++ return -EACCES; + } + + sig_size = Fread(sig_hdr->sig, sizeof(uint8_t), st.st_size, fd); @@ -385,36 +449,42 @@ index 000000000..beb397309 + rpmlog(RPMLOG_ERR, "digest_list: could not read '%s': %s\n", + path_sig, strerror(errno)); + Fclose(fd); -+ ret = -EIO; -+ goto out; ++ return -EIO; + } + + sig_hdr->sig_size = __cpu_to_be16(sig_size); -+ ++ Fclose(fd); + 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); ++ /* The signature may include the header */ ++ if (hdr_exist) ++ ret = lsetxattr(path, XATTR_NAME_IMA, sig_hdr->sig, sig_size, 0); ++ else ++ 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; +} + -+static int process_digest_list(rpmte te, int parser) ++static int process_digest_list(rpmte te, int parser, int pre) +{ + char *path = NULL, *path_sig = NULL; + int digest_list_signed = 0; + struct stat st; + ssize_t size; ++ int type = rpmteType(te); ++ struct __user_cap_header_struct cap_header_data; ++ cap_user_header_t cap_header = &cap_header_data; ++ struct __user_cap_data_struct cap_data_data; ++ cap_user_data_t cap_data = &cap_data_data; + rpmRC ret = RPMRC_OK; + + path = malloc(PATH_MAX); @@ -439,11 +509,17 @@ index 000000000..beb397309 + 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; ++ rpmlog(RPMLOG_DEBUG, "digest_list: digest_list_signed = 1\n"); ++ } else { ++ rpmlog(RPMLOG_DEBUG, "digest_list: digest_list_signed = 0\n"); ++ } + -+ if (parser && !digest_list_signed) ++ if (parser && !digest_list_signed) { ++ rpmlog(RPMLOG_DEBUG, "digest_list: parser has to be signed!"); + goto out; ++ } + + if (parser) + snprintf(path, PATH_MAX, "%s/0-parser_list-compact-libexec", @@ -454,8 +530,10 @@ index 000000000..beb397309 + DIGEST_LIST_DEFAULT_PATH, rpmteN(te), rpmteV(te), + rpmteR(te), rpmteA(te)); + -+ if (stat(path, &st) == -1) ++ if (stat(path, &st) == -1) { ++ rpmlog(RPMLOG_DEBUG, "digest_list: failed to find digest list file path!"); + goto out; ++ } + + if (!parser && !digest_list_signed) + snprintf(path, PATH_MAX, "%s/0-metadata_list-rpm-%s-%s-%s.%s", @@ -464,15 +542,7 @@ index 000000000..beb397309 + + 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) || -+ (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 (type == TR_ADDED && !pre && size < 0) { + if (!digest_list_signed) { + /* Write RPM header to the disk */ + ret = write_rpm_digest_list(te, path); @@ -480,7 +550,21 @@ index 000000000..beb397309 + ret = RPMRC_FAIL; + goto out; + } ++ } + ++ /* don't call lsetxattr without CAP_SYS_ADMIN */ ++ cap_header->pid = getpid(); ++ cap_header->version = _LINUX_CAPABILITY_VERSION_1; ++ if (capget(cap_header, cap_data) < 0) { ++ ret = -ENOENT; ++ goto out; ++ } ++ if (!(cap_data->effective & CAP_TO_MASK(CAP_SYS_ADMIN))) { ++ ret = -EPERM; ++ goto out; ++ } ++ ++ if (!digest_list_signed) { + /* Write RPM header sig to security.ima */ + ret = write_rpm_digest_list_ima_xattr(te, path); + } else { @@ -491,24 +575,22 @@ index 000000000..beb397309 + ret = RPMRC_FAIL; + goto out; + } ++ } else if (type == TR_ADDED && pre) { ++ if (size < 0) ++ goto out; ++ ++ /* rpm is overwriting the digest list, remove from the kernel */ ++ type = TR_REMOVED; + } + + /* Upload digest list to securityfs */ -+ upload_digest_list(path, rpmteType(te), digest_list_signed); ++ upload_digest_list(path, type, digest_list_signed); + -+ if (rpmteType(te) == TR_REMOVED) { ++ if (type == 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 " -+ "security.ima from '%s'\n", path); -+ else -+ rpmlog(RPMLOG_DEBUG, "digest_list: security.ima " -+ "successfully removed from '%s'\n", path); + } +out: + free(path); @@ -516,36 +598,113 @@ index 000000000..beb397309 + return ret; +} + ++rpmte cur_te; ++int digest_list_counter; ++ +static rpmRC digest_list_psm_pre(rpmPlugin plugin, rpmte te) +{ -+ process_digest_list(te, 0); -+ if (!strcmp(rpmteN(te), "digest-list-tools")) -+ process_digest_list(te, 1); ++ Header rpm = rpmteHeader(te); ++ rpmtd dirnames, dirindexes; ++ int i = -1; ++ ++ digest_list_counter = 0; ++ ++ dirnames = rpmtdNew(); ++ headerGet(rpm, RPMTAG_DIRNAMES, dirnames, 0); ++ ++ while ((i = rpmtdNext(dirnames)) >= 0) { ++ char *dirname = (char *) rpmtdGetString(dirnames); ++ ++ if (!strncmp(dirname, DIGEST_LIST_DEFAULT_PATH, ++ sizeof(DIGEST_LIST_DEFAULT_PATH) - 1) && ++ dirname[sizeof(DIGEST_LIST_DEFAULT_PATH) - 1] == '/') ++ break; ++ } ++ ++ rpmtdFree(dirnames); ++ ++ if (i == -1) ++ return RPMRC_OK; ++ ++ dirindexes = rpmtdNew(); ++ headerGet(rpm, RPMTAG_DIRINDEXES, dirindexes, 0); ++ while (rpmtdNext(dirindexes) >= 0) ++ if (rpmtdGetNumber(dirindexes) == i) ++ digest_list_counter++; ++ ++ rpmtdFree(dirindexes); ++ ++ cur_te = te; ++ return RPMRC_OK; ++} ++ ++static rpmRC digest_list_file_common(rpmPlugin plugin, rpmfi fi, ++ const char* path, mode_t file_mode, ++ rpmFsmOp op, int pre, int res) ++{ ++ rpmFileAction action = XFO_ACTION(op); ++ ++ if (!digest_list_counter) ++ return RPMRC_OK; ++ ++ if (!cur_te) ++ return RPMRC_OK; ++ ++ if (!pre && res != RPMRC_OK) ++ return res; ++ ++ if (!pre && rpmteType(cur_te) != TR_ADDED) ++ return RPMRC_OK; ++ ++ if (pre && action == FA_SKIP) ++ return RPMRC_OK; ++ ++ if (strncmp(path, DIGEST_LIST_DEFAULT_PATH, ++ sizeof(DIGEST_LIST_DEFAULT_PATH) - 1) || ++ path[sizeof(DIGEST_LIST_DEFAULT_PATH) - 1] != '/') ++ return RPMRC_OK; ++ ++ if (!pre && --digest_list_counter) ++ return RPMRC_OK; ++ ++ rpmlog(RPMLOG_DEBUG, "process ima digest, pre: %d, action: %d, teType: %d\n", ++ pre, action, rpmteType(cur_te)); ++ process_digest_list(cur_te, 0, pre); ++ if (!strcmp(rpmteN(cur_te), "digest-list-tools")) { ++ if (pre && rpmteType(cur_te) == TR_REMOVED) ++ return RPMRC_OK; ++ ++ rpmlog(RPMLOG_DEBUG, "process parser digest\n"); ++ process_digest_list(cur_te, 1, pre); ++ } + + return RPMRC_OK; +} + -+static rpmRC digest_list_psm_post(rpmPlugin plugin, rpmte te, int res) ++static rpmRC digest_list_file_pre(rpmPlugin plugin, rpmfi fi, ++ const char* path, mode_t file_mode, ++ rpmFsmOp op) +{ -+ if (res != RPMRC_OK) -+ return RPMRC_OK; ++ return digest_list_file_common(plugin, fi, path, file_mode, op, 1, 0); ++} + -+ process_digest_list(te, 0); -+ if (!strcmp(rpmteN(te), "digest-list-tools")) -+ process_digest_list(te, 1); -+ -+ return RPMRC_OK; ++static rpmRC digest_list_file_post(rpmPlugin plugin, rpmfi fi, ++ const char* path, mode_t file_mode, ++ rpmFsmOp op, int res) ++{ ++ return digest_list_file_common(plugin, fi, path, file_mode, op, 0, res); +} + +struct rpmPluginHooks_s digest_list_hooks = { + .psm_pre = digest_list_psm_pre, -+ .psm_post = digest_list_psm_post, ++ .fsm_file_pre = digest_list_file_pre, ++ .fsm_file_post = digest_list_file_post, +}; diff --git a/rpmio/digest.h b/rpmio/digest.h -index 9e0cde3b9..01ca10d92 100644 +index ec7f339..0d11d80 100644 --- a/rpmio/digest.h +++ b/rpmio/digest.h -@@ -24,6 +24,7 @@ struct pgpDigAlg_s { +@@ -25,6 +25,7 @@ struct pgpDigAlg_s { struct pgpDigParams_s { char * userid; uint8_t * hash; @@ -554,10 +713,10 @@ index 9e0cde3b9..01ca10d92 100644 uint8_t version; /*!< version number. */ diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c -index 46cd0f31a..3c6b18b53 100644 +index d36bd62..e508062 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, +@@ -627,6 +627,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, } p = ((uint8_t *)v) + sizeof(*v); @@ -565,7 +724,7 @@ index 46cd0f31a..3c6b18b53 100644 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, +@@ -689,6 +690,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen, if (p > hend) return 1; @@ -573,7 +732,7 @@ index 46cd0f31a..3c6b18b53 100644 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, +@@ -804,6 +806,7 @@ static int pgpPrtKey(pgpTag tag, const uint8_t *h, size_t hlen, } p = ((uint8_t *)v) + sizeof(*v); @@ -582,5 +741,5 @@ index 46cd0f31a..3c6b18b53 100644 } } break; -- -2.27.GIT +2.33.0 diff --git a/Add-license-to-digest_list.c.patch b/Add-license-to-digest_list.c.patch deleted file mode 100644 index fe07b05..0000000 --- a/Add-license-to-digest_list.c.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 676cd4c0b90043b745a39b43446e42e80948c643 Mon Sep 17 00:00:00 2001 -From: Roberto Sassu -Date: Fri, 12 Mar 2021 10:57:24 +0100 -Subject: [PATCH 5/5] Add license to digest_list.c - ---- - plugins/digest_list.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/plugins/digest_list.c b/plugins/digest_list.c -index cfde5cd1d..992a7e81a 100644 ---- a/plugins/digest_list.c -+++ b/plugins/digest_list.c -@@ -1,3 +1,17 @@ -+/* -+ * Copyright (C) 2020-2021 Huawei Technologies Duesseldorf GmbH -+ * -+ * Author: Roberto Sassu -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation, version 2 of the -+ * License. -+ * -+ * File: digest_list.c -+ * Plugin to load digest lists in the Linux kernel. -+ */ -+ - #include "system.h" - #include "errno.h" - --- -2.26.2 - diff --git a/Check-rpm-parser.patch b/Check-rpm-parser.patch deleted file mode 100644 index 43052a2..0000000 --- a/Check-rpm-parser.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 18df7feaf512cf4d7548121e1f04d4e7066fb324 Mon Sep 17 00:00:00 2001 -From: Roberto Sassu -Date: Wed, 10 Mar 2021 12:23:32 +0100 -Subject: [PATCH 2/5] Check rpm parser - ---- - plugins/digest_list.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/plugins/digest_list.c b/plugins/digest_list.c -index bb778c57f..c62f8c22f 100644 ---- a/plugins/digest_list.c -+++ b/plugins/digest_list.c -@@ -131,6 +131,12 @@ static int upload_digest_list(char *path, int type, int digest_list_signed) - - /* If the digest list is not signed, execute the RPM parser */ - if (!digest_list_signed) { -+ if (stat(RPM_PARSER, &st) == -1) { -+ rpmlog(RPMLOG_DEBUG, "digest_list: %s not found, " -+ "not uploading digest list\n", RPM_PARSER); -+ return 0; -+ } -+ - if ((pid = fork()) == 0) { - execlp(RPM_PARSER, RPM_PARSER, (type == TR_ADDED) ? - "add" : "del", path, NULL); --- -2.26.2 - diff --git a/Fix-digest_list_counter.patch b/Fix-digest_list_counter.patch deleted file mode 100644 index b9a3cd9..0000000 --- a/Fix-digest_list_counter.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 8ecd5fc6884ae165e38e16b900cc4da90665b9db Mon Sep 17 00:00:00 2001 -From: Roberto Sassu -Date: Wed, 10 Mar 2021 12:22:39 +0100 -Subject: [PATCH 1/5] Fix digest_list_counter - ---- - plugins/digest_list.c | 38 +++++++++++++++++++++++--------------- - 1 file changed, 23 insertions(+), 15 deletions(-) - -diff --git a/plugins/digest_list.c b/plugins/digest_list.c -index 2dfa21e35..bb778c57f 100644 ---- a/plugins/digest_list.c -+++ b/plugins/digest_list.c -@@ -477,8 +477,8 @@ int digest_list_counter; - static rpmRC digest_list_psm_pre(rpmPlugin plugin, rpmte te) - { - Header rpm = rpmteHeader(te); -- rpmtd dirnames; -- int i; -+ rpmtd dirnames, dirindexes; -+ int i = -1; - - digest_list_counter = 0; - -@@ -487,13 +487,26 @@ static rpmRC digest_list_psm_pre(rpmPlugin plugin, rpmte te) - - while ((i = rpmtdNext(dirnames)) >= 0) { - char *dirname = (char *) rpmtdGetString(dirnames); -+ - if (!strncmp(dirname, DIGEST_LIST_DEFAULT_PATH, -- sizeof(DIGEST_LIST_DEFAULT_PATH) - 1)) -- digest_list_counter++; -+ sizeof(DIGEST_LIST_DEFAULT_PATH) - 1) && -+ dirname[sizeof(DIGEST_LIST_DEFAULT_PATH) - 1] == '/') -+ break; - } - - rpmtdFree(dirnames); - -+ if (i == -1) -+ return RPMRC_OK; -+ -+ dirindexes = rpmtdNew(); -+ headerGet(rpm, RPMTAG_DIRINDEXES, dirindexes, 0); -+ while (rpmtdNext(dirindexes) >= 0) -+ if (rpmtdGetNumber(dirindexes) == i) -+ digest_list_counter++; -+ -+ rpmtdFree(dirindexes); -+ - cur_te = te; - return RPMRC_OK; - } -@@ -517,18 +530,13 @@ static rpmRC digest_list_file_common(rpmPlugin plugin, rpmfi fi, - (!pre && action != FA_CREATE)) - return RPMRC_OK; - -- if (digest_list_counter) { -- if (!pre) { -- if (!strncmp(path, DIGEST_LIST_DEFAULT_PATH, -- sizeof(DIGEST_LIST_DEFAULT_PATH) - 1)) -- digest_list_counter--; -- } else { -- digest_list_counter = 0; -- } -+ if (strncmp(path, DIGEST_LIST_DEFAULT_PATH, -+ sizeof(DIGEST_LIST_DEFAULT_PATH) - 1) || -+ path[sizeof(DIGEST_LIST_DEFAULT_PATH) - 1] != '/') -+ return RPMRC_OK; - -- if (digest_list_counter) -- return RPMRC_OK; -- } -+ if (!pre && --digest_list_counter) -+ return RPMRC_OK; - - process_digest_list(cur_te, 0); - if (!strcmp(rpmteN(cur_te), "digest-list-tools")) --- -2.26.2 - diff --git a/Remove-digest-list-from-the-kernel-during-package-re.patch b/Remove-digest-list-from-the-kernel-during-package-re.patch deleted file mode 100644 index 2bd6caa..0000000 --- a/Remove-digest-list-from-the-kernel-during-package-re.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 0f088c5c9efa8ab877455bc273d7e536c763f824 Mon Sep 17 00:00:00 2001 -From: Roberto Sassu -Date: Thu, 11 Mar 2021 11:59:45 +0100 -Subject: [PATCH] Remove digest list from the kernel during package - reinstallation - -Signed-off-by: luhuaxin ---- - plugins/digest_list.c | 36 +++++++++++++++++------------------- - 1 file changed, 17 insertions(+), 19 deletions(-) - -diff --git a/plugins/digest_list.c b/plugins/digest_list.c -index ca77282..63f8f1c 100644 ---- a/plugins/digest_list.c -+++ b/plugins/digest_list.c -@@ -27,9 +27,6 @@ - #define DIGEST_LIST_DEFAULT_PATH "/etc/ima/digest_lists" - #define RPM_PARSER "/usr/libexec/rpm_parser" - --#define DIGEST_LIST_OP_ADD 0 --#define DIGEST_LIST_OP_DEL 1 -- - enum hash_algo { - HASH_ALGO_MD4, - HASH_ALGO_MD5, -@@ -372,12 +369,13 @@ out: - return ret; - } - --static int process_digest_list(rpmte te, int parser) -+static int process_digest_list(rpmte te, int parser, int pre) - { - char *path = NULL, *path_sig = NULL; - int digest_list_signed = 0; - struct stat st; - ssize_t size; -+ int type = rpmteType(te); - struct __user_cap_header_struct cap_header_data; - cap_user_header_t cap_header = &cap_header_data; - struct __user_cap_data_struct cap_data_data; -@@ -431,15 +429,7 @@ static int process_digest_list(rpmte te, int parser) - - 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) || -- (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 (type == TR_ADDED && !pre && size < 0) { - if (!digest_list_signed) { - /* Write RPM header to the disk */ - ret = write_rpm_digest_list(te, path); -@@ -472,12 +462,18 @@ static int process_digest_list(rpmte te, int parser) - ret = RPMRC_FAIL; - goto out; - } -+ } else if (type == TR_ADDED && pre) { -+ if (size < 0) -+ goto out; -+ -+ /* rpm is overwriting the digest list, remove from the kernel */ -+ type = TR_REMOVED; - } - - /* Upload digest list to securityfs */ -- upload_digest_list(path, rpmteType(te), digest_list_signed); -+ upload_digest_list(path, type, digest_list_signed); - -- if (rpmteType(te) == TR_REMOVED) { -+ if (type == TR_REMOVED) { - if (!digest_list_signed) { - unlink(path); - goto out; -@@ -552,8 +548,10 @@ static rpmRC digest_list_file_common(rpmPlugin plugin, rpmfi fi, - if (!pre && res != RPMRC_OK) - return res; - -- if ((pre && action != FA_ERASE) || -- (!pre && action != FA_CREATE)) -+ if (!pre && rpmteType(cur_te) != TR_ADDED) -+ return RPMRC_OK; -+ -+ if (pre && action == FA_SKIP) - return RPMRC_OK; - - if (strncmp(path, DIGEST_LIST_DEFAULT_PATH, -@@ -564,9 +562,9 @@ static rpmRC digest_list_file_common(rpmPlugin plugin, rpmfi fi, - if (!pre && --digest_list_counter) - return RPMRC_OK; - -- process_digest_list(cur_te, 0); -+ process_digest_list(cur_te, 0, pre); - if (!strcmp(rpmteN(cur_te), "digest-list-tools")) -- process_digest_list(cur_te, 1); -+ process_digest_list(cur_te, 1, pre); - - return RPMRC_OK; - } --- -2.33.0 - diff --git a/call-process_digest_list-after-files-are-added.patch b/call-process_digest_list-after-files-are-added.patch deleted file mode 100644 index 4809b58..0000000 --- a/call-process_digest_list-after-files-are-added.patch +++ /dev/null @@ -1,115 +0,0 @@ -From 641ec5a50cb5057e02c4cfe7bd537a32fafdd665 Mon Sep 17 00:00:00 2001 -From: Roberto Sassu -Date: Mon, 26 Oct 2020 12:10:31 +0800 -Subject: [PATCH] call process_digest_list after files are added - -Signed-off-by: Anakin Zhang ---- - plugins/digest_list.c | 78 ++++++++++++++++++++++++++++++++++++++----- - 1 file changed, 69 insertions(+), 9 deletions(-) - -diff --git a/plugins/digest_list.c b/plugins/digest_list.c -index 9fcb5c4..7213b41 100644 ---- a/plugins/digest_list.c -+++ b/plugins/digest_list.c -@@ -479,28 +479,88 @@ out: - return ret; - } - -+rpmte cur_te; -+int digest_list_counter; -+ - static rpmRC digest_list_psm_pre(rpmPlugin plugin, rpmte te) - { -- process_digest_list(te, 0); -- if (!strcmp(rpmteN(te), "digest-list-tools")) -- process_digest_list(te, 1); -+ Header rpm = rpmteHeader(te); -+ rpmtd dirnames; -+ int i; -+ -+ digest_list_counter = 0; -+ -+ dirnames = rpmtdNew(); -+ headerGet(rpm, RPMTAG_DIRNAMES, dirnames, 0); -+ -+ while ((i = rpmtdNext(dirnames)) >= 0) { -+ char *dirname = (char *) rpmtdGetString(dirnames); -+ if (!strncmp(dirname, DIGEST_LIST_DEFAULT_PATH, -+ sizeof(DIGEST_LIST_DEFAULT_PATH) - 1)) -+ digest_list_counter++; -+ } - -+ rpmtdFree(dirnames); -+ -+ cur_te = te; - return RPMRC_OK; - } - --static rpmRC digest_list_psm_post(rpmPlugin plugin, rpmte te, int res) -+static rpmRC digest_list_file_common(rpmPlugin plugin, rpmfi fi, -+ const char* path, mode_t file_mode, -+ rpmFsmOp op, int pre, int res) - { -- if (res != RPMRC_OK) -+ rpmFileAction action = XFO_ACTION(op); -+ -+ if (!digest_list_counter) -+ return RPMRC_OK; -+ -+ if (!cur_te) -+ return RPMRC_OK; -+ -+ if (!pre && res != RPMRC_OK) -+ return res; -+ -+ if ((pre && action != FA_ERASE) || -+ (!pre && action != FA_CREATE)) - return RPMRC_OK; - -- process_digest_list(te, 0); -- if (!strcmp(rpmteN(te), "digest-list-tools")) -- process_digest_list(te, 1); -+ if (digest_list_counter) { -+ if (!pre) { -+ if (!strncmp(path, DIGEST_LIST_DEFAULT_PATH, -+ sizeof(DIGEST_LIST_DEFAULT_PATH) - 1)) -+ digest_list_counter--; -+ } else { -+ digest_list_counter = 0; -+ } -+ -+ if (digest_list_counter) -+ return RPMRC_OK; -+ } -+ -+ process_digest_list(cur_te, 0); -+ if (!strcmp(rpmteN(cur_te), "digest-list-tools")) -+ process_digest_list(cur_te, 1); - - return RPMRC_OK; - } - -+static rpmRC digest_list_file_pre(rpmPlugin plugin, rpmfi fi, -+ const char* path, mode_t file_mode, -+ rpmFsmOp op) -+{ -+ return digest_list_file_common(plugin, fi, path, file_mode, op, 1, 0); -+} -+ -+static rpmRC digest_list_file_post(rpmPlugin plugin, rpmfi fi, -+ const char* path, mode_t file_mode, -+ rpmFsmOp op, int res) -+{ -+ return digest_list_file_common(plugin, fi, path, file_mode, op, 0, res); -+} -+ - struct rpmPluginHooks_s digest_list_hooks = { - .psm_pre = digest_list_psm_pre, -- .psm_post = digest_list_psm_post, -+ .fsm_file_pre = digest_list_file_pre, -+ .fsm_file_post = digest_list_file_post, - }; --- -2.23.0 - diff --git a/dont-remove-ima-xattr-of-parser-when-upgrading.patch b/dont-remove-ima-xattr-of-parser-when-upgrading.patch deleted file mode 100644 index b2e0424..0000000 --- a/dont-remove-ima-xattr-of-parser-when-upgrading.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 2c27c71952ce3ac61afeabd3ef4e1d182574e905 Mon Sep 17 00:00:00 2001 -From: luhuaxin -Date: Tue, 15 Mar 2022 20:54:06 +0800 -Subject: [PATCH] dont remove ima xattr of parser when upgrading - -Signed-off-by: luhuaxin ---- - plugins/digest_list.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/plugins/digest_list.c b/plugins/digest_list.c -index 0692b5b..1d7ef92 100644 ---- a/plugins/digest_list.c -+++ b/plugins/digest_list.c -@@ -576,9 +576,16 @@ static rpmRC digest_list_file_common(rpmPlugin plugin, rpmfi fi, - if (!pre && --digest_list_counter) - return RPMRC_OK; - -+ rpmlog(RPMLOG_DEBUG, "process ima digest, pre: %d, action: %d, teType: %d\n", -+ pre, action, rpmteType(cur_te)); - process_digest_list(cur_te, 0, pre); -- if (!strcmp(rpmteN(cur_te), "digest-list-tools")) -+ if (!strcmp(rpmteN(cur_te), "digest-list-tools")) { -+ if (pre && rpmteType(cur_te) == TR_REMOVED) -+ return RPMRC_OK; -+ -+ rpmlog(RPMLOG_DEBUG, "process parser digest\n"); - process_digest_list(cur_te, 1, pre); -+ } - - return RPMRC_OK; - } --- -2.33.0 - diff --git a/fix-lsetxattr-error-in-container.patch b/fix-lsetxattr-error-in-container.patch deleted file mode 100644 index c7cd4da..0000000 --- a/fix-lsetxattr-error-in-container.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 848cad38da6c727c91f0fcb8052f9402de598737 Mon Sep 17 00:00:00 2001 -From: Zhang Tianxing -Date: Mon, 13 Sep 2021 17:32:11 +0800 -Subject: [PATCH] fix lsetxattr error in container - -The digest list plugin in rpm will set security.ima xattr to IMA digest lists -when installing or updating an rpm package. However, in a container without -CAP_SYS_ADMIN, we'll get error messages when calling lsetxattr. - -This patch is to skip lsetxattr when CAP_SYS_ADMIN is missing. - -Signed-off-by: Zhang Tianxing ---- - plugins/digest_list.c | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/plugins/digest_list.c b/plugins/digest_list.c -index 6bc9415..2d14463 100644 ---- a/plugins/digest_list.c -+++ b/plugins/digest_list.c -@@ -12,6 +12,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -370,6 +371,10 @@ static int process_digest_list(rpmte te, int parser) - int digest_list_signed = 0; - struct stat st; - ssize_t size; -+ struct __user_cap_header_struct cap_header_data; -+ cap_user_header_t cap_header = &cap_header_data; -+ struct __user_cap_data_struct cap_data_data; -+ cap_user_data_t cap_data = &cap_data_data; - rpmRC ret = RPMRC_OK; - - path = malloc(PATH_MAX); -@@ -435,7 +440,21 @@ static int process_digest_list(rpmte te, int parser) - ret = RPMRC_FAIL; - goto out; - } -+ } - -+ /* don't call lsetxattr without CAP_SYS_ADMIN */ -+ cap_header->pid = getpid(); -+ cap_header->version = _LINUX_CAPABILITY_VERSION_1; -+ if (capget(cap_header, cap_data) < 0) { -+ ret = -ENOENT; -+ goto out; -+ } -+ if (!(cap_data->effective & CAP_TO_MASK(CAP_SYS_ADMIN))) { -+ ret = -EPERM; -+ goto out; -+ } -+ -+ if (!digest_list_signed) { - /* Write RPM header sig to security.ima */ - ret = write_rpm_digest_list_ima_xattr(te, path); - } else { --- -2.27.0 - diff --git a/rpm.spec b/rpm.spec index 0a24dc3..d37c9b8 100644 --- a/rpm.spec +++ b/rpm.spec @@ -1,6 +1,6 @@ Name: rpm Version: 4.17.0 -Release: 38 +Release: 39 Summary: RPM Package Manager License: GPLv2+ URL: http://www.rpm.org/ @@ -16,20 +16,13 @@ Patch7: Generate-digest-lists.patch Patch8: Add-digest-list-plugin.patch Patch9: Don-t-add-dist-to-release-if-it-is-already-there.patch Patch10: Generate-digest-lists-before-calling-genCpioListAndH.patch -Patch11: call-process_digest_list-after-files-are-added.patch -Patch12: fix-lsetxattr-error-in-container.patch -Patch13: rpm-selinux-plugin-check-context-file-exist.patch -Patch14: get-in-use-of-ndb.patch -Patch15: still-in-use-of-python-scripts-from-old-version.patch -Patch16: Add-loongarch-architecture-support.patch -Patch17: Fix-digest_list_counter.patch -Patch18: Check-rpm-parser.patch -Patch19: Remove-digest-list-from-the-kernel-during-package-re.patch -Patch20: Add-license-to-digest_list.c.patch -Patch21: Avoid-generating-digest-lists-if-they-are-already-pa.patch -Patch22: dont-remove-ima-xattr-of-parser-when-upgrading.patch -Patch23: rpm-Add-sw64-architecture.patch -Patch24: 0001-add-default-machine-name-to-support-loongarch.patch +Patch11: rpm-selinux-plugin-check-context-file-exist.patch +Patch12: get-in-use-of-ndb.patch +Patch13: still-in-use-of-python-scripts-from-old-version.patch +Patch14: Add-loongarch-architecture-support.patch +Patch15: Avoid-generating-digest-lists-if-they-are-already-pa.patch +Patch16: rpm-Add-sw64-architecture.patch +Patch17: 0001-add-default-machine-name-to-support-loongarch.patch Patch6000: backport-Use-root-as-default-UID_0_USER-and-UID_0_GROUP.patch Patch6001: backport-Check-file-iterator-for-being-NULL-consistently.patch @@ -206,7 +199,7 @@ Obsoletes: apidocs %prep %autosetup -n %{name}-%{version} -p1 %ifnarch sw_64 -%patch23 -R -p1 +%patch16 -R -p1 %endif %build @@ -418,6 +411,9 @@ make check || (cat tests/rpmtests.log; exit 0) %{_mandir}/man1/gendiff.1* %changelog +* Fri Jul 05 2024 luhuaxin - 4.17.0-39 +- IMA digest list plugin support signature within IMA header + * Tue Jun 04 2024 Zhao Mengmeng - 4.17.0-38 - Don't segfault on missing priority tag