4

I am trying to COPY a file into a table in PostgreSQL. The table owner is postgres and the file owner is postgres.

The file is in /tmp.

Still I am getting the error message:

could not open file "/tmp/file" for reading: Permission denied

I don't understand what I am doing wrong as all the posts I've found say that if I have the file in /tmp and owner is postgres then the COPY command should work.

Craig Ringer
  • 307,061
  • 76
  • 688
  • 778
user1439690
  • 659
  • 1
  • 11
  • 26
  • 1
    Please add the syntax you used and the permissions on the file. – Miljen Mikic Sep 05 '12 at 06:31
  • Yep, editing your answer to mention: PostgreSQL version, how you installed Pg, the OS and version, the file permissions (`ls -l filename` and `ls --lcontext filename`), the table permissions (`\d+ tablename` in `psql`), and the exact text of the command you ran + the error message would be helpful. – Craig Ringer Sep 05 '12 at 09:20

2 Answers2

6

A guess: You are using Fedora, Red Hat Enterprise Linux, CentOS, Scientific Linux, or one of the other distros that enable SELinux by default.

Either and on your particular OS/version the SELinux policies for PostgreSQL do not permit the server to read files outside the PostgreSQL data directory, or the file was created by a service covered by a targeted policy so it has a label that PostgreSQL isn't allowed to read from.

You can confirm whether or not this is the problem by running, as root:

setenforce 0

then re-testing. Run:

setenforce 1

to re-enable SELinux after testing. setenforce isn't permanent; SELinux will be automatically re-enabled on reboot anyway. Disabling SELinux permanently is not usually a good solution for issues like this; if you confirm the issue is SELinux it can be explored further.


Since you have not specified the OS or version you are using, the PostgreSQL version, the exact command you're running, ls -al on the file, \d+ on the table, etc, it's hard to give any more detail, or to know if this is more than a guess. Try updating your answer to include all that and an ls --lcontext of the file too.

Craig Ringer
  • 307,061
  • 76
  • 688
  • 778
  • 2
    @user1439690 Great, now you know it's SELinux. `setenforce` is a *temporary* measure. The correct fix is to set the SELinux context of the file. See https://access.redhat.com/knowledge/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Security-Enhanced_Linux/chap-Security-Enhanced_Linux-SELinux_Contexts.html – Craig Ringer Sep 05 '12 at 22:58
1

COPY with a file name instructs the PostgreSQL server to directly read from or write to a file. The file must be accessible by the PostgreSQL user (the user ID the server runs as) and the name must be specified from the viewpoint of the server. (source: postgresql documentation)

So the file should be readable (or writable) by the unix user under which postgresql server is running (i.e not your user!). To be absolutly sure, you can try to run sudo -u postgres head /tmp/test.csv (assuming you are allowed to used sudo and assuming the database user is postgres).

If that fails, it might be an issue related to SELinux (as mentioned by Craig Ringer). Under the most common SELinux policy (the "targeted" reference policy), used by Red Hat/Fedora/CentOS, Scientific Linux, Debian and others... the postgresql server process is confined : it can only read/write a few file types.

The denial might not be logged in auditd's log file (/var/log/audit/audit.log) due to a donaudit rule. So the usual SELinux quick test apply e.g: stop SELinux from confining any process by running getenforce;setengorce 0;getenforce, then test postgresql's COPY. Then re-activate SELinux by running setenforce 1 (this command modify the running state, not the configuration file, so SELinux will be active (Enforcing) after reboot.

The proper way to fix that is to change the SELinux context of the file to load. A quick hack is to run:

chcon -t postgresql_tmp_t /tmp/a.csv

But this file labelling will not survive if hte filesystem is relabel or if you create a new file. You will need to create a directory with an SELinux file context mapping :

which semanage || yum install policycoreutils-python
semanage fcontext -a -t postgresql_tmp_t '/srv/psql_copydir(/.*)?'
mkdir /srv/psql_copydir
chmod 750 /srv/psql_copydir
chgrp postgres /srv/psql_copydir
restorecon -Rv /srv/psql_copydir
ls -Zd /srv/psql_copydir

Any file created in that directory should have the proper file context automatically so postgresql server can read/write it.

(to check the SELinux context under which postgres is running, runps xaZ | grep "postmaste[r]" | grep -o "[a-z_]*_t", which should print postgresql_t. To list the context types to which postgresql_t can write, use sesearch -s postgresql_t -A | grep ': file.*write'. the command sesearch belong to the setools-console RPM package).

Franklin Piat
  • 3,952
  • 3
  • 32
  • 45