6

I have an old "PHPDBG" function that lets me "printf" to a text file.

I've had PHPDBG.inc "since forever" (at least since PHP 4.x days), but it doesn't seem to be working in my current configuration (ubuntu18, Apache 2.4.29 and PHP 7.2).

Specifically:

  • I can't open the file ($fp is null) ...
  • /tmp/PHPDBG.txt never gets created (because of the fopen failure)
  • /tmp should be world-writable ... and ...
  • I don't seem to be able to get a PHP error in the Apache error.log, or get anything meaningful from either error_get_last() or $php_errormsg.

Here is the test code:

test.php:

<?php
  function PHPDBG ($s) {
    $fp = fopen ("/tmp/PHPDBG.txt", "a");
    if ($fp) {
      // Successful open ... but nothing written!
      fputs($fp, $s . "\n");
      fclose($fp);
    } else {
      echo "<h3>FILE OPEN ERROR</h3>\n";
      echo "<p>" . print_r(error_get_last()) . "</p>\n";
      echo "<p>" . $php_errormsg . "</p>\n";
    }
  }

  PHPDBG('>>Hello');
  phpinfo();
  PHPDBG('<<Goodbye');
 ?>

Questions:

Q1: Any idea what might be wrong with $fp = fopen ("/tmp/PHPDBG.txt", "a");?

Q2: What can I do to get a meaningful error message if "fopen()" fails?


Additional info: assuming error_get_last() is returning "1: EPERM 1 /* Operation not permitted */", then I manually created /tmp/PHPDBG.txt, chmod +rw, and tried "test.php" again. No-go: I got exactly the same results: $fp was null, no meaningful error messages, and /tmp/PHPDBG.txt was unchanged:

root@ubuntu18:/tmp# umask 0
root@ubuntu18:/tmp# touch PHPDBG.txt
root@ubuntu18:/tmp# ls -l PHPDBG.txt
-rw-rw-rw- 1 root root 0 Mar  5 18:13 PHPDBG.txt
 <= Re-ran test here... failed exactly like before...
root@ubuntu18:/tmp# ls -l PHPDBG.txt
-rw-rw-rw- 1 root root 0 Mar  5 18:13 PHPDBG.txt

Additional notes:

  1. Ibu pointed out a stupid typo in the original version of the code I posted. Whoops! It crept in at the last minute, the typo WASN'T the problem. I'm still not able to "fopen()" a file in /tmp and write to it from PHP 7.2. I used to be able to do this in earlier (MUCH earlier!) versions of PHP.

  2. I just double-checked: I AM able to write to the file if it happens to be in the local directory:

    // $fp = fopen ("/tmp/PHPDBG.txt", "a");  // Opens, but fails to write anything
    $fp = fopen ("PHPDBG.txt", "a");  // Works OK
    

Q: Why????

Update

The reason "it used to work" is that systemd was introduced to (newer versions of) Linux, bringing with it "PrivateTmp".

My workaround was to disable this "feature" for Apache/PHP. I edited /etc/systemd/system/multi-user.target.wants/apache2.service as follows:

[Service]
...
PrivateTmp=true  <-- Changed this to "false"

Additional notes are here.

paulsm4
  • 114,292
  • 17
  • 138
  • 190
  • 1
    I know it may be stupid, but sometimes it's the most obvious things that we overlook. Since you can open and modify the file when located in the local directory: did you check and double check that the path to the file is the correct one, bot the directory and the file have the required read and write permissions AND that the user that owns both the directory and the file is the same and is the same as the user your PHP instance runs on? – Javier Larroulet Mar 06 '19 at 17:29
  • I finally found out why it "wasn't working". PHP uses Apache, Apache uses Systemd ... and systemd has a neat "feature" which I'd never heard of: "PrivateTmp". So when I opened `/tmp/PHPDBG.txt`, "systemd" surreptitiously opened `/tmp/systemd-private-c6f7629309e647818680f8a6ee1105d6-apache2.service-lGKGc6/tmp/PHPDBG.txt` behind my back instead. I only discovered it - accidentally - by doing a "find" from the root folder... Sigh... – paulsm4 Mar 06 '19 at 17:47
  • 1
    what's important is that you got it to work :) ... didn't know that systemd feature either – Javier Larroulet Mar 06 '19 at 17:48

3 Answers3

