SELinux/PostgresQL "denied { open } for [..] comm="pg_ctl" path="$PGDATA/postgresql.conf"

LANerd asked:

I’ve installed PostgresQL on a SELinux-enabled Centos 7 box and changed it’s default data directory to /srv/postgres/data, a separate LUKS-encrypted LVM volume group/logical volume, for reasons of mobility, in case I have to move the server, and confidentiality, should the data media be stolen or exposed while moving. I think that the LUKS/LVM functionality involved shouldn’t affect my problem, but mention it for reasons of completeness.

Now, when I start the postgresql service:

root@fafner:~ # systemctl start postgresql

… I get this in /var/log/audit/audit.log:

root@fafner:~ # tail -f /var/log/audit/audit.log | grep "postgresql" 
[..]
type=AVC msg=audit(1476614020.689:522): avc: denied  { open } for  pid=2900 comm="pg_ctl" path="/srv/postgres/data/postgresql.conf" dev="dm-4" ino=136 scontext=system_u:system_r:postgresql_t:s0 tcontext=unconfined_u:object_r:var_t:s0 tclass=file type=SYSCALL msg=audit(1476614020.689:522): arch=c000003e syscall=2 success=no exit=-13 a0=7ffc681cc430 a1=0 a2=1b6 a3=24 items=1 ppid=1 pid=2900 auid=4294967295 uid=989 gid=986 euid=989 suid=989 fsuid=989 egid=986 sgid=986 fsgid=986 tty=(none) ses=4294967295 comm="pg_ctl" exe="/usr/bin/pg_ctl" subj=system_u:system_r:postgresql_t:s0 key=(null)
type=PATH msg=audit(1476614020.689:522): item=0 name="/srv/postgres/data/postgresql.conf" inode=136 dev=fd:04 mode=0100600 ouid=989 ogid=986 rdev=00:00 obj=unconfined_u:object_r:var_t:s0 objtype=NORMAL
type=AVC msg=audit(1476614020.725:523): avc: denied  { open } for  pid=2904 comm="postgres" path="/srv/postgres/data/postgresql.conf" dev="dm-4" ino=136 scontext=system_u:system_r:postgresql_t:s0 tcontext=unconfined_u:object_r:var_t:s0 tclass=file type=SYSCALL msg=audit(1476614020.725:523): arch=c000003e syscall=2 success=no exit=-13 a0=befc30 a1=0 a2=1b6 a3=24 items=1 ppid=2900 pid=2904 auid=4294967295 uid=989 gid=986 euid=989 suid=989 fsuid=989 egid=986 sgid=986 fsgid=986 tty=(none) ses=4294967295 comm="postgres" exe="/usr/bin/postgres" subj=system_u:system_r:postgresql_t:s0 key=(null)
type=PATH msg=audit(1476614020.725:523): item=0 name="/srv/postgres/data/postgresql.conf" inode=136 dev=fd:04 mode=0100600 ouid=989 ogid=986 rdev=00:00 obj=unconfined_u:object_r:var_t:s0 objtype=NORMAL
type=SERVICE_START msg=audit(1476614021.712:524): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=postgresql comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=failed'

I’ve tried using audit2allow to fix the issue:

root@fafner:~ # grep "postgresql" /var/log/audit/audit.log | audit2allow -M postgresql_tskjoedt
root@fafner:~ # semodule -i postgresql_tskjoedt.pp

… rendering some output in /var/log/audit/audit.log that I’ve pasted at the bottom of the post. It didn’t fix the problem, though, the error persists in exactly the same form.

I’ve also tried:

root@fafner:~ # restorecon -Rv /usr/bin/pg_ctl
root@fafner:~ # restorecon -Rv /srv/postgres/data

… and even touch’ing a ‘.autorelabel’-file on the root and postgres filesystems, and rebooting, to relabel everything involved. But I still get the same “denied open for pg_ctl on postgresql.conf” error in audit.log.

I’ve done these things a couple of times assuming that the changes are not cumulative.

From this answer and some of the links that it refers to I gather that somehow these SELinux contexts/labels do not line up properly:

root@fafner:~ # ls -Z /usr/bin/pg_ctl
-rwxr-xr-x. root root system_u:object_r:postgresql_exec_t:s0 /usr/bin/pg_ctl
root@fafner:~ # ls -Z /usr/bin/postgres
-rwxr-xr-x. root root system_u:object_r:postgresql_exec_t:s0 /usr/bin/postgres
root@fafner:~ # ls -Z /srv/postgres/data/postgresql.conf
-rw-------. postgres postgres unconfined_u:object_r:var_t:s0   /srv/postgres/data/postgresql.conf

I could just shuffle the labels around until something may start working, but I don’t want to arbitrarily set or ruin SELinux labels just to get things working; then I might as well just turn off SELinux.

Also, I don’t understand why ‘audit2allow’ doesn’t fix the specific problem; isn’t this command supposed to do exactly that, in essence, widen the SELinux context just enough for the specific operation to be allowed?

This whole question of course stems from my lack of understanding of SELinux, and much of the audit.log output is relatively obscure to me. Can someone pinpoint what clue I should be picking up on?

Kind regards,

Torsten

The “audit2allow” output and activation:

root@fafner:~ # grep "postgresql" /var/log/audit/audit.log | audit2allow -M postgresql_tskjoedt
******************** IMPORTANT ***********************
To make this policy package active, execute:

