Bug 135068

Summary: Apache/PHP can't communicate with local postgres with selinux-policy-targeted
Product: [Fedora] Fedora Reporter: David Hollis <dhollis>
Component: selinux-policy-targetedAssignee: Daniel Walsh <dwalsh>
Status: CLOSED RAWHIDE QA Contact:
Severity: low Docs Contact:
Priority: medium    
Version: rawhideCC: tgl
Target Milestone: ---   
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2004-10-18 20:19:25 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description David Hollis 2004-10-08 13:29:04 UTC
From Bugzilla Helper:
User-Agent: Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041002
Firefox/0.10.1

Description of problem:
I have Apache, PHP & Postgres on my laptop for developing some web
apps.  After reenabling selinux recently with the targeted policy in
enforcing mode, my PHP scripts can't communicate with postgres.  It
appears to be due to the security context on the postgres socket,
/tmp/.S.PGSQL.5432.  Changing into permissive mode lets everything
work once again, but with the continual 'avc denied' messages in
syslog as expected. 

Oct  8 09:26:22 dhollis-lnx kernel: audit(1097241982.919:0): avc: 
denied  { write } for  pid=4745 exe=/usr/sbin/httpd name=.s.PGSQL.5432
dev=dm-0 ino=966674 scontext=root:system_r:httpd_t
tcontext=root:object_r:tmp_t tclass=sock_file


[dhollis@dhollis-lnx ~]$ ls -Z /tmp/.s.PGSQL.5432
srwxrwxrwx  postgres postgres root:object_r:tmp_t             
/tmp/.s.PGSQL.5432

httpd-2.0.52-2
php-4.3.9-2
postgresql-7.4.5-3
selinux-policy-targeted-1.17.28-2


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

How reproducible:
Always

Steps to Reproduce:
1. Configure selinux with targeted policy in enforcing mode
2. Write a PHP script to talk to postgres
3. View script - database connection fails
    

Actual Results:  Database connection fails, avc denied messages in
/var/log/messages

Expected Results:  Database connection succeeds, life goes on.

Additional info:

Comment 1 Colin Walters 2004-10-08 13:55:08 UTC
This one is rather difficult to fix without pulling postgres into the
targeted policy.

One workaround might be to change postgres to put its socket somewhere
like /var/run/postgresql/, and label that directory specially, and
allow Apache access to that type.

Hm, actually from looking at the current policy it appears Postgresql
should be doing just that - but maybe that's only on Debian?  

Comment 2 Tom Lane 2004-10-08 15:10:36 UTC
I disagree with moving the socket.  That has been proposed and
rejected repeatedly by the upstream community, mainly on
backwards-compatibility grounds, and so if we do it we are going to be
effectively protocol-incompatible with clients built from source
distributions.  (Yeah, I know Debian is being deliberately
incompatible.  With my upstream-maintainer hat on, I don't like them
either.)

Why exactly is SELinux forbidding writes to globally writable objects
in /tmp?  That seems to me to be well beyond the bounds of reasonable
paranoia.

Comment 3 Colin Walters 2004-10-08 15:23:36 UTC
I don't understand why it has to be protocol-incompatible?  Can't the
client libraries be modified to first look in /var/run, and if that
fails, then look in /tmp?  This is something that should be upstream
anyways.

The SELinux policy is forbidding access to random objects in /tmp
because they could be anything - they could be one of your email files
that your editor has open, for example.  A buggy postgresql daemon
could then arbitrarily overwrite your email composition.  Not to
mention things like the X connection socket, ssh-agent sockets, etc etc.


Comment 4 Tom Lane 2004-10-08 15:56:27 UTC
Indeed ... so are you going to insist that all those other sockets be
moved?  I can believe that this policy is reasonable for ordinary
files in /tmp.  I disagree that it is reasonable for sockets.

As for your compatibility argument, "we have to modify the clients" is
pretty much the definition of "we broke the protocol", in my book.

Comment 5 Colin Walters 2004-10-08 16:08:28 UTC
The X socket should probably be moved too, yes.  The ssh-agent socket
is only used for communication between a single userid, so it's not a
problem.

