Bug 772084 - Can't connect to local Postgresql server from Apache httpd / PHP
Summary: Can't connect to local Postgresql server from Apache httpd / PHP
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Fedora
Classification: Fedora
Component: selinux-policy-targeted
Version: 16
Hardware: x86_64
OS: Linux
unspecified
unspecified
Target Milestone: ---
Assignee: Miroslav Grepl
QA Contact: Ben Levenson
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2012-01-05 21:59 UTC by Yann Droneaud
Modified: 2012-01-09 16:03 UTC (History)
4 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed: 2012-01-06 18:50:50 UTC
Type: ---
Embargoed:


Attachments (Terms of Use)

Description Yann Droneaud 2012-01-05 21:59:19 UTC
After upgrading from Fedora 14 to Fedora 16,
my installation of Apache httpd + PHP + Dolibarr + Postgresql doesn't work:
the PHP scripts can't connect to the database while I'm able to connect to the database from command line, using psql and various authentication schemes.

/var/log/httpd/error_log is filled with lines such as

[Wed Jan 04 23:13:57 2012] [error] [client ::1] PHP Warning:  pg_connect(): Unable to connect to PostgreSQL server: could not connect to server: Permission denied\n\tIs the server running on host "localhost" (::1) and accepting\n\tTCP/IP connections on port 5432?\ncould not connect to server: Permission denied\n\tIs the server running on host "localhost" (127.0.0.1) and accepting\n\tTCP/IP connections on port 5432? in /usr/share/dolibarr/htdocs/lib/databases/pgsql.lib.php on line 357, referer: http://localhost/dolibarr/install/check.php

[Wed Jan 04 23:13:57 2012] [error] [client ::1] PHP Warning:  pg_last_error() expects parameter 1 to be resource, boolean given in /usr/share/dolibarr/htdocs/lib/databases/pgsql.lib.php on line 836, referer: http://localhost/dolibarr/install/check.php

There's nothing logged in /var/lib/pgsql/data/pg_log/postgresql-*.log regarding connections.

