5

I'm trying to connect to PostgreSQL Unix domain socket from a PHP web application. Relevant system components:

  • CentOS 7 x64 (SELinux enforced)
  • postgresql93 9.3.5-2PGDG.rhel7
  • nginx 1.6.2-1.el7.ngx
  • php-common 5.4.16-23.el7_0.3
  • php-fpm 5.4.16-23.el7_0.3
  • php-pdo 5.4.16-23.el7_0.3
  • php-pgsql 5.4.16-23.el7_0.3

PostgreSQL is listening on standard port 5432 and I have no problems to use it via TCP/IP at 127.0.0.1:5432, but when I try to connect to its Unix domain socket, I have a following error:

Cannot connect to database: SQLSTATE[08006] [7] could not connect to server:
No such file or directory
    Is the server running locally and accepting
    connections on Unix domain socket "/tmp/.s.PGSQL.5432"?

File /tmp/.s.PGSQL.5432 exists and I can connect using psql:

$ psql -Uusername db_name
psql (9.3.5)
Type "help" for help.

db_name=>

So there should be no problems from the PostgreSQL side. Or are there?

Relevant line from /var/lib/pgsql/9.3/data/pg_hba.conf:

local    all    username        trust

Change of location for Unix domain socket file in /var/lib/pgsql/9.3/data/postgresql.conf did not help:

unix_socket_directories = '/var/run/pgsql'

There was nothing in /var/log/audit/audit.log, but I've tried to disable SELinux, just to be sure:

# setenforce 0

This did not help, so it is not SELinux.

Relevant lines from strace of php-fpm:

[pid   882] socket(PF_LOCAL, SOCK_STREAM, 0) = 5
[pid   882] fcntl(5, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
[pid   882] fcntl(5, F_SETFD, FD_CLOEXEC) = 0
[pid   882] connect(5, {sa_family=AF_LOCAL, sun_path="/tmp/.s.PGSQL.5432"}, 110) = -1 ENOENT (No such file or directory)
[pid   882] close(5)                    = 0

The file name is correct and, again, file /tmp/.s.PGSQL.5432 exists:

$ ls -l /tmp/.s.PGSQL.5432
srwxrwxrwx. 1 postgres postgres 0 Nov  1 09:47 /tmp/.s.PGSQL.5432

It looks like php-fpm process is not chroot'ed:

# ls -l /proc/882/root
lrwxrwxrwx. 1 apache apache 0 Oct 31 19:54 /proc/882/root -> /

At this point I have no more ideas where the problem can be and I would appreciate any help.

7

I've resolved the problem. The initial cause of it was in systemd service file for php-fpm /usr/lib/systemd/system/php-fpm.service:

[Service]
PrivateTmp=true

This means that php-fpm could not see /tmp/.s.PGSQL.5432 nor anything else located in /tmp. To resolve the issue I've changed the location for PostgreSQL Unix domain socket file with following steps:

  • Create a new directory /var/pgsql (note changing SELinux file context):

    # mkdir /var/pgsql
    # chown posgres:postgres /var/pgsql
    # chmod 0755 /var/pgsql
    # semanage fcontext -a -t httpd_var_run_t "/var/pgsql(/.*)?"
    # restorecon -R /var/pgsql
    
  • Uncomment and modify unix_socket_directories parameter in /var/lib/pgsql/9.3/data/postgresql.conf (/tmp is still needed not to break psql and other programs):

    unix_socket_directories = '/tmp,/var/pgsql'
    

And here was another tricky part... In the original post I wrote that I've tried to change the location of Unix domain socket file, and I really did. What I missed was the changed error message. I thought that the error was the same, but it wasn't:

Error (256): Cannot connect to database: SQLSTATE[08006] [7] could not connect to
server: Permission denied
    Is the server running locally and accepting
    connections on Unix domain socket "/var/pgsql/.s.PGSQL.5432"?

Permission denied - this is something one can fight.

Everything works with

# setenforce 0

The problem is:

# audit2allow -a

#============= httpd_t ==============
allow httpd_t initrc_t:unix_stream_socket connectto;

And it can be fixed:

# audit2allow -a -M httpd_postgresql_unix_socket_connect
# semodule -i httpd_postgresql_unix_socket_connect.pp

Content of httpd_postgresql_unix_socket_connect.te:

module httpd_postgresql_unix_socket_connect 1.0;

require {
        type httpd_t;
        type initrc_t;
        class unix_stream_socket connectto;
}

#============= httpd_t ==============
allow httpd_t initrc_t:unix_stream_socket connectto;

Turn SELinux back on:

# setenforce 1

And everything works!

P.S. I'd be glad to know if there is a way to avoid custom SELinux module by changing some file contexts or booleans. It might be the case, because SELinux allows nginx to use php-fpm Unix domain socket (/var/run/php5-fpm.sock), but for some reason blocks usage of PostgreSQL Unix domain socket (/var/pgsql/.s.PGSQL.5432).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.