This bug has been migrated to another issue tracking site. It has been closed here and may no longer be being monitored.

If you would like to get updates for this issue, or to participate in it, you may do so at Red Hat Issue Tracker .
RHEL Engineering is moving the tracking of its product development work on RHEL 6 through RHEL 9 to Red Hat Jira (issues.redhat.com). If you're a Red Hat customer, please continue to file support cases via the Red Hat customer portal. If you're not, please head to the "RHEL project" in Red Hat Jira and file new tickets here. Individual Bugzilla bugs in the statuses "NEW", "ASSIGNED", and "POST" are being migrated throughout September 2023. Bugs of Red Hat partners with an assigned Engineering Partner Manager (EPM) are migrated in late September as per pre-agreed dates. Bugs against components "kernel", "kernel-rt", and "kpatch" are only migrated if still in "NEW" or "ASSIGNED". If you cannot log in to RH Jira, please consult article #7032570. That failing, please send an e-mail to the RH Jira admins at rh-issues@redhat.com to troubleshoot your issue as a user management inquiry. The email creates a ServiceNow ticket with Red Hat. Individual Bugzilla bugs that are migrated will be moved to status "CLOSED", resolution "MIGRATED", and set with "MigratedToJIRA" in "Keywords". The link to the successor Jira issue will be found under "Links", have a little "two-footprint" icon next to it, and direct you to the "RHEL project" in Red Hat Jira (issue links are of type "https://issues.redhat.com/browse/RHEL-XXXX", where "X" is a digit). This same link will be available in a blue banner at the top of the page informing you that that bug has been migrated.
Bug 2176844 - fapolicyd can create RPM DB files /var/lib/rpm/__db.xxx` with bad ownership causing AVCs to occur
Summary: fapolicyd can create RPM DB files /var/lib/rpm/__db.xxx` with bad ownership c...
Keywords:
Status: CLOSED MIGRATED
Alias: None
Product: Red Hat Enterprise Linux 8
Classification: Red Hat
Component: fapolicyd
Version: 8.7
Hardware: All
OS: Linux
medium
medium
Target Milestone: rc
: ---
Assignee: Radovan Sroka
QA Contact: BaseOS QE Security Team
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2023-03-09 13:23 UTC by Renaud Métrich
Modified: 2023-07-27 10:35 UTC (History)
3 users (show)

Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2023-07-20 12:17:34 UTC
Type: Bug
Target Upstream Version:
Embargoed:
pm-rhel: mirror+


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Red Hat Issue Tracker   RHEL-829 0 None None None 2023-07-27 10:35:56 UTC
Red Hat Issue Tracker RHELPLAN-151218 0 None None None 2023-03-09 13:26:54 UTC
Red Hat Issue Tracker SECENGSP-5089 0 None None None 2023-03-09 13:27:00 UTC

Description Renaud Métrich 2023-03-09 13:23:32 UTC
Description of problem:

Because fapolicyd executes with fapolicyd:fapolicyd user/group, it may happen that upon start, fapolicyd creates RPM DB files and owns them:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
# ls -ld /var/lib/rpm/__*
-rw-r-----. 1 fapolicyd fapolicyd  286720 Mar  9 14:13 /var/lib/rpm/__db.001
-rw-r-----. 1 fapolicyd fapolicyd   90112 Mar  9 14:13 /var/lib/rpm/__db.002
-rw-r-----. 1 fapolicyd fapolicyd 1318912 Mar  9 14:13 /var/lib/rpm/__db.003
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

This leads to other services, such as *rhsmcertd* to throw AVCs:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
... type=PROCTITLE msg=audit(02/22/2023 22:01:44.253:71037) : proctitle=/usr/libexec/platform-python /usr/libexec/rhsmcertd-worker 
... type=PATH msg=audit(02/22/2023 22:01:44.253:71037) : item=0 name=/var/lib/rpm/__db.001 inode=135 dev=fd:04 mode=file,640 ouid=fapolicyd ogid=fapolicyd rdev=00:00 obj=system_u:object_r:rpm_var_lib_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0 
... type=CWD msg=audit(02/22/2023 22:01:44.253:71037) : cwd=/ 
... type=SYSCALL msg=audit(02/22/2023 22:01:44.253:71037) : arch=x86_64 syscall=openat success=no exit=EACCES(Permission denied) a0=0xffffff9c a1=0x55b6c41d8650 a2=O_RDWR a3=0x0 items=1 ppid=1831 pid=305395 auid=unset uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=(none) ses=unset comm=rhsmcertd-worke exe=/usr/libexec/platform-python3.6 subj=system_u:system_r:rhsmcertd_t:s0 key=(null) 
... type=AVC msg=audit(02/22/2023 22:01:44.253:71037) : avc:  denied  { dac_override } for  pid=305395 comm=rhsmcertd-worke capability=dac_override  scontext=system_u:system_r:rhsmcertd_t:s0 tcontext=system_u:system_r:rhsmcertd_t:s0 tclass=capability permissive=0 
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

