php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #74357 lchown fails to change ownership of symlink with ZTS
Submitted: 2017-04-01 04:07 UTC Modified: 2025-11-30 14:35 UTC
From: msaladna at apisnetworks dot com Assigned: bukka (profile)
Status: Verified Package: Filesystem function related
PHP Version: 7.4.23 OS: CentOS 7.3
Private report: No CVE-ID: None
 [2017-04-01 04:07 UTC] msaladna at apisnetworks dot com
Description:
------------
Compiling PHP with ZTS affects performance of lchown and lchgrp. 

PHP CLI compiled without ZTS:

./configure --disable-all

ZTS is above + '--enable-maintainer-zts'

Test script:
---------------
<?php
   echo "TS: ", PHP_ZTS, "\n";
   is_link("foo") && unlink("foo");
   symlink("/tmp", "foo");
   lchown("foo", 99);
   var_dump(lstat("foo")['uid']);
?>

Expected result:
----------------
TS: 1
int(99)

Actual result:
--------------
TS: 1
int(0)

Patches

Pull Requests

Pull requests:

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-09-09 12:20 UTC] cmb@php.net
-Status: Open +Status: Feedback -Assigned To: +Assigned To: cmb
 [2021-09-09 12:20 UTC] cmb@php.net
What is the output of the following script:

<?php
   echo "TS: ", PHP_ZTS, "\n";
   is_link("foo") && unlink("foo");
   symlink("/tmp", "foo");
   lchown("foo", 99);
   clearstatcache(true);
   var_dump(lstat("foo")['uid']);
?>

And please check with any of the actively supported PHP
versions[1]?

[1] <https://www.php.net/supported-versions.php>
 [2021-09-09 16:26 UTC] msaladna at apisnetworks dot com
-Status: Feedback +Status: Assigned -PHP Version: 7.1.3 +PHP Version: 7.4.23
 [2021-09-09 16:26 UTC] msaladna at apisnetworks dot com
Problem still persists. Sample code amended for clarity:

<?php
   echo "TS: ", PHP_ZTS, " ", PHP_VERSION, "\n";
   echo posix_getuid(), ":", posix_geteuid(), "\n";
   is_link("foo") && unlink("foo");
   symlink("/tmp", "foo");
   lchown("foo", 99);
   clearstatcache(true);
   var_dump(lstat("foo")['uid']);
?>

This is on a CentOS 7/PHP 7.4 machine.

TS: 1 7.4.23
0:0
int(0)

And on a Rocky Linux (CentOS 8)/PHP 8 machine:

TS: 1 8.0.6
0:0
int(0)
 [2021-09-10 14:40 UTC] cmb@php.net
-Status: Assigned +Status: Verified -Assigned To: cmb +Assigned To:
 [2021-09-10 14:40 UTC] cmb@php.net
I can confirm the reported behavior (PHP-7.4).  It is apparently
not related to the realpath cache, since disabling the cache in
the first place doesn't make a difference.
 [2024-07-13 09:12 UTC] ewverb654 at gmail dot com
This information is really helpful for who really needs this. I hope you will many more write post like this. (https://github.com)(https://www.mgh-patientgateway.com)
 [2025-11-30 14:35 UTC] bukka@php.net
-Assigned To: +Assigned To: bukka
 [2025-11-30 14:35 UTC] bukka@php.net
So this is really a bug in ZTS. The reason is that virtual_chown calls:

if (virtual_file_ex(&new_state, filename, NULL, CWD_REALPATH)) {

The problem is that this calls tsrm_realpath_r which resolves the simlink in 

		if (save && S_ISLNK(st.st_mode)) {
			if (++(*ll) > LINK_MAX || (j = (size_t)php_sys_readlink(tmp, path, MAXPATHLEN)) == (size_t)-1) {
				/* too many links or broken symlinks */
				free_alloca(tmp, use_heap);
				return (size_t)-1;
			}
			path[j] = 0;
			if (IS_ABSOLUTE_PATH(path, j)) {
				j = tsrm_realpath_r(path, 1, j, ll, t, use_realpath, is_dir, &directory);
				if (j == (size_t)-1) {
					free_alloca(tmp, use_heap);
					return (size_t)-1;
				}
			} else {
				if (i + j >= MAXPATHLEN-1) {
					free_alloca(tmp, use_heap);
					return (size_t)-1; /* buffer overflow */
				}
				memmove(path+i, path, j+1);
				memcpy(path, tmp, i-1);
				path[i-1] = DEFAULT_SLASH;
				j = tsrm_realpath_r(path, start, i + j, ll, t, use_realpath, is_dir, &directory);
				if (j == (size_t)-1) {
					free_alloca(tmp, use_heap);
					return (size_t)-1;
				}
			}
			if (link_is_dir) {
				*link_is_dir = directory;
			}
		}


Currently it seems that it does not get resolved only for CWD_EXPAND but not 100% sure if it's safe. Anyway I created https://github.com/php/php-src/pull/20626 so it will be checked there.
 [2025-11-30 14:35 UTC] bukka@php.net
The following pull request has been associated:

Patch Name: Fix bug #74357: lchown fails to change ownership of symlink with ZTS
On GitHub:  https://github.com/php/php-src/pull/20626
Patch:      https://github.com/php/php-src/pull/20626.patch
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Sat Dec 13 09:00:01 2025 UTC