As for compatibility - the point is that you change the client
libraries and the server at the same time.  In order for this to fail,
someone would have to recompile the client libraries from an older
upstream version, but still use a newer server.   For that we can just
say "Not supported".  Especially for RHEL where we only support the
binaries we ship.


Comment 6 Tom Lane 2004-10-08 17:31:21 UTC
I don't think you got my point before.  Upstream is not changing;
they've had this discussion already, and if Debian couldn't persuade
them to change, Red Hat won't either.  So your dismissal of the issue
as "older upstream versions" isn't going to fly.  Yes, we can put
blinders on and say that we only support our own binaries, but there
is still going to be a real compatibility problem.

Another issue is that the SELinux policy breaks ordinary PG
builds-from-source, or externally supplied RPMs, regardless of what we
do to the version we ship.  Since there are a lot of
application-visible incompatibilities between different major PG
releases, people frequently want to run a version that is not what we
include in Fedora or RHEL --- it could be either older or newer. 
Calling that unsupported isn't going to stop people from needing to do
it.

So I really think we have to adjust the policy.  You didn't respond to
my question about why sockets need this much protection.  I see the
point that sloppily written applications might put world-writable
files into /tmp unintentionally, but I really doubt that any app is
going to create a world-writable socket there without knowing exactly
what it is doing.

Comment 7 Daniel Walsh 2004-10-08 17:38:29 UTC
Apache becomes compromized, hacker gets a shell running as user
apache. The Xserver has a world R/W socket in /tmp.

Hacker uses this socket to break further into the system.

In a tight SELinux world SELinux would have prevented this further access.

Dan

Comment 8 Tom Lane 2004-10-08 18:38:38 UTC
Exactly how does it get in the hacker's way if the world-writable
socket is kept somewhere else than /tmp?  It's equally world-writable
either place, so I don't see that a policy that discriminates against
sockets in /tmp is stopping anything.

Comment 9 Colin Walters 2004-10-08 19:03:08 UTC
The way SELinux works is it assigns "types" to files (and in fact all
objects).  When a new file is created, by default the assigned type
will be inherited from the parent directory it's created in.  So when
a process creates a file in /tmp (which has type tmp_t), the file will
by default also get the tmp_t type.  tmp_t is very generic, and is
used for any random application that creates a file in /tmp.

If the file is moved into /var/run/postgresql, which would have a type
like postgresql_var_run_t, then the newly created socket would inherit
that type, and we could grant Apache access to *just*
postgresql_var_run_t, not all of tmp_t, which is a much wider set of
files.

Another alternative is to patch postgresql to assign the type itself -
but that's problematic for a number of reasons.  Simply moving the
socket is far easier.  Does that make sense?

As for upstream - maybe Debian alone couldn't push this change, but it
seems plausible to me that Debian and Red Hat together could.

Also, SELinux isn't breaking postgresql here.  We could quite easily
grant Apache the requisite permissions to read the tmp_t socket.  The
point is that it's a very bad idea from a system security standpoint.


Comment 10 Tom Lane 2004-10-08 19:27:23 UTC
Frankly I'd prefer the assign-the-type patch to moving the socket.

None of this has convinced me that you have good reasons for
preventing access to sockets in /tmp.  If an application is putting a
world-writable socket in /tmp, that presumably means that it *wants*
to receive data from other processes on the same machine.  Your
arguments seem to revolve around the notion that it's a good idea to
shut down interprocess communication against the express design intent
of the applications involved, and I just don't buy that.  (Am I going
to have to explicitly security-enable every program I write that needs
to talk to Postgres?  No thanks.)  I am even less convinced that
putting the sockets somewhere else represents a gain in system
security.

I can see the value of being able to attach a separate security type
to the postgres socket, for those who *do* want draconian restrictions
on interprocess communication, but it does not follow that we have to
move the socket to make that happen.  What else besides parent
directory can we use to determine object type?

Comment 11 Colin Walters 2004-10-08 19:56:40 UTC
An application that creates a socket file world-readable could simply
be misconfigured or buggy.  Or it could be compromised.  SELinux
protects your system from this.  

