public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Petr Lautrbach <lautrbach@redhat.com>
To: git-commits@fedoraproject.org
Subject: [rpms/fapolicyd] f44: fapolicyd-2.0-2
Date: Mon, 24 Aug 2026 14:46:43 GMT [thread overview]
Message-ID: <178758280312.1.12520463819164667177.rpms-fapolicyd-78f62eabb7aa@fedoraproject.org> (raw)
A new commit has been pushed.
Repo : rpms/fapolicyd
Branch : f44
Commit : 78f62eabb7aa37a50ebf10285dd8e328d777fca2
Author : Petr Lautrbach <lautrbach@redhat.com>
Date : 2026-08-13T11:00:47+02:00
Stats : +425/-24 in 5 file(s)
URL : https://src.fedoraproject.org/rpms/fapolicyd/c/78f62eabb7aa37a50ebf10285dd8e328d777fca2?branch=f44
Log:
fapolicyd-2.0-2
- Allow a couple other non-obvious javascript files into the trust db
https://github.com/linux-application-whitelisting/fapolicyd/issues/432
---
diff --git a/0003-update-changelog.patch b/0003-update-changelog.patch
deleted file mode 100644
index 65c25ae..0000000
--- a/0003-update-changelog.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-From ccf618b664230e0f5497345e6a4503e6f2c7bca9 Mon Sep 17 00:00:00 2001
-From: Steve Grubb <ausearch.1@gmail.com>
-Date: Thu, 23 Jul 2026 11:26:13 -0400
-Subject: [PATCH] update changelog
-Content-type: text/plain
-
----
- ChangeLog | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/ChangeLog b/ChangeLog
-index d230c610c956..1c3ea75a1c4e 100644
---- a/ChangeLog
-+++ b/ChangeLog
-@@ -1,4 +1,5 @@
- 2.0.1
-+- Enable large file support on 32-bit builds
-
- 2.0
- - Add decision_threads configuration to fapolicyd.conf
---
-2.55.0
-
diff --git a/0004-Allow-KDE-qml-files-into-the-trust-db.patch b/0004-Allow-KDE-qml-files-into-the-trust-db.patch
new file mode 100644
index 0000000..f9e1ebe
--- /dev/null
+++ b/0004-Allow-KDE-qml-files-into-the-trust-db.patch
@@ -0,0 +1,26 @@
+From a1fb321acd9cce76733a7a623aac62f7e8334599 Mon Sep 17 00:00:00 2001
+From: Steve Grubb <ausearch.1@gmail.com>
+Date: Sat, 8 Aug 2026 10:25:17 -0400
+Subject: [PATCH] Allow KDE qml files into the trust db
+Content-type: text/plain
+
+---
+ init/fapolicyd-filter.conf | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/init/fapolicyd-filter.conf b/init/fapolicyd-filter.conf
+index 1acddfb1ab5c..c2db6f17c1bc 100644
+--- a/init/fapolicyd-filter.conf
++++ b/init/fapolicyd-filter.conf
+@@ -43,6 +43,8 @@
+ + *.stp
+ # Javascript
+ + *.js
++ # QML - KDE's javascript-like language
++ + *.qml
+ # Java archive
+ + *.jar
+ # M4
+--
+2.55.0
+
diff --git a/0005-Allow-a-couple-other-non-obvious-javascript-files-in.patch b/0005-Allow-a-couple-other-non-obvious-javascript-files-in.patch
new file mode 100644
index 0000000..b740bde
--- /dev/null
+++ b/0005-Allow-a-couple-other-non-obvious-javascript-files-in.patch
@@ -0,0 +1,30 @@
+From fae1cc6b22f5f6ee16b7768ee9e68579843c1552 Mon Sep 17 00:00:00 2001
+From: Steve Grubb <ausearch.1@gmail.com>
+Date: Sat, 8 Aug 2026 16:41:40 -0400
+Subject: [PATCH] Allow a couple other non-obvious javascript files into the
+ trust db
+Content-type: text/plain
+
+---
+ init/fapolicyd-filter.conf | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/init/fapolicyd-filter.conf b/init/fapolicyd-filter.conf
+index c2db6f17c1bc..7c78d60df48f 100644
+--- a/init/fapolicyd-filter.conf
++++ b/init/fapolicyd-filter.conf
+@@ -45,6 +45,11 @@
+ + *.js
+ # QML - KDE's javascript-like language
+ + *.qml
++ # Polkit Javascript rules
++ + polkit-1/rules.d/*.rules
++ # GNOME Javascript applications without a file extension
++ + gnome-shell/org.gnome.*
++ + org.gnome.Characters/org.gnome.Characters
+ # Java archive
+ + *.jar
+ # M4
+--
+2.55.0
+
diff --git a/0006-Fix-32-bit-large-file-digest-truncation.patch b/0006-Fix-32-bit-large-file-digest-truncation.patch
new file mode 100644
index 0000000..6519cef
--- /dev/null
+++ b/0006-Fix-32-bit-large-file-digest-truncation.patch
@@ -0,0 +1,361 @@
+From d44f0cab26acdd2fbb17b96c1ec0d75dbe2af044 Mon Sep 17 00:00:00 2001
+From: Steve Grubb <ausearch.1@gmail.com>
+Date: Tue, 11 Aug 2026 13:20:15 -0400
+Subject: [PATCH] Fix 32-bit large-file digest truncation
+Content-type: text/plain
+
+Large-file builds use a 64-bit off_t on 32-bit systems, but get_hash_from_fd2 accepted the byte count as size_t. Files at or above 4 GiB were therefore hashed modulo 2^32 bytes, allowing trust creation and SHA or IMA fallback verification to agree on a truncated digest.
+
+Carry file sizes as off_t through the hashing API and the Debian MD5 backend. Preserve the mmap path for representable sizes, and use offset-safe pread chunks with incremental EVP hashing when the size exceeds SIZE_MAX.
+
+Add an i686-gated LMDB regression that trusts an unchanged 4 GiB file, mutates its final byte, and requires SHA verification to reject it. The RPM and Debian build/test matrices pass, and a focused ELF32 run confirmed that changing the last byte changes the digest.
+---
+ src/library/file.c | 112 +++++++++++++++++++++++++++++++---
+ src/library/file.h | 2 +-
+ src/library/md5-backend.c | 6 +-
+ src/tests/event_test.c | 6 +-
+ src/tests/md5_backend_test.c | 2 +-
+ src/tests/trustdb_lmdb_test.c | 74 ++++++++++++++++++++++
+ 6 files changed, 187 insertions(+), 15 deletions(-)
+
+diff --git a/src/library/file.c b/src/library/file.c
+index e52de152895e..627e18115716 100644
+--- a/src/library/file.c
++++ b/src/library/file.c
+@@ -31,6 +31,7 @@
+ #include <sys/stat.h>
+ #include <string.h>
+ #include <stdlib.h>
++#include <openssl/evp.h>
+ #include <openssl/sha.h>
+ #include <openssl/md5.h>
+ #include <magic.h>
+@@ -1339,15 +1340,105 @@ static const char *degenerate_hash_sha512 =
+ "47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
+ static const char *degenerate_hash_md5 =
+ "d41d8cd98f00b204e9800998ecf8427e";
+-char *get_hash_from_fd2(int fd, size_t size, file_hash_alg_t alg)
++
++/*
++ * get_evp_hash_algorithm - map a file hash algorithm to OpenSSL's EVP API.
++ * @alg: file digest algorithm requested by the caller.
++ * Returns the EVP implementation, or NULL when the algorithm is unavailable.
++ */
++static const EVP_MD *get_evp_hash_algorithm(file_hash_alg_t alg)
++{
++ switch (alg) {
++ case FILE_HASH_ALG_SHA1:
++ return EVP_sha1();
++ case FILE_HASH_ALG_SHA256:
++ return EVP_sha256();
++ case FILE_HASH_ALG_SHA512:
++ return EVP_sha512();
++ case FILE_HASH_ALG_MD5:
++#ifdef USE_DEB
++ return EVP_md5();
++#else
++ return NULL;
++#endif
++ default:
++ return NULL;
++ }
++}
++
++/*
++ * hash_fd_in_chunks - hash a file that cannot fit in one mmap length.
++ * @fd: open descriptor whose contents should be measured.
++ * @size: number of bytes to include in the digest calculation.
++ * @alg: digest algorithm to use for the measurement.
++ *
++ * pread preserves the descriptor offset while off_t keeps every chunk offset
++ * representable on 32-bit large-file builds. Returns an allocated hex digest
++ * on success, or NULL on read, allocation, or digest failure.
++ */
++static char *hash_fd_in_chunks(int fd, off_t size, file_hash_alg_t alg)
++{
++ unsigned char buf[64 * 1024];
++ unsigned char hptr[EVP_MAX_MD_SIZE];
++ const EVP_MD *md = get_evp_hash_algorithm(alg);
++ EVP_MD_CTX *ctx = NULL;
++ off_t offset = 0;
++ unsigned int hash_length = 0;
++ char *digest = NULL;
++
++ if (md == NULL)
++ return NULL;
++
++ ctx = EVP_MD_CTX_new();
++ if (ctx == NULL || EVP_DigestInit_ex(ctx, md, NULL) != 1)
++ goto out;
++
++ while (offset < size) {
++ off_t remaining = size - offset;
++ size_t requested = sizeof(buf);
++ ssize_t len;
++
++ if (remaining < (off_t)requested)
++ requested = (size_t)remaining;
++ do {
++ len = pread(fd, buf, requested, offset);
++ } while (len < 0 && errno == EINTR);
++ if (len <= 0) {
++ if (len == 0)
++ errno = EIO;
++ goto out;
++ }
++ if (EVP_DigestUpdate(ctx, buf, (size_t)len) != 1)
++ goto out;
++ offset += len;
++ }
++
++ if (EVP_DigestFinal_ex(ctx, hptr, &hash_length) != 1 ||
++ hash_length != file_hash_length(alg))
++ goto out;
++
++ digest = malloc(((size_t)hash_length * 2) + 1);
++ if (digest)
++ bytes2hex(digest, hptr, hash_length);
++out:
++ EVP_MD_CTX_free(ctx);
++ return digest;
++}
++
++char *get_hash_from_fd2(int fd, off_t size, file_hash_alg_t alg)
+ {
+ unsigned char *mapped;
+ char *digest = NULL;
++ size_t map_size;
+ size_t digest_length;
+ struct decision_timing_span timing;
+
+ decision_timing_stage_begin(DECISION_TIMING_STAGE_HASH_SHA,
+ &timing);
++ if (size < 0) {
++ decision_timing_stage_end(&timing);
++ return NULL;
++ }
+ if (size == 0) {
+ char *degenerate;
+
+@@ -1378,34 +1469,41 @@ char *get_hash_from_fd2(int fd, size_t size, file_hash_alg_t alg)
+ return NULL;
+ }
+
+- mapped = mmap(0, size, PROT_READ, MAP_SHARED|MAP_POPULATE, fd, 0);
++ if ((uintmax_t)size > SIZE_MAX) {
++ digest = hash_fd_in_chunks(fd, size, alg);
++ decision_timing_stage_end(&timing);
++ return digest;
++ }
++
++ map_size = (size_t)size;
++ mapped = mmap(0, map_size, PROT_READ, MAP_SHARED|MAP_POPULATE, fd, 0);
+ if (mapped != MAP_FAILED) {
+ unsigned char hptr[SHA512_DIGEST_LENGTH];
+ int computed = 0;
+
+ switch (alg) {
+ case FILE_HASH_ALG_SHA1:
+- SHA1(mapped, size, hptr);
++ SHA1(mapped, map_size, hptr);
+ computed = 1;
+ break;
+ case FILE_HASH_ALG_SHA256:
+- SHA256(mapped, size, hptr);
++ SHA256(mapped, map_size, hptr);
+ computed = 1;
+ break;
+ case FILE_HASH_ALG_SHA512:
+- SHA512(mapped, size, hptr);
++ SHA512(mapped, map_size, hptr);
+ computed = 1;
+ break;
+ case FILE_HASH_ALG_MD5:
+ #ifdef USE_DEB
+- MD5(mapped, size, hptr);
++ MD5(mapped, map_size, hptr);
+ computed = 1;
+ #endif
+ break;
+ default:
+ break;
+ }
+- munmap(mapped, size);
++ munmap(mapped, map_size);
+
+ if (computed) {
+ digest = malloc((digest_length * 2) + 1);
+diff --git a/src/library/file.h b/src/library/file.h
+index 167cd93587b0..a818062ee7ec 100644
+--- a/src/library/file.h
++++ b/src/library/file.h
+@@ -106,7 +106,7 @@ char *get_file_type_from_fd(int fd, const struct file_info *i, const char *path,
+ __attr_access ((__write_only__, 5, 4)) __attr_fd_arg_read (1);
+ char *bytes2hex(char *final, const unsigned char *buf, unsigned int size)
+ __attr_access ((__read_only__, 2, 3));
+-char *get_hash_from_fd2(int fd, size_t size, file_hash_alg_t alg)
++char *get_hash_from_fd2(int fd, off_t size, file_hash_alg_t alg)
+ __attr_dealloc_free __attr_fd_arg_read (1);
+ int get_ima_hash(int fd, file_hash_alg_t *alg, char *sha)
+ __attr_fd_arg (1);
+diff --git a/src/library/md5-backend.c b/src/library/md5-backend.c
+index 836606d353c1..d68a39e0414d 100644
+--- a/src/library/md5-backend.c
++++ b/src/library/md5-backend.c
+@@ -103,17 +103,17 @@ md5_backend_result_t add_file_to_backend_by_md5(const char *path,
+ return MD5_BACKEND_SKIPPED;
+ }
+
+- size_t file_size = path_stat.st_size;
++ off_t file_size = path_stat.st_size;
+ trustdb_size_t stored_size;
+
+- if (trustdb_size_from_unsigned(file_size, &stored_size)) {
++ if (trustdb_size_from_signed((intmax_t)file_size, &stored_size)) {
+ close(fd);
+ msg(LOG_ERR, "File size for %s exceeds trust DB format", path);
+ return MD5_BACKEND_FATAL;
+ }
+
+ #ifdef DEBUG
+- msg(LOG_DEBUG, "\tFile size: %zu", file_size);
++ msg(LOG_DEBUG, "\tFile size: %jd", (intmax_t)file_size);
+ #endif
+
+ char *md5_digest = get_hash_from_fd2(fd, file_size,
+diff --git a/src/tests/event_test.c b/src/tests/event_test.c
+index 34c33a9b3a68..9fc174a23095 100644
+--- a/src/tests/event_test.c
++++ b/src/tests/event_test.c
+@@ -65,7 +65,7 @@ int check_trust_database(const char *exe, const char *digest, int mode);
+ char *get_device_from_stat(unsigned int device, size_t blen, char *buf);
+ char *get_file_type_from_fd(int fd, const struct file_info *i, const char *path,
+ size_t blen, char *buf);
+-char *get_hash_from_fd2(int fd, size_t size, file_hash_alg_t alg);
++char *get_hash_from_fd2(int fd, off_t size, file_hash_alg_t alg);
+
+ struct stub_proc_record {
+ pid_t pid;
+@@ -442,12 +442,12 @@ char *get_file_type_from_fd(int fd, const struct file_info *i, const char *path,
+ /*
+ * Produce a fake digest string so new_event() can populate hash attributes.
+ */
+-char *get_hash_from_fd2(int fd, size_t size, file_hash_alg_t alg)
++char *get_hash_from_fd2(int fd, off_t size, file_hash_alg_t alg)
+ {
+ char *out = malloc(64);
+ if (out == NULL)
+ return NULL;
+- snprintf(out, 64, "hash-%d-%zu-%d", fd, (size_t)size, (int)alg);
++ snprintf(out, 64, "hash-%d-%jd-%d", fd, (intmax_t)size, (int)alg);
+ return out;
+ }
+
+diff --git a/src/tests/md5_backend_test.c b/src/tests/md5_backend_test.c
+index 4c7b4e1aec5e..3f4290cae0ef 100644
+--- a/src/tests/md5_backend_test.c
++++ b/src/tests/md5_backend_test.c
+@@ -115,7 +115,7 @@ static char *md5_for_file(const char *path)
+ if (fstat(fd, &sb) < 0)
+ error(1, errno, "fstat failed");
+
+- hash = get_hash_from_fd2(fd, (size_t)sb.st_size, FILE_HASH_ALG_MD5);
++ hash = get_hash_from_fd2(fd, sb.st_size, FILE_HASH_ALG_MD5);
+ if (close(fd) < 0)
+ error(1, errno, "close failed");
+ if (hash == NULL)
+diff --git a/src/tests/trustdb_lmdb_test.c b/src/tests/trustdb_lmdb_test.c
+index 5e54589cc6d1..f935d482aca5 100644
+--- a/src/tests/trustdb_lmdb_test.c
++++ b/src/tests/trustdb_lmdb_test.c
+@@ -691,6 +691,76 @@ static int test_lmdb_large_size_import(void)
+ return 0;
+ }
+
++/*
++ * test_lmdb_large_file_sha256_recompute - cover content past size_t on i686.
++ *
++ * Large-file builds have a 64-bit off_t even when size_t remains 32 bits. A
++ * byte at the end of an exact 4 GiB file must therefore affect both the trust
++ * record digest and the runtime SHA recomputation used to validate it. The
++ * IMA fallback uses the same hashing helper when its xattr digest is stale.
++ *
++ * Returns 0 on success or when the host ABI cannot expose the truncation.
++ */
++static int test_lmdb_large_file_sha256_recompute(void)
++{
++ const off_t large_size = (off_t)UINT64_C(4294967296);
++ const char original_tail = 'A';
++ const char changed_tail = 'B';
++ conf_t cfg;
++ char dir[128];
++ char path[128];
++ char payload[512];
++ struct file_info *info = NULL;
++ char *hash = NULL;
++ long entries = 0;
++ int fd = -1;
++ int rc;
++
++ if (sizeof(size_t) >= sizeof(off_t))
++ return 0;
++
++ fd = create_test_file(path, sizeof(path), "");
++ CHECK(fd != -1, 277, "[ERROR:277] failed to create large SHA file");
++ CHECK(ftruncate(fd, large_size) == 0, 278,
++ "[ERROR:278] failed to size large SHA file");
++ CHECK(pwrite(fd, &original_tail, 1, large_size - 1) == 1, 279,
++ "[ERROR:279] failed to write large SHA file tail");
++ CHECK(describe_test_file(fd, &info, &hash) == 0, 280,
++ "[ERROR:280] failed to hash large SHA file");
++
++ rc = with_temp_db(dir, sizeof(dir), &cfg);
++ CHECK(rc == 0, 281, "[ERROR:281] failed to open large SHA LMDB");
++ cfg.integrity = IN_SHA256;
++ rc = decision_config_publish(&cfg);
++ CHECK(rc == 0, 282,
++ "[ERROR:282] failed to publish SHA integrity config");
++
++ snprintf(payload, sizeof(payload), "%s " DATA_FORMAT "\n", path,
++ SRC_FILE_DB, (trustdb_size_t)info->size, hash);
++ rc = import_records(payload, &entries);
++ CHECK(rc == 0 && entries == 1, 283,
++ "[ERROR:283] large SHA record import failed");
++ CHECK(check_trust_database(path, info, fd) == 1, 284,
++ "[ERROR:284] unchanged large SHA file was not trusted");
++
++ CHECK(pwrite(fd, &changed_tail, 1, large_size - 1) == 1, 285,
++ "[ERROR:285] failed to change large SHA file tail");
++ CHECK(check_trust_database(path, info, fd) == 0, 286,
++ "[ERROR:286] changed large SHA file remained trusted");
++
++ decision_config_destroy();
++ database_close_for_tests();
++ database_set_location(NULL, NULL);
++ CHECK(remove_lmdb_files(dir) == 0, 287,
++ "[ERROR:287] large SHA LMDB cleanup failed");
++ free(hash);
++ free(info);
++ CHECK(close(fd) == 0, 288, "[ERROR:288] large SHA file close failed");
++ CHECK(unlink(path) == 0, 289,
++ "[ERROR:289] large SHA file cleanup failed");
++ return 0;
++}
++
+ static int test_lmdb_short_path_round_trip(void)
+ {
+ conf_t cfg;
+@@ -1976,6 +2046,10 @@ int main(void)
+ if (rc)
+ return rc;
+
++ rc = test_lmdb_large_file_sha256_recompute();
++ if (rc)
++ return rc;
++
+ rc = test_lmdb_short_path_round_trip();
+ if (rc)
+ return rc;
+--
+2.55.0
+
diff --git a/fapolicyd.spec b/fapolicyd.spec
index 69f331c..4b8f9df 100644
--- a/fapolicyd.spec
+++ b/fapolicyd.spec
@@ -5,7 +5,7 @@
Summary: Application Whitelisting Daemon
Name: fapolicyd
Version: 2.0
-Release: 1%{?dist}
+Release: 2%{?dist}
License: GPL-3.0-or-later
URL: https://github.com/linux-application-whitelisting/fapolicyd
Source0: https://github.com/linux-application-whitelisting/fapolicyd/releases/download/v%{version}/fapolicyd-%{version}.tar.gz
@@ -24,6 +24,9 @@ Source20: https://github.com/troydhanson/uthash/archive/refs/tags/v2.3.0.tar.gz#
# $ for j in [0-9]*.patch; do printf "Patch: %s\n" $j; done
# Patch list start
Patch: 0002-Fix-large-file-support-on-32-bit-builds.patch
+Patch: 0004-Allow-KDE-qml-files-into-the-trust-db.patch
+Patch: 0005-Allow-a-couple-other-non-obvious-javascript-files-in.patch
+Patch: 0006-Fix-32-bit-large-file-digest-truncation.patch
# Patch: 0003-update-changelog.patch
# Patch list end
@@ -231,6 +234,10 @@ fi
%selinux_relabel_post -s %{selinuxtype}
%changelog
+* Thu Aug 13 2026 Petr Lautrbach <lautrbach@redhat.com> - 2.0-2
+- Allow a couple other non-obvious javascript files into the trust db
+ https://github.com/linux-application-whitelisting/fapolicyd/issues/432
+
* Thu Jul 23 2026 Petr Lautrbach <lautrbach@redhat.com> - 2.0-1
- fapolicyd-2.0
https://github.com/linux-application-whitelisting/fapolicyd/releases/tag/v2.0
reply other threads:[~2026-08-24 14:46 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=178758280312.1.12520463819164667177.rpms-fapolicyd-78f62eabb7aa@fedoraproject.org \
--to=lautrbach@redhat.com \
--cc=git-commits@fedoraproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox