firewalld triggers SELinux AVCs if /tmp, /var/tmp, and /dev/shm are mounted with noexec

Solution Unverified - Updated -

Environment

  • Red Hat Enterprise Linux (RHEL) 7.6, 8.0
  • libffi-3.0.13-18.el7.x86_64
  • firewalld-0.5.3-5.el7.noarch

Issue

If /tmp, /var/tmp, and /dev/shm are mounted with the noexec mount option firewalld can trigger the following SELinux AVCs when started or restarted:

type=AVC msg=audit(1560544617.17:262): avc:  denied  { write } for  pid=14424 comm="firewalld" name="/" dev="sda1" ino=2 scontext=system_u:system_r:firewalld_t:s0 tcontext=system_u:object_r:root_t:s0 tclass=dir permissive=1

type=AVC msg=audit(1560544617.18:263): avc:  denied  { add_name } for  pid=14424 comm="firewalld" name="ffiENLlbD" scontext=system_u:system_r:firewalld_t:s0 tcontext=system_u:object_r:root_t:s0 tclass=dir permissive=1

type=AVC msg=audit(1560544617.18:263): avc:  denied  { create } for  pid=14424 comm="firewalld" name="ffiENLlbD" scontext=system_u:system_r:firewalld_t:s0 tcontext=system_u:object_r:root_t:s0 tclass=file permissive=1

type=AVC msg=audit(1560544617.18:263): avc:  denied  { read write open } for  pid=14424 comm="firewalld" path="/ffiENLlbD" dev="sda1" ino=595 scontext=system_u:system_r:firewalld_t:s0 tcontext=system_u:object_r:root_t:s0 tclass=file permissive=1

I.e. it tries to write to the root directory '/' and create temporary file there with random name which begins with the 'ffi' string, in this example 'ffiENLlbD'.

This problem can also manifests with other daemons written in python which use DBus, not just with the firewalld.

Resolution

This problem can be resolved by mounting some temporary directory with the exec mount option (i.e. the default mount option) and setting the TMPDIR environment variable to point to it. This can be done just for the firewalld service by editing the /etc/sysconfig/firewalld file.

Also good candidate for the temporal directory is the /run directory, which is by default mounted with the exec mount option. To use it as a workaround for this problem add the following text to the /etc/sysconfig/firewalld file:

TMPDIR=/run

We believe that the /run directory should be used by default in such cases without this workaround. The feature requests are tracked by RHEL 7 bug 1722756 and RHEL 8 bug 1723951.

For more details and updates please contact Red Hat Support.

Root Cause

DBus code in the firewalld uses pygobject which uses libffi to call gobject-introspection functions. The libffi is used for portability to translate the calling conventions. It does it by writing temporary files and executing them (that's why it needs mapping with PROT_EXEC).

The temporal files created by libffi are prefixed by 'ffi', e.g. 'ffiBlLJT1', so they can be easily distinguished from other temporal files.

The libffi uses the following search table when searching for the temporal directory (libffi-3.0.13/src/closures.c:367):

open_temp_exec_file_opts[] = {
  { open_temp_exec_file_env, "TMPDIR", 0 },
  { open_temp_exec_file_dir, "/tmp", 0 },
  { open_temp_exec_file_dir, "/var/tmp", 0 },
  { open_temp_exec_file_dir, "/dev/shm", 0 },
  { open_temp_exec_file_env, "HOME", 0 },
#ifdef HAVE_MNTENT
  { open_temp_exec_file_mnt, "/etc/mtab", 1 },
  { open_temp_exec_file_mnt, "/proc/mounts", 1 },
#endif /* HAVE_MNTENT */
};

Thus, when it tries all the explicit entries from this search table and still doesn't find mount point mounted with the exec mount option, it fallbacks to the /etc/mtab or /proc/mounts. From there it can try the root mount point ('/') which will cause the above mentioned SELinux AVCs.

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.