These notes were made running PostgreSQL and PL/Java on a Red Hat system, but should be applicable—with possible changes to details—on other systems running SELinux.
Anything that gets run by postgres
itself runs under a special SELinux context
with type postgresql_t
that severely limits things it can do. This is
generally good.
SELinux may prevent it from opening important files, such as
libpljava-[version].so
or pljava-[version].jar
, depending
on the SELinux contexts set on those files. The contexts can be
listed using ls -Z
.
The exact SELinux rules being applied, and the file contexts they
would allow, can be different. For example, a .so
file is considered
executable and triggers one kind of rule, while to SELinux a .jar
file
is just an ordinary file that Java is trying to open.
Whether a failure is being caused by SELinux can be determined by
searching the system log for avc: denied
messages. If that is the
problem, it can be solved in more than one way. For example:
libpljava-[version].so
to lib_t
and on
pljava-[version].jar
to usr_t
did the trick.Something in the JVM uses the sched_get{param,priority,scheduler}
system
calls, so a process of type postgresql_t
has to be given the getsched
SELinux permission. Also, for SSL connections to work, access to the
random_device
needs to be allowed. Both of these rules can be added in
a policy module:
policy_module(mod-pljava, 1.0)
require {
type postgresql_t;
type random_device_t;
}
allow postgresql_t postgresql_t : process { getsched };
allow postgresql_t random_device_t : chr_file { getattr };
If that is placed in a file pljava.te
then
make -f /usr/share/selinux/devel/Makefile
semodule -i pljava.pp
will build and install it.
As another example, suppose a PL/Java function needs to make an ssh
connection to a remote host. In the default policy, nothing running as
postgresql_t
is allowed to connect network sockets to remote ssh
ports.
Again, a policy module can do the trick:
policy_module(mod-pgsql-ssh, 1.0)
require {
type postgresql_t;
type ssh_port_t;
}
allow postgresql_t ssh_port_t : tcp_socket { name_connect };
As it stands, this is quite broad, and would allow connections to the ssh
port at any remote address, exactly what the SELinux policy was trying
to prevent. It is reportedly possible (if fiddly) to allow only connecting
to the ssh
port on the intended remote machine, using the right
melange of SELinux and iptables.
At one time, log messages saying avc: denied { execstack }
might be seen,
because Sun had released a Java distribution with a libjvm.so
with the
execstack
attribute missing entirely, which SELinux interprets to mean that
the library might need to execute code on the stack, even if it doesn't
really.
If seen, the problem can be confirmed by running
execstack -q
(manual page) on the
libjvm.so
file and seeing that it has no execstack
attribute.
Recent Java distributions have properly included the attribute, set to false, so SELinux knows the JVM will not need to execute code on the stack. Therefore, the best resolution to the issue is to upgrade to a JDK distribution that is not missing the attribute.
One of the best ways to cause a PL/Java installation to stop working, after being trouble-free for ages, is to replace or update one of the files it depends on, and forget to reapply the needed SELinux context to the file.