diff --git a/Add-digest-list-plugin.patch b/Add-digest-list-plugin.patch index 01c6a66..5ae4b45 100644 --- a/Add-digest-list-plugin.patch +++ b/Add-digest-list-plugin.patch @@ -1,19 +1,20 @@ -From bc3ce3b2cb903ce0f2dca39964f11c4e79256a35 Mon Sep 17 00:00:00 2001 +From 3b2fb7d5a40d25c3295e02eb3695a45189342369 Mon Sep 17 00:00:00 2001 From: zhoushuiqing Date: Fri, 16 Jun 2023 11:21:37 +0800 Subject: [PATCH] Add-digest-list-plugin +Signed-off-by: Huaxin Lu --- - plugins/digest_list.c | 670 ++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 670 insertions(+) + plugins/digest_list.c | 680 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 680 insertions(+) create mode 100644 plugins/digest_list.c diff --git a/plugins/digest_list.c b/plugins/digest_list.c new file mode 100644 -index 0000000..70cae82 +index 0000000..715b8d6 --- /dev/null +++ b/plugins/digest_list.c -@@ -0,0 +1,670 @@ +@@ -0,0 +1,680 @@ +/* + * Copyright (C) 2020-2021 Huawei Technologies Duesseldorf GmbH + * @@ -114,22 +115,11 @@ index 0000000..70cae82 + 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 " @@ -137,24 +127,39 @@ index 0000000..70cae82 + 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; + } + @@ -163,7 +168,7 @@ index 0000000..70cae82 + if (stat(RPM_PARSER, &st) == -1) { + rpmlog(RPMLOG_DEBUG, "digest_list: %s not found, " + "not uploading digest list\n", RPM_PARSER); -+ return 0; ++ return RPMRC_OK; + } + + if ((pid = fork()) == 0) { @@ -176,12 +181,13 @@ index 0000000..70cae82 + 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; + } @@ -205,12 +211,11 @@ index 0000000..70cae82 +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"); @@ -221,7 +226,6 @@ index 0000000..70cae82 + + written = Fwrite(rpm_header_magic, sizeof(uint8_t), + sizeof(rpm_header_magic), fd); -+ + if (written != sizeof(rpm_header_magic)) { + ret = -EIO; + goto out; @@ -239,20 +243,18 @@ index 0000000..70cae82 + +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; @@ -323,22 +325,16 @@ index 0000000..70cae82 + 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; @@ -349,25 +345,42 @@ index 0000000..70cae82 + 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); @@ -375,27 +388,28 @@ index 0000000..70cae82 + 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; +} + @@ -483,11 +497,17 @@ index 0000000..70cae82 + 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", @@ -498,8 +518,10 @@ index 0000000..70cae82 + 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 (!digest_list_signed && check_append_signature(path)) { + digest_list_signed = 1; @@ -564,17 +586,6 @@ index 0000000..70cae82 + unlink(path); + goto out; + } -+ -+ if (digest_list_signed_append) -+ 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); @@ -685,5 +696,5 @@ index 0000000..70cae82 + .fsm_file_post = digest_list_file_post, +}; -- -2.33.0 +2.46.0 diff --git a/rpm.spec b/rpm.spec index a3dcaac..831ed89 100644 --- a/rpm.spec +++ b/rpm.spec @@ -1,6 +1,6 @@ Name: rpm Version: 4.18.2 -Release: 8 +Release: 9 Summary: RPM Package Manager License: GPLv2+ URL: http://www.rpm.org/ @@ -337,6 +337,9 @@ make clean %exclude %{_mandir}/man8/rpmspec.8.gz %changelog +* Fri Aug 16 2024 luhuaxin - 4.18.2-9 +- IMA digest list plugin support signature within IMA header + * Wed Jul 24 2024 gengqihu - 4.18.2-8 - Backport some patches from upstream