Additionally, "rpm -V" then complains because it's not in accordance with expected permissions and owner:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
# rpm -V rpm
.M...UG..  c /var/lib/rpm/__db.001
.M...UG..  c /var/lib/rpm/__db.002
.M...UG..  c /var/lib/rpm/__db.003
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

The expected permissions and ownership are 600 / root:root:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
# ls -ld /var/lib/rpm/__*
-rw-------. 1 root root  286720 Mar  9 13:50 /var/lib/rpm/__db.001
-rw-------. 1 root root   90112 Mar  9 13:50 /var/lib/rpm/__db.002
-rw-------. 1 root root 1318912 Mar  9 13:50 /var/lib/rpm/__db.003
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------


Version-Release number of selected component (if applicable):

fapolicyd-1.1.3-8.el8.x86_64 and latest fapolicyd-1.1.3-8.el8_7.1.x86_64

How reproducible:

Always

Steps to Reproduce:
1. Stop fapolicyd service

   # systemctl stop fapolicyd

2. Delete RPM files

   # rm /var/lib/rpm/__*

3. Start fapolicyd service

   # systemctl start fapolicyd

4. Check permissions and ownership

Actual results:

640 / fapolicyd:fapolicyd

Expected results:

600 / root:root

Additional info:

The reason for this is execution of rpm command (or librpm, didn't check) internally

Comment 1 Radovan Sroka 2023-03-09 14:49:54 UTC
@mdomonko @ffesti @pmatilai can you look at this?

Fapolicyd is using librpm. It is iterating over all the files in installed packages. 
We don't want to write anything but there are some new files created by librpm under fapolicyd user and group.

https://github.com/linux-application-whitelisting/fapolicyd/blob/main/src/library/rpm-backend.c

How can we prevent such a behavior?

Comment 2 Michal Domonkos 2023-03-09 15:09:04 UTC
These files are BerkeleyDB "shared regions" [1].  A quick look reveals that the use of rpmtsInitIterator() in rpm-backend.c leads to rpmtsOpenDB() in librpm which may explain where those files are being created.

This likely isn't fapolicyd specific, the same could happen with any librpm application.  It seems like an implementation detail of librpm (or BDB for that matter), not something that the calling application should need to care about so it remains to be seen whether it's just the librpm API lacking here or a straight up bug.

Florian, Panu, any thoughts?

[1] https://docs.oracle.com/cd/E17275_01/html/programmer_reference/env_region.html

Comment 3 Michal Domonkos 2023-03-09 15:12:06 UTC
And by "bug", I mean the fact that there can be files in the /var/lib/rpm directory that are created as a result of an librpm API call and that are owned by the user/group running the process, not root.

Comment 4 Panu Matilainen 2023-03-10 11:41:36 UTC
That's supposed to be a "can't happen" because /var/lib/rpm is supposed to be owned by root:root and nobody else can write there.

What does 'ls -ld /var/lib/rpm/' say? If there's something loosening up the rpmdb directory permissions then that's pretty severe.

Comment 5 Renaud Métrich 2023-03-10 12:07:57 UTC
Top directory permissions are correct:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
[root@vm-stig8 ~]# ls -ld /var/lib/rpm
drwxr-xr-x. 2 root root 4096 Mar 10 12:49 /var/lib/rpm
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

Through stracing (in Permissive or else ...), I can see that capabilities are kept before switching user:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
1738  12:55:13.504793 prctl(PR_SET_KEEPCAPS, 1) = 0 <0.000010>
1738  12:55:13.504830 capset({version=_LINUX_CAPABILITY_VERSION_3, pid=1738}, {effective=1<<CAP_DAC_OVERRIDE|1<<CAP_SETGID|1<<CAP_SETUID|1<<CAP_SYS_PTRACE|1<<CAP_SYS_ADMIN|1<<CAP_SYS_NICE|1<<CAP_SYS_RESOURCE|1<<CAP_AUDIT_WRITE, permitted=1<<CAP_DAC_OVERRIDE|1<<CAP_SETGID|1<<CAP_SETUID|1<<CAP_SYS_PTRACE|1<<CAP_SYS_ADMIN|1<<CAP_SYS_NICE|1<<CAP_SYS_RESOURCE|1<<CAP_AUDIT_WRITE, inheritable=0}) = 0 <0.000008>
1738  12:55:13.504864 setresgid(991, 991, 991) = 0 <0.000007>
1738  12:55:13.504892 setgroups(0, NULL) = 0 <0.000010>
1738  12:55:13.504921 setresuid(995, 995, 995) = 0 <0.000010>
1738  12:55:13.504949 prctl(PR_SET_KEEPCAPS, 0) = 0 <0.000006>
1738  12:55:13.504974 capset({version=_LINUX_CAPABILITY_VERSION_3, pid=1738}, {effective=1<<CAP_DAC_OVERRIDE|1<<CAP_SYS_PTRACE|1<<CAP_SYS_ADMIN|1<<CAP_SYS_NICE|1<<CAP_SYS_RESOURCE|1<<CAP_AUDIT_WRITE, permitted=1<<CAP_DAC_OVERRIDE|1<<CAP_SYS_PTRACE|1<<CAP_SYS_ADMIN|1<<CAP_SYS_NICE|1<<CAP_SYS_RESOURCE|1<<CAP_AUDIT_WRITE, inheritable=0}) = 0 <0.000006>
 :
1738  12:55:13.517812 openat(AT_FDCWD</>, "/var/lib/rpm/__db.001", O_RDWR|O_CREAT|O_EXCL, 0644 <unfinished ...>
1738  12:55:13.517898 <... openat resumed>) = 8</var/lib/rpm/__db.001> <0.000069>
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

Using systemtap, I could find that capset() is called by:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
(gdb) bt
#0  0x00007f73e16510bb in capset () from /lib64/libc.so.6
#1  0x00007f73e2839dbb in capng_apply () from /lib64/libcap-ng.so.0
#2  0x00007f73e2839ee5 in capng_change_id () from /lib64/libcap-ng.so.0
#3  0x000055d2d240a5e8 in main (argc=<optimized out>, argv=<optimized out>) at daemon/fapolicyd.c:493
(gdb) f 3
#3  0x000055d2d240a5e8 in main (argc=<optimized out>, argv=<optimized out>) at daemon/fapolicyd.c:493
493			if (capng_change_id(config.uid, config.gid,
(gdb) list
488		if (config.uid != 0) {
489			capng_clear(CAPNG_SELECT_BOTH);
490			capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
491				CAP_DAC_OVERRIDE, CAP_SYS_ADMIN, CAP_SYS_PTRACE,
492				CAP_SYS_NICE, CAP_SYS_RESOURCE, CAP_AUDIT_WRITE, -1);
493			if (capng_change_id(config.uid, config.gid,
494								CAPNG_DROP_SUPP_GRP)) {
495				msg(LOG_ERR, "Cannot change to uid %d", config.uid);
496				exit(1);
497			} else
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

Comment 6 Renaud Métrich 2023-03-10 12:10:36 UTC
This DAC_OVERRIDE makes sense to be able to check files from everybody, but at the time RPMDB is read, it should not have the capability enabled.

Comment 7 Radovan Sroka 2023-03-22 10:07:02 UTC
(In reply to Panu Matilainen from comment #4)
> That's supposed to be a "can't happen" because /var/lib/rpm is supposed to
> be owned by root:root and nobody else can write there.
> 
> What does 'ls -ld /var/lib/rpm/' say? If there's something loosening up the
> rpmdb directory permissions then that's pretty severe.

Fapolicyd has and needs CAP_DAC_OVERRIDE capability that's why files are created there... 

Would it make sense to implement a possibility to pass a flag to librpm that we don't want to create anything?

Comment 8 Panu Matilainen 2023-03-28 12:52:41 UTC
Unfortunately not. BDB needs to create those __db.* environment files for shared locking, even if for read-only access. Regular user queries are forced to run in private locking mode because they can't create or write to those files, and regularly produce garbage because of that. Which is something you don't want in fapolicyd.
So it's a damned if you do, damned if you don't situation.

Comment 9 Radovan Sroka 2023-07-04 09:17:36 UTC
Do you think it's possible to reproduce also in RHEL9? I mean whether BDB can be used there?

Comment 10 Panu Matilainen 2023-07-04 10:18:04 UTC
No, RHEL9 only has minimal readonly bdb-support which doesn't create such files.

Comment 11 Radovan Sroka 2023-07-10 09:49:10 UTC
I've created fapolicyd downstream workaround for rhel8. It corrects those files with chown. What do you think?

diff -up ./src/daemon/fapolicyd.c.librpm-workaround ./src/daemon/fapolicyd.c
--- ./src/daemon/fapolicyd.c.librpm-workaround	2023-07-10 11:19:19.507044648 +0200
+++ ./src/daemon/fapolicyd.c	2023-07-10 11:19:19.509044621 +0200
@@ -572,7 +572,7 @@ int main(int argc, const char *argv[])
 		capng_clear(CAPNG_SELECT_BOTH);
 		capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
 			CAP_DAC_OVERRIDE, CAP_SYS_ADMIN, CAP_SYS_PTRACE,
-			CAP_SYS_NICE, CAP_SYS_RESOURCE, CAP_AUDIT_WRITE, -1);
+			CAP_SYS_NICE, CAP_SYS_RESOURCE, CAP_AUDIT_WRITE, CAP_CHOWN, -1);
 		if (capng_change_id(config.uid, config.gid,
 							CAPNG_DROP_SUPP_GRP)) {
 			msg(LOG_ERR, "Cannot change to uid %d", config.uid);
diff -up ./src/library/rpm-backend.c.librpm-workaround ./src/library/rpm-backend.c
--- ./src/library/rpm-backend.c.librpm-workaround	2023-06-15 16:45:14.000000000 +0200
+++ ./src/library/rpm-backend.c	2023-07-10 11:22:07.066794595 +0200
@@ -32,7 +32,12 @@
 #include <rpm/rpmdb.h>
 #include <rpm/rpmpgp.h>
 #include <fnmatch.h>
+#include <glob.h>
+#include <pwd.h>
+#include <grp.h>
+#include <fcntl.h>
 
+#include <unistd.h>
 #include <uthash.h>
 
 #include "message.h"
@@ -59,6 +64,50 @@ backend rpm_backend =
 static rpmts ts = NULL;
 static rpmdbMatchIterator mi = NULL;
 
+static void fix_files(void)
+{
+	glob_t glob_result;
+	const char *pattern = "/var/lib/rpm/__*";
+
+	struct passwd * usr = getpwnam("fapolicyd");
+	if (usr == NULL) {
+		return;
+	}
+
+	struct group * grp = getgrnam("fapolicyd");
+	if (grp == NULL) {
+		return;
+	}
+
+	int return_value = glob(pattern, 0, NULL, &glob_result);
+	if (return_value != 0) {
+		return;
+	}
+
+	for (int i = 0; i < glob_result.gl_pathc; ++i) {
+
+		int fd = open(glob_result.gl_pathv[i], O_NOFOLLOW);
+
+		if (fd == -1)
+			continue;
+
+		struct stat file_stat;
+		if (fstat(fd, &file_stat) != 0) {
+			continue;
+		}
+
+		if (file_stat.st_uid == usr->pw_uid &&
+			file_stat.st_gid == grp->gr_gid) {
+
+			fchown(fd, 0, 0);
+		}
+
+		close(fd);
+	}
+
+	globfree(&glob_result);
+}
+
 static int init_rpm(void)
 {
 	return rpmReadConfigFiles ((const char *)NULL, (const char *)NULL);
@@ -201,8 +250,13 @@ static int rpm_load_list(const conf_t *c
 		return rc;
 	}
 
+	int fixed = 0;
 	// Loop across the rpm database
 	while (get_next_package_rpm()) {
+		if (!fixed) {
+			fixed = 1;
+			fix_files();
+		}
 		// Loop across the packages
 		while (get_next_file_rpm()) {
 			// We do not want directories or symlinks in the

Comment 12 Radovan Sroka 2023-07-19 12:14:42 UTC
This bug is going to be migrated.

Contact point for migration questions or issues: rsroka
Guidance for Bugzilla users to test their Jira account or create one if needed:

https://redhat.service-now.com/help?id=kb_article_view&sysparm_article=KB0016394
https://redhat.service-now.com/help?id=kb_article_view&sysparm_article=KB0016694
https://redhat.service-now.com/help?id=kb_article_view&sysparm_article=KB0016774


Note You need to log in before you can comment on or make changes to this bug.