skip to Main Content

I changed my server; the old one ran Centos 8, the new runs Ubuntu 20.4. Now my php scripts have a problem with permissions — why?

Example:

current user: root
script was executed under user: nobody

Message: fopen(/tmp/RebuildCat_sequence.cnt): failed to open stream: Permission denied

Actually this file is owned by nobody, so I should not get this warning at all:

CS-1 01:47:22 :/tmp# ls -latr /tmp/RebuildCat_sequence.cnt
--wxrwxrwT+ 1 nobody nogroup 480 Oct 23 00:02 /tmp/RebuildCat_sequence.cnt

This php file is called by cron (root), as a rule, and as I noticed that some similar cron triggered files are owned by systemd-timesync, I issued

setfacl -m u:systemd-timesync:rwX /tmp
setfacl -m u:nobody:rwX /tmp

and even

setfacl -R -m u:nobody:rwX /tmp
setfacl -R -m u:systemd-timesync:rwX /tmp

to no avail. How do I understand this?

In my understanding both users systemd-timesync and nobody should be able to read and write files in /tmp without problem due to acl. I think someone has to educate me here.

/tmp resides on /dev/md2

    CS-1 01:32:34 :/tmp# tune2fs -l /dev/md2 | grep "Default mount options:"
    Default mount options:    user_xattr acl

No problem here, I guess.

CS-1 01:46:09 :/tmp# getfacl /tmp
getfacl: Removing leading '/' from absolute path names
# file: tmp
# owner: root
# group: root
# flags: --t
user::rwx
user:systemd-timesync:rwx
user:nobody:rwx
group::rwx
mask::rwx
other::rwx

Looks OK to me, as well. Clueless.

Addendum

OK, I set chmod 777 /tmp, but still I get a PHP error fopen(/tmp/RebuildCat_sequence.cnt): failed to open stream: Permission denied, but file_put_contents works with 777 — how do I understand this? Why does fopen throw an error, but file_put_contents does not?

2

Answers


  1. Chosen as BEST ANSWER

    Well, it looks like I was kind of silly. I'm sure I double checked permissions on /tmp in WinSCP (1777), but I am unsure if I did it in the console.

    Now I issued chmod 777 /tmp in the console and there it is! This problem is gone. chmod 666 /tmp reintroduces the problem. chmod 676 /tmp is OK as well.

    I googled quite a bit to educate myself about this topic, but frankly I don't understand it. In particular why did I have the problem in the first place and why did ACL not solve the problem? I'd appreciate some enlightenment.


  2. Alas, chmod 777 /tmp in the console is not the answer. It is much more complicated than that. So I wasn’t silly at all.

    How to reproduce?

    In my case, I have 2 docker PHP containers writing to a number of case specific log files, one of them using apache, the other nginx. Both have a mapping /tmp:/tmp, so we can look at a file from the host or from inside a container.

    From inside the containers, the owner is apache:apache if created in the apache container or nginx:nginx in the nginx container, but from the host’s perspective it is systemd-timesync:systemd-journal for the same file in both cases.

    Of course, the apache container does not have a user nginx and vice versa (neither does the host). So if my PHP script wants to write to a file created by the other container, I have said permission problem.

    Fix

    The remedy is easy, if at creation time the owner is changed to nobody and permissions to 666.

    If not, we cannot change the owner from the other container and get failed to open stream: Permission denied. See https://serverfault.com/questions/772227/chmod-not-working-correctly-in-docker (also see the discussion about changing permissions from host via system call below).

    So I wrote a wrapper function str_to_file to add this manipulation:

    function str_to_file($str, $filename= "/tmp/tmp.txt", $mode="a+") {
        if (!file_exists($filename)){
            touch($filename);           # create file
            chmod($filename, 0666);     # the owner can chmod
            chown($filename, 'nobody'); # the owner can chown
        } # if (!file_exists($filename))
    
        $mode = $mode == 'w'
            ? LOCK_EX
            :  FILE_APPEND | LOCK_EX;
    
        file_put_contents($filename, $str . PHP_EOL, $mode);
    } # str_to_file
    

    This works for both the apache and nginx containers.

    Explanation

    How did I get into this mess anyway?

    It looks like either I didn’t mess it up when on CentOS, so in this case most probably it has nothing to do with my switch to Ubuntu. I cannot remember what I did but I don’t remember I had this kind of permission problem on CentOS.

    Or CentOS handles files created in a container differently than Ubuntu. I am sure I never saw a user systemd-timesync:systemd-journal on CentOS. Unfortunately I cannot investigate without too much effort what user CentOS would substitute from the host point of view and which consequences this has.

    Oh wait, I remember I do have another server running PHP and nginx on CentOS. Creating a file in /tmp from within the container reveals that the owner from both inside the container and from the host is nobody. So there is a significant difference between both Linux versions.

    What’s more, this insight explains why I experienced this permission problem only after the switch from CentOS to Ubuntu, to which I was forced due to the fact that my provider does not offer CentOS anymore for obvious reasons.

    By the way, I first tried the CentOS substitutes AlmaLinux and RockyLinux with bad results of different nature which finally forced me to use Ubuntu. This switch in turn revealed lots of problems, this one being the last, which cost me several weeks so far. I hope that this nightmare ends now.

    Acting from cron, the apache version is and was used exclusively, so no problem here.

    Testing from the browser lately, I switched by chance and for no particular reason from the apache version to the nginx version and vice versa, creating those described problems.

    Actually I don’t know why the containers write on behalf of those users. The user of the container is root in both cases, as is standard with docker. I guess it is the browser engine which introduces these users.

    Interestingly, when trying to change permissions and ownership via system call after creation, I failed, if I remember correctly, although the user then should be root and root should be capable of doing that.

    It turns out that on apache the system user [system(‘whoami’)] is not root but apache, but the file owner is apache where as on nginx the system user is nobody and the file owner is nginx. So changing permissions with system should work on apache [system("chmod 0666 $filename"); system("chown nobody:nobody $filename");], but not on nginx. Alas, it does not work on apache either.

    Quick check in apache container:

    /tmp # whoami
    root
    /tmp # ls -la *6_0.ins
    -rw-r--r--    1 apache   apache         494 Nov 14 18:25 tmp_test_t6_0.ins
    /tmp # su apache chmod 0666 tmp_test_t6_0.ins
    This account is not available
    

    Sorry, I can’t understand this. And no idea about ACL.

    apache vs. nginx

    Why do I use both web server versions in the first place?

    Well, the process I invoke processes random data which may take a long time, so chances are that nginx times out. This is a well-known nginx feature.

    Despite all my studies and obvious instructions, I could not manage nginx to behave. Geez!

    Finally, as an appropriate workaround, I introduced apache, which does not have this problem. For decent runtimes it makes no difference, of course.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search