!360 IMA digest list plugin support signature within IMA header

From: @HuaxinLuGitee 
Reviewed-by: @xujing99 
Signed-off-by: @xujing99
This commit is contained in:
openeuler-ci-bot 2024-08-16 06:14:46 +00:00 committed by Gitee
commit 1623f2dfc1
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
2 changed files with 96 additions and 82 deletions

View File

@ -1,19 +1,20 @@
From bc3ce3b2cb903ce0f2dca39964f11c4e79256a35 Mon Sep 17 00:00:00 2001 From 3b2fb7d5a40d25c3295e02eb3695a45189342369 Mon Sep 17 00:00:00 2001
From: zhoushuiqing <zhoushuiqing2@huawei.com> From: zhoushuiqing <zhoushuiqing2@huawei.com>
Date: Fri, 16 Jun 2023 11:21:37 +0800 Date: Fri, 16 Jun 2023 11:21:37 +0800
Subject: [PATCH] Add-digest-list-plugin Subject: [PATCH] Add-digest-list-plugin
Signed-off-by: Huaxin Lu <luhuaxin1@huawei.com>
--- ---
plugins/digest_list.c | 670 ++++++++++++++++++++++++++++++++++++++++++ plugins/digest_list.c | 680 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 670 insertions(+) 1 file changed, 680 insertions(+)
create mode 100644 plugins/digest_list.c create mode 100644 plugins/digest_list.c
diff --git a/plugins/digest_list.c b/plugins/digest_list.c diff --git a/plugins/digest_list.c b/plugins/digest_list.c
new file mode 100644 new file mode 100644
index 0000000..70cae82 index 0000000..715b8d6
--- /dev/null --- /dev/null
+++ b/plugins/digest_list.c +++ b/plugins/digest_list.c
@@ -0,0 +1,670 @@ @@ -0,0 +1,680 @@
+/* +/*
+ * Copyright (C) 2020-2021 Huawei Technologies Duesseldorf GmbH + * Copyright (C) 2020-2021 Huawei Technologies Duesseldorf GmbH
+ * + *
@ -114,22 +115,11 @@ index 0000000..70cae82
+ uint8_t sig[0]; /* signature payload */ + uint8_t sig[0]; /* signature payload */
+} __attribute__((packed)); +} __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; + int fd = 0, ret = 0;
+ char buf[21]; + char first = 0;
+ 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); + fd = open(DIGEST_LIST_COUNT, O_RDONLY);
+ if (fd < 0) { + if (fd < 0) {
+ rpmlog(RPMLOG_ERR, "digest_list: could not open IMA interface " + rpmlog(RPMLOG_ERR, "digest_list: could not open IMA interface "
@ -137,24 +127,39 @@ index 0000000..70cae82
+ return -EACCES; + return -EACCES;
+ } + }
+ +
+ ret = read(fd, buf, sizeof(buf)); + ret = read(fd, &first, 1);
+ close(fd);
+
+ if (ret <= 0) { + if (ret <= 0) {
+ rpmlog(RPMLOG_ERR, "digest_list: could not read from IMA " + rpmlog(RPMLOG_ERR, "digest_list: could not read from IMA "
+ "interface '%s': %s\n", DIGEST_LIST_COUNT, + "interface '%s': %s\n", DIGEST_LIST_COUNT,
+ strerror(errno)); + strerror(errno));
+ close(fd);
+ return -EACCES; + return -EACCES;
+ } + }
+ +
+ /* Last character is newline */ + close(fd);
+ buf[ret - 1] = '\0'; + 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') { + ima_path = (type == TR_REMOVED) ? DIGEST_LIST_DATA_DEL_PATH :
+ rpmlog(RPMLOG_DEBUG, "digest_list: not uploading '%s' to IMA " + DIGEST_LIST_DATA_PATH;
+ "interface '%s'\n", path, ima_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; + return RPMRC_OK;
+ } + }
+ +
@ -163,7 +168,7 @@ index 0000000..70cae82
+ if (stat(RPM_PARSER, &st) == -1) { + if (stat(RPM_PARSER, &st) == -1) {
+ rpmlog(RPMLOG_DEBUG, "digest_list: %s not found, " + rpmlog(RPMLOG_DEBUG, "digest_list: %s not found, "
+ "not uploading digest list\n", RPM_PARSER); + "not uploading digest list\n", RPM_PARSER);
+ return 0; + return RPMRC_OK;
+ } + }
+ +
+ if ((pid = fork()) == 0) { + if ((pid = fork()) == 0) {
@ -176,12 +181,13 @@ index 0000000..70cae82
+ if (ret != 0) + if (ret != 0)
+ rpmlog(RPMLOG_ERR, "digest_list: %s returned %d\n", + rpmlog(RPMLOG_ERR, "digest_list: %s returned %d\n",
+ RPM_PARSER, ret); + 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); + fd = open(ima_path, O_WRONLY);
+ if (fd < 0) { + 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)); + "'%s': %s\n", ima_path, strerror(errno));
+ return -EACCES; + return -EACCES;
+ } + }
@ -205,12 +211,11 @@ index 0000000..70cae82
+static int write_rpm_digest_list(rpmte te, char *path) +static int write_rpm_digest_list(rpmte te, char *path)
+{ +{
+ FD_t fd; + FD_t fd;
+ ssize_t written;
+ Header rpm = rpmteHeader(te);
+ rpmtd immutable;
+ int ret = 0; + int ret = 0;
+ ssize_t written = 0;
+ Header rpm = rpmteHeader(te);
+ rpmtd immutable = rpmtdNew();
+ +
+ immutable = rpmtdNew();
+ headerGet(rpm, RPMTAG_HEADERIMMUTABLE, immutable, 0); + headerGet(rpm, RPMTAG_HEADERIMMUTABLE, immutable, 0);
+ +
+ fd = Fopen(path, "w.ufdio"); + fd = Fopen(path, "w.ufdio");
@ -221,7 +226,6 @@ index 0000000..70cae82
+ +
+ written = Fwrite(rpm_header_magic, sizeof(uint8_t), + written = Fwrite(rpm_header_magic, sizeof(uint8_t),
+ sizeof(rpm_header_magic), fd); + sizeof(rpm_header_magic), fd);
+
+ if (written != sizeof(rpm_header_magic)) { + if (written != sizeof(rpm_header_magic)) {
+ ret = -EIO; + ret = -EIO;
+ goto out; + goto out;
@ -239,20 +243,18 @@ index 0000000..70cae82
+ +
+static int write_rpm_digest_list_ima_xattr(rpmte te, char *path) +static int write_rpm_digest_list_ima_xattr(rpmte te, char *path)
+{ +{
+ rpmtd signature; + FD_t fd;
+ ssize_t written; + ssize_t written = 0;
+ int ret = 0, sig_size = 0, sig_size_rounded = 0;
+ uint8_t sig[2048] = { 0 }; + uint8_t sig[2048] = { 0 };
+ pgpDigParams sigp = NULL; + pgpDigParams sigp = NULL;
+ struct signature_v2_hdr *sig_hdr = (struct signature_v2_hdr *)sig; + struct signature_v2_hdr *sig_hdr = (struct signature_v2_hdr *)sig;
+ Header rpm = rpmteHeader(te); + Header rpm = rpmteHeader(te);
+ FD_t fd; + rpmtd signature = rpmtdNew();
+ int ret = 0, sig_size, sig_size_rounded;
+ +
+ signature = rpmtdNew();
+ headerGet(rpm, RPMTAG_RSAHEADER, signature, 0); + headerGet(rpm, RPMTAG_RSAHEADER, signature, 0);
+ ret = pgpPrtParams(signature->data, signature->count, + ret = pgpPrtParams(signature->data, signature->count,
+ PGPTAG_SIGNATURE, &sigp); + PGPTAG_SIGNATURE, &sigp);
+
+ if (ret) { + if (ret) {
+ ret = -ENOENT; + ret = -ENOENT;
+ goto out; + goto out;
@ -323,22 +325,16 @@ index 0000000..70cae82
+ return ret; + 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; + int ret = 0;
+ uint8_t sig[2048] = { 0 };
+ pgpDigParams sigp = NULL; + pgpDigParams sigp = NULL;
+ struct signature_v2_hdr *sig_hdr = (struct signature_v2_hdr *)sig;
+ Header rpm = rpmteHeader(te); + Header rpm = rpmteHeader(te);
+ FD_t fd; + rpmtd signature = rpmtdNew();
+ struct stat st;
+ int ret = 0, sig_size;
+ +
+ signature = rpmtdNew();
+ headerGet(rpm, RPMTAG_RSAHEADER, signature, 0); + headerGet(rpm, RPMTAG_RSAHEADER, signature, 0);
+ ret = pgpPrtParams(signature->data, signature->count, + ret = pgpPrtParams(signature->data, signature->count,
+ PGPTAG_SIGNATURE, &sigp); + PGPTAG_SIGNATURE, &sigp);
+
+ if (ret) { + if (ret) {
+ ret = -ENOENT; + ret = -ENOENT;
+ goto out; + goto out;
@ -349,25 +345,42 @@ index 0000000..70cae82
+ sig_hdr->hash_algo = HASH_ALGO_SHA256; + sig_hdr->hash_algo = HASH_ALGO_SHA256;
+ memcpy((void *)&sig_hdr->keyid, sigp->signid + sizeof(uint32_t), + memcpy((void *)&sig_hdr->keyid, sigp->signid + sizeof(uint32_t),
+ sizeof(uint32_t)); + sizeof(uint32_t));
+out:
+ pgpDigParamsFree(sigp);
+ rpmtdFree(signature);
+ return ret;
+}
+ +
+ if (stat(path_sig, &st) == -1) { +static int write_digest_list_ima_xattr(rpmte te, char *path, char *path_sig)
+ ret = -EACCES; +{
+ goto out; + 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)) { + if (sizeof(sig_hdr) + st.st_size > sizeof(sig)) {
+ rpmlog(RPMLOG_ERR, "digest_list: signature in %s too big\n", + rpmlog(RPMLOG_ERR, "digest_list: signature in %s too big\n",
+ path); + path);
+ ret = -E2BIG; + return -E2BIG;
+ goto out;
+ } + }
+ +
+ fd = Fopen(path_sig, "r.ufdio"); + fd = Fopen(path_sig, "r.ufdio");
+ if (fd < 0) { + if (fd < 0) {
+ rpmlog(RPMLOG_ERR, "digest_list: could not open '%s': %s\n", + rpmlog(RPMLOG_ERR, "digest_list: could not open '%s': %s\n",
+ path_sig, strerror(errno)); + path_sig, strerror(errno));
+ ret = -EACCES; + return -EACCES;
+ goto out;
+ } + }
+ +
+ sig_size = Fread(sig_hdr->sig, sizeof(uint8_t), st.st_size, fd); + 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", + rpmlog(RPMLOG_ERR, "digest_list: could not read '%s': %s\n",
+ path_sig, strerror(errno)); + path_sig, strerror(errno));
+ Fclose(fd); + Fclose(fd);
+ ret = -EIO; + return -EIO;
+ goto out;
+ } + }
+ +
+ sig_hdr->sig_size = __cpu_to_be16(sig_size); + sig_hdr->sig_size = __cpu_to_be16(sig_size);
+ + Fclose(fd);
+ rpmlog(RPMLOG_DEBUG, + rpmlog(RPMLOG_DEBUG,
+ "digest_list: read signature of %d bytes from '%s'\n", + "digest_list: read signature of %d bytes from '%s'\n",
+ sig_size, path_sig); + sig_size, path_sig);
+ +
+ ret = lsetxattr(path, XATTR_NAME_IMA, + /* The signature may include the header */
+ sig, sizeof(*sig_hdr) + sig_size, 0); + 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) + if (ret < 0)
+ rpmlog(RPMLOG_ERR, "digest_list: could not apply security.ima " + rpmlog(RPMLOG_ERR, "digest_list: could not apply security.ima "
+ "on '%s': %s\n", path, strerror(errno)); + "on '%s': %s\n", path, strerror(errno));
+ else + else
+ rpmlog(RPMLOG_DEBUG, "digest_list: security.ima successfully " + rpmlog(RPMLOG_DEBUG, "digest_list: security.ima successfully "
+ "applied on '%s'\n", path); + "applied on '%s'\n", path);
+out: +
+ pgpDigParamsFree(sigp);
+ rpmtdFree(signature);
+ return ret; + return ret;
+} +}
+ +
@ -483,11 +497,17 @@ index 0000000..70cae82
+ DIGEST_LIST_DEFAULT_PATH, rpmteN(te), rpmteV(te), + DIGEST_LIST_DEFAULT_PATH, rpmteN(te), rpmteV(te),
+ rpmteR(te), rpmteA(te)); + rpmteR(te), rpmteA(te));
+ +
+ if (!stat(path_sig, &st)) + if (!stat(path_sig, &st)) {
+ digest_list_signed = 1; + 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; + goto out;
+ }
+ +
+ if (parser) + if (parser)
+ snprintf(path, PATH_MAX, "%s/0-parser_list-compact-libexec", + 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), + DIGEST_LIST_DEFAULT_PATH, rpmteN(te), rpmteV(te),
+ rpmteR(te), rpmteA(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; + goto out;
+ }
+ +
+ if (!digest_list_signed && check_append_signature(path)) { + if (!digest_list_signed && check_append_signature(path)) {
+ digest_list_signed = 1; + digest_list_signed = 1;
@ -564,17 +586,6 @@ index 0000000..70cae82
+ unlink(path); + unlink(path);
+ goto out; + 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: +out:
+ free(path); + free(path);
@ -685,5 +696,5 @@ index 0000000..70cae82
+ .fsm_file_post = digest_list_file_post, + .fsm_file_post = digest_list_file_post,
+}; +};
-- --
2.33.0 2.46.0

View File

@ -1,6 +1,6 @@
Name: rpm Name: rpm
Version: 4.18.2 Version: 4.18.2
Release: 8 Release: 9
Summary: RPM Package Manager Summary: RPM Package Manager
License: GPLv2+ License: GPLv2+
URL: http://www.rpm.org/ URL: http://www.rpm.org/
@ -337,6 +337,9 @@ make clean
%exclude %{_mandir}/man8/rpmspec.8.gz %exclude %{_mandir}/man8/rpmspec.8.gz
%changelog %changelog
* Fri Aug 16 2024 luhuaxin <luhuaxin1@huawei.com> - 4.18.2-9
- IMA digest list plugin support signature within IMA header
* Wed Jul 24 2024 gengqihu<gengqihu2@h-partners.com> - 4.18.2-8 * Wed Jul 24 2024 gengqihu<gengqihu2@h-partners.com> - 4.18.2-8
- Backport some patches from upstream - Backport some patches from upstream