Comment 1 Yann Droneaud 2012-01-05 22:04:49 UTC
Using strace, I'm getting

 socket(PF_INET6, SOCK_STREAM, IPPROTO_IP) = 12
 setsockopt(12, SOL_TCP, TCP_NODELAY, [1], 4) = 0
 fcntl(12, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
 fcntl(12, F_SETFD, FD_CLOEXEC)          = 0
 setsockopt(12, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0
 connect(12, {sa_family=AF_INET6, sin6_port=htons(5432), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = -1 EACCES (Permission denied)
 close(12)                               = 0
 socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 12
 setsockopt(12, SOL_TCP, TCP_NODELAY, [1], 4) = 0
 fcntl(12, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
 fcntl(12, F_SETFD, FD_CLOEXEC)          = 0
 setsockopt(12, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0
 connect(12, {sa_family=AF_INET, sin_port=htons(5432), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EACCES (Permission denied)
 close(12)                               = 0

Comment 2 Yann Droneaud 2012-01-05 22:10:24 UTC
But when I'm starting httpd as root using /usr/bin/httpd -k start instead of systemctl start httpd.service, everything works.

With strace I'm getting:

 socket(PF_INET6, SOCK_STREAM, IPPROTO_IP) = 12
 setsockopt(12, SOL_TCP, TCP_NODELAY, [1], 4) = 0
 fcntl(12, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
 fcntl(12, F_SETFD, FD_CLOEXEC)          = 0
 setsockopt(12, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0
 connect(12, {sa_family=AF_INET6, sin6_port=htons(5432), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = -1 EINPROGRESS (Operation now in progress)
 poll([{fd=12, events=POLLOUT|POLLERR}], 1, -1) = 1 ([{fd=12, revents=POLLOUT}])
 getsockopt(12, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
 getsockname(12, {sa_family=AF_INET6, sin6_port=htons(50963), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, [28]) = 0

The PHP application is correctly working.

Comment 3 Yann Droneaud 2012-01-05 22:14:18 UTC
In fact, my problem is related to selinux:

When starting httpd with /usr/bin/httpd -k start, error_log reports:

SELinux policy enabled; httpd running as context unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023


Instead, when started with systemctl start httpd.service, error_log reports:

SELinux policy enabled; httpd running as context system_u:system_r:httpd_t:s0

Comment 4 Yann Droneaud 2012-01-05 22:16:52 UTC
So I think the fix is to try to convince Dolibarr to connect to Postgresql using local Unix socket /tmp/.s.PGSQL.5432 instead of TCP socket 127.0.0.1:5432 or [::1]:5432.

Comment 5 Tom Lane 2012-01-05 23:04:32 UTC
Yeah, that looks like a selinux problem not a postgres problem; httpd_t ought to be allowed to make this connection.  Reassigning.

Comment 6 Daniel Walsh 2012-01-06 15:43:31 UTC
What AVC's are you seeing? in /var/log/audit/audit.log.

I think the problem is the Postgesql sockets are in /tmp rather then in /var/run or /run.

Comment 7 Yann Droneaud 2012-01-06 15:58:02 UTC
(In reply to comment #6)
> What AVC's are you seeing? in /var/log/audit/audit.log.
> 

Oh, I thought I would see them with dmesg (or in /var/log/messages).

But here they are:

type=SERVICE_START msg=audit(1325715234.546:1332): user pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg=': comm="httpd" exe="/bin/systemd" hostname=? addr=? terminal=? res=success'

type=AVC msg=audit(1325715237.030:1333): avc:  denied  { name_connect } for  pid=30650 comm="httpd" dest=5432 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:postgresql_port_t:s0 tclass=tcp_socket

type=SYSCALL msg=audit(1325715237.030:1333): arch=c000003e syscall=42 success=no exit=-13 a0=b a1=7f2523a7e300 a2=1c a3=7fffbe735a58 items=0 ppid=30648 pid=30650 auid=4294967295 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4294967295 comm="httpd" exe="/usr/sbin/httpd" subj=system_u:system_r:httpd_t:s0 key=(null)

type=AVC msg=audit(1325715237.030:1334): avc:  denied  { name_connect } for  pid=30650 comm="httpd" dest=5432 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:postgresql_port_t:s0 tclass=tcp_socket

type=SYSCALL msg=audit(1325715237.030:1334): arch=c000003e syscall=42 success=no exit=-13 a0=b a1=7f2523a7dcd0 a2=10 a3=7fffbe735a58 items=0 ppid=30648 pid=30650 auid=4294967295 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4294967295 comm="httpd" exe="/usr/sbin/httpd" subj=system_u:system_r:httpd_t:s0 key=(null)


etc.

> I think the problem is the Postgesql sockets are in /tmp rather then in
> /var/run or /run.

It's not a problem with Unix domain socket: it seems it's working fine with them.
But when using TCP socket to connect to localhost, Apache HTTPd get is denied rights to connect to 127.0.0.1:5432 or [::1]:5432.

Comment 8 Daniel Walsh 2012-01-06 18:50:50 UTC
audit2allow -i /tmp/t


#============= httpd_t ==============
#!!!! This avc can be allowed using one of the these booleans:
#     httpd_can_network_connect, httpd_can_network_connect_db

allow httpd_t postgresql_port_t:tcp_socket name_connect;

If I looked at the setroubleshoot I see something like:

sealert -a /tmp/t
100% donefound 1 alerts in /tmp/t
--------------------------------------------------------------------------------

SELinux is preventing /usr/sbin/httpd from name_connect access on the tcp_socket .

*****  Plugin catchall_boolean (47.5 confidence) suggests  *******************

If you want to allow HTTPD scripts and modules to connect to the network using any TCP port.
Then you must tell SELinux about this by enabling the 'httpd_can_network_connect' boolean.
Do
setsebool -P httpd_can_network_connect 1

*****  Plugin catchall_boolean (47.5 confidence) suggests  *******************

If you want to allow HTTPD scripts and modules to connect to databases over the network.
Then you must tell SELinux about this by enabling the 'httpd_can_network_connect_db' boolean.
Do
setsebool -P httpd_can_network_connect_db 1

*****  Plugin catchall (6.38 confidence) suggests  ***************************

If you believe that httpd should be allowed name_connect access on the  tcp_socket by default.
Then you should report this as a bug.
You can generate a local policy module to allow this access.
Do
allow this access for now by executing:
# grep httpd /var/log/audit/audit.log | audit2allow -M mypol
# semodule -i mypol.pp

# semanage boolean -l | grep http | grep database
httpd_can_network_connect_db   (off  ,  off)  Allow HTTPD scripts and modules to connect to databases over the network.



Bottom line.  Set the httpd_can_network_connect_db boolean and your good to go.

# setsebool -P httpd_can_network_connect_db 1

Comment 9 Tom Lane 2012-01-06 20:55:49 UTC
(In reply to comment #8)
> Bottom line.  Set the httpd_can_network_connect_db boolean and your good to go.
> # setsebool -P httpd_can_network_connect_db 1

That will allow httpd to connect to anything at all, right?

That's certainly enough to solve the immediate problem, but I wonder whether it would be sensible to provide another, narrower-in-scope boolean that allows connections to only a few "likely" ports, such as 5432 for postgres and 3306 for mysql.  In particular I don't like the idea that there's no way to allow database access without also turning httpd into a potential spam engine (ie, with the ability to connect to remote port 25).

Comment 10 Yann Droneaud 2012-01-09 11:13:45 UTC
(In reply to comment #8)

Thanks for the audit.log analysis and suggestions.

But I think there's still a bug in the documentation: in the release-notes from F15 to F16 there's nothing about this new restriction.
My Apache HTTPd / PHP / PostgreSQL setup was working fine in F14 but not after upgrading which was a bit disturbing.

In the meantime, I have reported a bug against dolibarr and fixed it by using the Unix domain socket for local connections
https://doliforge.org/tracker/?func=detail&aid=270&group_id=144

Comment 11 Daniel Walsh 2012-01-09 16:03:11 UTC
httpd_can_network_connect_db only allows you to connect to the "Database ports"  not to the mail ports.

sesearch -A -s httpd_t -C -c tcp_socket| grep connect_db
WARNING: Policy would be downgraded from version 27 to 26.
DT allow httpd_t postgresql_port_t : tcp_socket { recv_msg send_msg name_connect } ; [ httpd_can_network_connect_db ]
DT allow httpd_t mssql_port_t : tcp_socket name_connect ; [ httpd_can_network_connect_db ]
DT allow httpd_t postgresql_t : tcp_socket recvfrom ; [ httpd_can_network_connect_db ]
DT allow httpd_t netlabel_peer_t : tcp_socket recvfrom ; [ httpd_can_network_connect_db ]
DT allow httpd_t oracle_port_t : tcp_socket name_connect ; [ httpd_can_network_connect_db ]
DT allow httpd_t mysqld_port_t : tcp_socket { recv_msg send_msg name_connect } ; [ httpd_can_network_connect_db ]
DT allow httpd_t firebird_port_t : tcp_socket name_connect ; [ httpd_can_network_connect_db ]
DT allow httpd_t mysqld_t : tcp_socket recvfrom ; [ httpd_can_network_connect_db ]


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