semodule -i postgresql_tskjoedt.pp

root@fafner:~ # semodule -i postgresql_tskjoedt.pp

… giving this output:

root@fafner:~ # tail -f /var/log/audit/audit.log | grep "postgresql" 
[..]
type=PATH msg=audit(1476614657.389:3389): item=1 name="/etc/selinux/targeted/modules/tmp/modules/postgresql.conf_tskjoedt.pp.tmp" inode=8880955 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:semanage_store_t:s0 objtype=CREATE
type=PATH msg=audit(1476614657.451:3390): item=2 name="/etc/selinux/targeted/modules/tmp/modules/postgresql.conf_tskjoedt.pp.tmp" inode=8880955 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:semanage_store_t:s0 objtype=DELETE
type=PATH msg=audit(1476614657.451:3390): item=3 name="/etc/selinux/targeted/modules/tmp/modules/postgresql.conf_tskjoedt.pp" inode=8880955 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:semanage_store_t:s0 objtype=CREATE
type=PATH msg=audit(1476614658.040:3453): item=1 name="/etc/selinux/targeted/modules/tmp/modules/postgresql.pp.tmp" inode=10578379 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:semanage_store_t:s0 objtype=CREATE
type=PATH msg=audit(1476614658.049:3454): item=2 name="/etc/selinux/targeted/modules/tmp/modules/postgresql.pp.tmp" inode=10578379 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:semanage_store_t:s0 objtype=DELETE
type=PATH msg=audit(1476614658.049:3454): item=3 name="/etc/selinux/targeted/modules/tmp/modules/postgresql.pp" inode=10578379 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:semanage_store_t:s0 objtype=CREATE
type=PATH msg=audit(1476614660.640:3701): item=1 name="/etc/selinux/targeted/modules/tmp/modules/postgresql.conf.pp.tmp" inode=9373011 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:semanage_store_t:s0 objtype=CREATE
type=PATH msg=audit(1476614660.650:3702): item=2 name="/etc/selinux/targeted/modules/tmp/modules/postgresql.conf.pp.tmp" inode=9373011 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:semanage_store_t:s0 objtype=DELETE
type=PATH msg=audit(1476614660.650:3702): item=3 name="/etc/selinux/targeted/modules/tmp/modules/postgresql.conf.pp" inode=9373011 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:semanage_store_t:s0 objtype=CREATE
type=PATH msg=audit(1476614660.650:3703): item=1 name="/etc/selinux/targeted/modules/tmp/modules/postgresql_tskjoedt.pp.tmp" inode=9373012 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:semanage_store_t:s0 objtype=CREATE
type=PATH msg=audit(1476614660.651:3704): item=2 name="/etc/selinux/targeted/modules/tmp/modules/postgresql_tskjoedt.pp.tmp" inode=9373012 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:semanage_store_t:s0 objtype=DELETE
type=PATH msg=audit(1476614660.651:3704): item=3 name="/etc/selinux/targeted/modules/tmp/modules/postgresql_tskjoedt.pp" inode=9373012 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:semanage_store_t:s0 objtype=CREATE
type=PATH msg=audit(1476614662.252:3877): item=1 name="/etc/selinux/targeted/modules/tmp/modules/postgresql_tskjoedt.pp" inode=9373012 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:semanage_store_t:s0 objtype=NORMAL
type=PATH msg=audit(1476614701.939:4076): item=1 name="/etc/selinux/targeted/modules/previous/modules/postgresql.conf_tskjoedt.pp" inode=26543251 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:semanage_store_t:s0 objtype=DELETE
type=PATH msg=audit(1476614702.201:4108): item=1 name="/etc/selinux/targeted/modules/previous/modules/postgresql.pp" inode=26823275 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:semanage_store_t:s0 objtype=DELETE
type=PATH msg=audit(1476614702.934:4232): item=1 name="/etc/selinux/targeted/modules/previous/modules/postgresql.conf.pp" inode=26823314 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:semanage_store_t:s0 objtype=DELETE
type=PATH msg=audit(1476614702.934:4233): item=1 name="/etc/selinux/targeted/modules/previous/modules/postgresql_tskjoedt.pp" inode=26823315 dev=fd:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:semanage_store_t:s0 objtype=DELETE

My answer:


Why change the data directory? That just makes your life complicated. You could have mounted the filesystem at the point of the default data directory, and everything would have just worked. It would also be easier to understand and maintain.

Filesystem                  Size  Used Avail Use% Mounted on
/dev/mapper/volgroup-pgsql  1.1T  128K  1.1T   1% /var/lib/pgsql

If you really mean to keep the non-default data directory, then you need to tell SELinux what contexts to apply to that directory and its contents. This is done with semanage fcontext. In this case, we’re going to use the --equal option to make your non-default directory have the same contexts as the default directory /var/lib/pgsql.

semanage fcontext --add --equal /var/lib/pgsql /srv/postgres

From the man page:

       -e EQUAL, --equal EQUAL
              Substitute  target  path with sourcepath when generating default
              label. This is used with fcontext. Requires  source  and  target
              path  arguments.  The context labeling for the target subtree is
              made equivalent to that defined for the source.

This is persistent, but it doesn’t change existing labels. To finish up, you’ll need to run restorecon to reset all the labels.

restorecon -rv /srv/postgres

View the full question and answer on Server Fault.

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.