|   | php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login | 
| 
  [2019-02-18 00:39 UTC] manabu dot matsui at gmail dot com
 Description:
------------
I tried to strace rename across devices, and the process was done as follows.
(Only system calls that should be noticed are pulled out so as not to become too long)
openat(AT_FDCWD, "/boot/hoge/oldfile", O_RDONLY) = 3
openat(AT_FDCWD, "/tmp/dstdir/newfile", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4
(mmap and write contents)
chmod("/tmp/dstdir/newfile", 0100664)       = 0
chown("/tmp/dstdir/newfile", 1000, 1000)    = 0
unlink("oldfile")                           = 0
Until chown is done, users who were not allowed to access to oldfile may be able to access newfile.
It is not impossible to avoid this problem by properly controlling environments such as umask, effective-gid (in case of linux semantics), group of destination directory (in case of bsd semantics).
However,  it is handled like mv command of GNU-oreutils, for example, there is no need for special preparation, so I think it will be safer.
* unlink newfile before open and open with O_EXCL to ensure that we do not open inappropriate file created by someone.
* open newfile with mode=600 to ensure that access from unwanted users is prevented during copying process.
* do chmod after chown to ensure that group access is not enabled until the group to which file belongs is set properly.
PatchesPull Requests
Pull requests: 
 HistoryAllCommentsChangesGit/SVN commits             | |||||||||||||||||||||||||||
|  Copyright © 2001-2025 The PHP Group All rights reserved. | Last updated: Fri Oct 31 18:00:01 2025 UTC | 
This is a problem when VCWD_RENAME() fails with EXDEV. In this case, the current implementation will execute php_copy_file(), VCWD_CHMOD(), VCWD_CHOWN() in this order. This is around the php_plain_files_rename() function in main/streams/plain_wrapper.c. ret = VCWD_RENAME(url_from, url_to); if (ret == -1) { #ifndef PHP_WIN32 # ifdef EXDEV if (errno == EXDEV) { zend_stat_t sb; if (php_copy_file(url_from, url_to) == SUCCESS) { if (VCWD_STAT(url_from, &sb) == 0) { # ifndef TSRM_WIN32 if (VCWD_CHMOD(url_to, sb.st_mode)) { if (errno == EPERM) { php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", strerror(errno)); VCWD_UNLINK(url_from); return 1; } php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", strerror(errno)); return 0; } if (VCWD_CHOWN(url_to, sb.st_uid, sb.st_gid)) { if (errno == EPERM) { php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", strerror(errno)); VCWD_UNLINK(url_from); return 1; } php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", strerror(errno)); return 0; } # endif VCWD_UNLINK(url_from); return 1; } } php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", strerror(errno)); return 0; } # endif #endif