6

I found the file that didn't seem to be created:

  1. PHP code: $fp = fopen ("/tmp/PHPDBG.txt", "a");

  2. Expected location: /tmp/PHPDBG.txt.

  3. Actual location: /tmp/systemd-private-c6f7629309e647818680f8a6ee1105d6-apache2.service-lGKGc6/tmp/PHPDBG.txt

Relevant links:

So it sounds like this is some kind of systemd "feature" (Grrr!!!!). Which explains why it "used to work" (in previous versions of Apache, PHP and Linux).

Workaround

I edited /etc/systemd/system/multi-user.target.wants/apache2.service:

[Service]
...
PrivateTmp=true  <-- Changed this to "false"
paulsm4
  • 114,292
  • 17
  • 138
  • 190
  • 1
    I thought it would be something in link with some form of security feature but I just didn't expect such an ugly path. I saw the systemd sub-folders but did not think of looking further yet we can see one that says "apache2". Oh well... – Alexis Wilke Jun 15 '20 at 20:24
  • 2
    I share your sentiments. Hopefully my post saved you a bit of time and trouble :) – paulsm4 Jun 15 '20 at 23:08
3

Your condition is reversed: if (!$fp).

You are saying if not handle, then write to the file. It should be the opposite.

<?php
  function PHPDBG ($s) {
    $fp = fopen ("/tmp/PHPDBG.txt", "a");
    if ($fp) { // fixed condition.
      fputs($fp, $s . "\n");
      fclose($fp);
    } else {
      echo "<h3>FILE OPEN ERROR</h3>\n";
      echo "<p>" . print_r(error_get_last()) . "</p>\n";
      echo "<p>" . $php_errormsg . "</p>\n";
    }
  }

  PHPDBG('>>Hello');
  phpinfo();
  PHPDBG('<<Goodbye');
?>
Ibu
  • 42,752
  • 13
  • 76
  • 103
  • I've been debugging for hours, and made some last minute changes to make it "more presentable". At which point I introduce the typo. Sorry about that, and thank you for your response. BUT... – paulsm4 Mar 06 '19 at 03:16
  • ... Please see my update. Even after fixing the typo, I still have the original problem: **I CANNOT WRITE TO THE FILE**. No error ... but nothing happens. Again - this is "old code". Q: Did "something change" in newer versions of PHP regarding "fopen()" and writing to the filesystem? Q: Any idea why the file isn't being written to?, or what I can do about it? – paulsm4 Mar 06 '19 at 03:17
-2

The real problem is a permissions problem.

When the private tmp file is created, it has permissions ONLY for root.

The permissions for httpd should be for httpd and so on.

Is this a systemd configurable item? Seems like systemd has solved a problem only to prevent actual use for which the problem existed. /tmp for httpd should be writeable by httpd but it is not.

  • No - the real problem is that systemd introduced an unexpected (to me, at least) level of complexity in the behavior of "/tmp". Look [here](https://unix.stackexchange.com/a/489662/431327) or [here](https://systemd.io/TEMPORARY_DIRECTORIES/). For the second link, you'll have to scroll down a bit to "Common Namespace" to see the rationale for this change. Then you have to scroll down even further to "PrivateTmp" for the implications for httpd (and any other system service). – paulsm4 Jan 17 '21 at 00:06
  • Hmm. Sounds like PrivateTmp is an useful idea at the very least. I recently had /tmp used as a vehicle for hijakcing my server. So if there is a PrivateTmp that is locked down by process but is still accessible and persistable as a location, it would help avoid scenarios where a server can be hijacked. My personal opinion though is that maybe /tmp is overused and is accessible by the world. Maybe we should start having specific directories under the control of our PHP programs that we use for debugging like this. Just a thought. – A Concerned Linux Denizen Nov 07 '21 at 19:18
  • Been doing this for over 30 years and I myself am guilty of having used /tmp. But I find as time wears on, I've used /tmp less and used a local locked down folder more often. Could it be that it's finally time to retire the use of /tmp by user processes? The attack vector in my most recent scenario used a first process to write files to /tmp which would eventually be cleared out presumably and then to use a second process to execute the /tmp files created. This injected a http proxy into my gitlab server and added cron entries and among other things. Took me a while to get it cleaned up. – A Concerned Linux Denizen Nov 07 '21 at 19:19