I'm having permissions problems when running the following PHP script as root:
#!/usr/bin/php
<?php
$ph = proc_open('whoami', [['pipe','r'],['pipe','w'],['file','/tmp/foo.bar', 'w']], $fds);
if ($ph) {
echo 'command output: ' . stream_get_contents($fds[1]);
proc_close($ph);
} else {
echo 'proc_open failed' . PHP_EOL;
}
The script itself runs fine if /tmp/foo.bar doesn't exist, or is owned by root. But if ownership is changed to another user, proc_open will fail regardless of permissions on the file.
SELinux is disabled, and we are not using ACLs. I'm using PHP 7.4.33 (I know it's old and unsupported, but it's a requirement for FreePBX) on Alma Linux 9.1.
Output:
$ ./test.php
command output: root
$ ls -lah /tmp/
total 12K
drwxrwxrwt. 18 root root 4.0K Dec 14 16:57 .
dr-xr-xr-x. 18 root root 4.0K Dec 14 16:48 ..
-rw-r--r-- 1 root root 0 Dec 14 16:57 foo.bar
$ chown admin /tmp/foo.bar
$ ./test.php
proc_open failed
$ chmod 777 /tmp/foo.bar
$ ./test.php
proc_open failed
$ ls -lah /tmp/
total 12K
drwxrwxrwt. 18 root root 4.0K Dec 14 16:57 .
dr-xr-xr-x. 18 root root 4.0K Dec 14 16:48 ..
-rwxrwxrwx 1 admin root 0 Dec 14 16:57 foo.bar
$ tail -2 /var/log/php.log
[14-Dec-2022 16:57:17 America/Toronto] PHP Warning: proc_open(/tmp/foo.bar): failed to open stream: Permission denied in /test.php on line 3
[14-Dec-2022 16:57:28 America/Toronto] PHP Warning: proc_open(/tmp/foo.bar): failed to open stream: Permission denied in /test.php on line 3
Even disregarding the fact that I'm root, group permissions should allow me full access to the file. So what's going on?
This is due to the permissions on the /tmp directory. When PHP tries to open the file for writing, it gets the EACCES error. From the documentation of open(2):
EACCES
Where O_CREAT is specified, the protected_fifos or protected_regular sysctl is enabled, the file already exists and is a FIFO or regular file, the owner of the file is neither the current user nor the owner of the containing directory, and the containing directory is both world- or group-writable and sticky. For details, see the descriptions of /proc/sys/fs/protected_fifos and /proc/sys/fs/protected_regular in proc(5).
/tmp has the sticky bit set so that anyone can create files there, but users can only delete their own files. Although root can bypass this deletion restriction, it can't bypass the above check in open().
Ok I tried this in a different directory than /tmp, as suggested in comments, and it worked as expected. Using that to hone my search terms I was able pretty quickly to find this U&L answer. Beginning with kernel 4.19 the fs.protected_regular kernel parameter was made available. This parameter:
Disallows open of FIFOs or regular files not owned by the user in world writable sticky directories, unless the owner is the same as that of the directory or the file is opened without the O_CREAT flag. The purpose is to make data spoofing attacks harder.
Apparently it's enabled by default. So because /tmp is world-writable and sticky, I can't touch files that aren't mine – even if I'm root. For the record, if I have to disable this feature:
sysctl fs.protected_regular=0
echo 'fs.protected_regular=0' > /etc/sysctl.d/90-writabletemp.conf
But I'll be better off trying to work around it in the code somehow.
Related
In PHP, I'm receiving this: Warning: fopen(/tmp/mydir/file.txt): failed to open stream: No such file or directory when calling fopen ('/tmp/mydir/file.txt', "r");
However:
cd /tmp
ls -l .
drwxrwxr-x 2 user 4.0K Aug 19 14:09 mydir
ls -l mydir
-rw-rw-r-- 1 user 41K Aug 19 14:09 file.txt
If I try to do print_r(scandir('/tmp/')); I get an empty array. Doing print_r(scandir('/tmp/mydir/')); I get failed to open dir: No such file or directory. However, doing print_r(scandir('/home/user/')); returns failed to open dir: Permission denied. For some reason, directories in /tmp show no such file or directory, even though they exist. It's also not a permission issue, and if it were, it would (should) produce the permission error.
What am I missing here? Or is this a known bug?
It could be an issue with PrivateTmp feature: it mounts /tmp and /var/tmp as visible only to that process so every process sees a different virtual /tmp folder.
If you want to change it, you can create /etc/systemd/system/php-fpm.service.d/private-tmp.conf with contents:
[Service] PrivateTmp=false
Source for the fix: Content of /tmp is not visible from PHP-FPM
I'm trying to write a simple online music player to improve my programming.
I have a server running CentOS 6.5, with an external hard disk containing all my files. I mounted my storage partition to /mnt/storage and my music is in /mnt/storage/cascornelissen/Muziek, which has the following permissions:
drwxrwxr-x 19 cascornelissen ftpusers 4096 Nov 4 14:43 Muziek
Then I have a simple httpd webserver, hosting the project in /var/www/html/melodi, which constains a softlink to the Muziek directory mentioned earlier:
lrwxrwxrwx 1 root ftpusers 34 Jan 26 22:31 music -> /mnt/storage/cascornelissen/Muziek
I want to use PHP's glob to list all the files but that returned an empty array. So I tried scandir("music") but it returns the following error:
Warning: scandir(music): failed to open dir: Permission denied in /var/www/html/melodi/index.php on line 42
Any ideas on how to fix this permissions issue?
Try this:
chmod ugo+x /mnt /mnt/storage /mnt/storage/cascornelissen
Probably some part of your path will not allow entry for your Apache user. Allowing entry to a directory means adding x or execute permissions to the directory.
Explanation
# create path a/b
mkdir -p a/b
ls a/b # this works
# now remove all permissions for a
chmod 000 a
ls a/b # ls: cannot access a/b: Permission denied
# but why, we should still have permission for b??
# Now, lets add x permission for a:
chmod ugo+x a
ls a/b # works again
ls a # ls: cannot open directory a: Permission denied
# So, we cannot list contents of a, but we can
# access a/b *through* a
So, execute permission or x for a directory means we can access the path below it, even if we cannot read the contents of the directory itself. In your case, Apache needs permission to "walk through" /mnt/storage/cascornelissen even though it will not read any files until it reaches Muziek.
When I try to shell_exec('/home/user/scripts/./script') I get the following error:
terminate called after throwing an instance of 'boost::filesystem3::filesystem_error'
what(): boost::filesystem::create_directory: Permission denied: "/.script"
Aborted (core dumped)
shell_exec('whoami') returns www-data on my web-facing php script.
The permissions to the directory and file are exactly the same:
-rwxrwxr-x 1 user123 group456 8246 Jun 25 06:10 script
drwxrwxr-x 7 user123 group456 4096 Jul 10 14:54 .
In fact I can shell_exec('touch /home/user/scripts/test') and it will create the file with no problem.
$ ls -l /home/user/scripts/test
-rw-r--r-- 1 www-data www-data 0 Jul 10 14:54 test123
This is how my groups are set up for each user:
$ groups user123
user123 : group456
$ groups www-data
www-data : group456
Why am I getting this error?
The script your running has a typo: it's trying to make the folder /.script in the root folder instead of ./script (relative path).
Are you trying to execute script at /home/user/scripts/./script then you should run as shell_exec('sh /home/user/scripts/script')
When you add ./ there on path its interpreted differently.
When you pass ./script - You are referring to filename script in current directory.
Also you are actually getting error from your c program which tells us your system is stopping apache to gain root privileges. You can audit2allow to let apache gain needed privileges.
-rw-r--r-- 1 root root 514 Jan 15 04:03 curl.php
-rw-r----- 1 root root 1344 Feb 5 02:09 dbm-config.ini
-rw-r--r-- 1 root root 5149 Feb 5 02:19 mysql-connectivity-status.php
Here, Am accessing the file "mysql-connectivity-status.php" from url like http://<ip>/html/DB-Monitoring/mysql-connectivity-status.php.
In mysql-connectivity-status.php I have called the file dbm-config.ini. While am accessing via URL am getting the following Warning.
Warning: parse_ini_file(/var/www/html/DB-Monitoring/dbm-config.ini): failed to open stream: Permission denied in /var/www/html/DB-Monitoring/mysql-connectivity-status.php on line 113
So, I don't want to change the permission for the dbm-config.ini But how to I access the file using URL?
-rw-r----- 1 root root 1344 Feb 5 02:09 dbm-config.ini
The file can be read from and written to, by the user root rw- and read from by the members of the group root r--
If you access the php file using curl, this is executed most likely with your webservers user and group which is not root:root
That's why php can't read the ini file.
I recommend to move the file out of your document root so it can't be accessed directly from the web, then change the owner to your webserver user and group
determine the username php is executed with
ps aux | grep "httpd" # apache environment
ps aux | grep "php" # php fastcgi environment
chown user:group dbm-config.ini
The problem is that your webserver cannot access that file. If you cannot fix that you cannot access it remotely through that webserver. :)
Wild guess, since I don't know what you're using:
chown root:apache dbm-config.ini
chmod g+r dbm-config.ini
might help. That will set the owning group of the file to apache and give the group read access. IF your webserver is apache and that is the correct group that it is using this might help.
Is there a way to set php running under apache to create folders with the folder owned by the owner of the program that creates it instead of being owned by apache?
Using word press it creates new folders to upload into but these are owned by apache.apache and not by the site that they are running in. This also happens using ostickets. For now we have to SSH into the server and chmod the folder, but it would seem there would be a setting somewhere to override the ownership outside of any program that does it.
Safe_mode is turn on on your server. The function mkdir() creates folder with owner ("apache", "none", ..) that different of the current script owner. And scripts couldn't upload (move, copy) files into that folder with another owner (that is not like current script owner).
Disable safe_mode and that would be work.
See http://php.net/manual/en/features.safe-mode.php for details.
P.S. With enable safe_mode you can't use chmod() function in php.
Another way is to put the apache user and the "customer users" in a new group. Additional the directory should use the sticky bit SGID so each new file got the group assignment to this new group. This way the webserver and the "customer users" can work with the files without any problems
[17:57] progman#proglap /tmp/test $ ls -al /tmp/test
total 9
drwxrwsr-x 2 root users 48 Apr 1 17:55 .
drwxrwxrwt 36 root root 9264 Apr 1 17:53 ..
As you see the directory got the stick bit SGID and the owner is the "users" group in which I (progman) am. No if another user adds a file the group automatically get set to this group
[17:55] proglap ~ # touch /tmp/test/x
This is executed from root. Now we get:
[17:57] progman#proglap /tmp/test $ ls -la /tmp/test
total 9
drwxrwsr-x 2 root users 72 Apr 1 17:59 .
drwxrwxrwt 36 root root 9264 Apr 1 17:53 ..
-rw-r--r-- 1 root users 0 Apr 1 17:59 x
As you see the added file is from root, but the group is set to users and this way I can remove it
[18:00] progman#proglap /tmp/test $ rm x
rm: remove write-protected regular empty file `x'? y
[18:01] progman#proglap /tmp/test $ ls -la /tmp/test
total 9
drwxrwsr-x 2 root users 48 Apr 1 18:01 .
drwxrwxrwt 36 root root 9264 Apr 1 17:53 ..
Keep in mind that you still need to change the chmod if you want to edit the file as rw-r--r-- is just group read access. But changing the chmod, maybe even working with umask, is better than dealing with root-access and using chown.
Not directly, no. You can't "give away" ownership of a file to another user, unless you're root. You could investigate using the "AssignUserID" apache directive to force that particular vhost to run as a particular user/group. With that Apache/PHP would create any files with the appropriate ownership
Check out PHP chown() function