It is indeed a good idea to shut down socket communication paths (and
indeed all information flow) unless they are explicitly needed.  For
example, the portmap daemon has no need to talk to the postgresql
socket - but just because postgres has to make it socket
world-readable, it can.  That could be one beginning to privilege
escalation, because portmap runs with uid 0, and perhaps postgresql
does uid-based permission checking that allows root.

> What else besides parent
> directory can we use to determine object type?

The parent directory is the only source for the default.  We can give
applications the ability to explicitly relabel files, but that opens
up its own large security problems, in addition to forcing the daemon
to carry a very SELinux-specific patch.

Changing the socket directory only breaks in a very specific, and I
think quite obscure case: older client libraries and a newer server. 
The case of older client libraries and older server works, as does
newer client libraries and older server, and obviously newer client
libraries and newer server.


Comment 12 Tom Lane 2004-10-08 20:39:34 UTC
The parent directory is the *only* control knob available?  Meseems
you have a remarkably inflexible system there.

Your argument that this "only breaks older clients with a newer
server" is quite wrong, as you are ignoring all the points I made
above.  The SELinux policy breaks older servers (regardless of
client), and older clients (regardless of server), period.  If there
were no reason for anyone to want to run anything but the latest and
greatest Postgres release then maybe this would not matter, but there
are plenty of reasons to want to.

Comment 13 Colin Walters 2004-10-08 20:51:20 UTC
Simply copying the parent directory's type isn't the only option; you
can define a special type for when a particular domain (e.g.
postgresql_t) creates a new file in a directory (e.g. tmp_t).  But
this would require running postgresql in its own unique domain,
instead of simply running it as unconfined_t as it is now, which means
it's basically unaffected by SELinux.  That's what I meant with my
very first comment about pulling postgresql into the targeted policy.
We could do this - but it would be much cleaner to put it in /var/run.

How does it break older servers?  Remember, I was suggesting to modify
the client libraries to first look in /var/run, and then fall back to
/tmp.




Comment 14 Tom Lane 2004-10-08 22:00:50 UTC
It breaks older servers because they'll put their socket in /tmp,
whence their clients (old or new) will be unable to communicate with
them.

Could we pursue the other option you mentioned about giving postgres
its own domain?  How is that identified exactly, is it just on the
name of the program, or what?

Comment 15 Colin Walters 2004-10-08 22:09:39 UTC
Huh? 

New clients will first look in /var/run, not find the socket, then
fall back to /tmp.
Old clients will simply look for it in /tmp in the first place.  Where
is the problem?



Comment 16 Tom Lane 2004-10-08 22:32:57 UTC
Sure, the clients will *find* the socket just fine.  *Using* it is
where the SELinux policy breaks things.

Comment 17 Colin Walters 2004-10-09 01:48:37 UTC
I thought we were discussing the effects of this change for upstream.  

As for the SELinux policy - yes, that's true, Apache won't be allowed
to connect to a /tmp socket.  But people affected by that can either
modify the policy, or disable SELinux protection for Apache, or simply
upgrade postgres.

Comment 18 David Hollis 2004-10-13 17:45:10 UTC
So what is the easy way to grant httpd access to the socket without A)
disabling SELinux protection for httpd or B) moving the socket around,
or C) waiting for postgres to be pulled into the targeted policy?

I'm not terribly familiar with the selinux policy syntax and would
prefer to not start tweaking them with local changes and having to
maintain them every time the targeted policy is updated by RH.  I have
no problem executing a chcon on the socket to make it work properly
with postgres and httpd.  That is a tolerable workaround for the short
term.

Comment 19 Daniel Walsh 2004-10-13 22:08:54 UTC
Current targeted policy allows apache to read/write sockets in /tmp.
This is not an ideal situation and I am thinking of adding a boolean
to allow users to tighten up security.  Putting sockets and files in
/var/run/PACKAGENAME/  Makes doing SELinux policy easier, because we
can set a security context on the /var/run/PACKAGENAME directory and
then all files created in that directory will get that default
context.  Then we can setup policy to allow secured applications
(apache) to communicate with files of that type.  This is much more
difficult to do when many applications share a single directory /tmp 
for instance.