Bug #63304 Function "my_copy()" may use closed file descriptors, causing EBADF
Submitted: 17 Nov 2011 12:53
Reporter: Joerg Bruehe Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: DDL Severity:S3 (Non-critical)
Version:5.1.50 and up OS:Any
Assigned to: CPU Architecture:Any

[17 Nov 2011 12:53] Joerg Bruehe
Description:
Function "my_copy()" will copy a file.

Depending on flags, it may do a "chmod()" and/or a "chown()" on the result file.
If either of these calls fails, an error handling section (common for the whole function) will be executed.

The problem is that both files will be closed when the copy is done, but the error handling section will again try "close()" calls.
As the files had been closed already, these second calls will fail and cause EBADF.
This errno will mask the one of the failing "chmod()" or "chown()".

As a result, the test output will report a wrong error number.

The erroneous code is contained in a changeset pushed to MySQL 5.1.50:
http://lists.mysql.com/commits/113975

Getting to the real problem, the failing "chmod()" or "chown()", will be the subject of a separate bug report.

How to repeat:
Run any test that calls "copy_file" (for example, test "rpl_cross_version" in 5.5) in a setting such that the user has write privileges on "mysql-test/" and all its subdirectories, but is not the owner (and is not privileged).

Most Unix systems will not allow the "chown()" call and return EPERM (value 1).

The test will fail with these lines:
   mysqltest: In included file "./include/setup_fake_relay_log.inc":
   included from ./include/setup_fake_relay_log.inc at line 81:
   At line 80: command "copy_file" failed with error 1. my_errno=9

Errno 9 is code EBADF.

Alternatively, inspect the code.

Suggested fix:
Prevent it by resetting the file descriptor values after the first "close()" call:

=== modified file 'mysys/my_copy.c'
--- mysys/my_copy.c     2011-06-30 15:37:13 +0000
+++ mysys/my_copy.c     2011-11-17 12:45:19 +0000
@@ -99,6 +99,7 @@ int my_copy(const char *from, const char

     if (my_close(from_file,MyFlags) | my_close(to_file,MyFlags))
       DBUG_RETURN(-1);                         /* Error on close */
+    from_file=to_file= -1;

     /* Copy modes if possible */
[30 Nov 2011 16:52] Davi Arnaut
Now the target file is not deleted on failure. Better to just do the close as the very last step.
[22 May 2015 7:08] Andrii Nikitin
see also bug #77127
[29 May 2015 9:24] Andrii Nikitin
Posted by developer:
 
This is still problem in 5.1.73 and 5.5.44 , verified looking at source code . 
5.6.23 doesn't show error, but will not attempt to remove "to" file in some cases when error occurs (so code still looks buggy).