/* Summary:
* O_TMPFILE linked with zero permissions when _FILE_OFFSET_BITS is 64
*
* Upstream MPD aborts on second run with the following message:
* errno: Failed to open ~/.mpd/database: Permission denied
* fatal_error: Can't open db file "~/.mpd/database" for reading/writing:
Permission denied
* The problem was introduced in the following commit:
* 8b217d531305433df01c789dab4dc81d58f05eba
* fs/io/FileOutputStream: use O_TMPFILE if available
* The problem only manifests under the following conditions:
* _FILE_OFFSET_BITS is set to 64 (presumably an value other than 32)
* open() a file with the O_TMPFILE flag and appropriate mode
* linkat() the file
* The resulting linked file will have the permission bits set to 0.
*
* This is either related to or identical and fixed by the following
bug-report (2015-02-24):
* https://sourceware.org/bugzilla/show_bug.cgi?id=17523
* In any case, directly using SYS_open is a valid workaround.
*
* The following is a simple test-case.
*
* Run:
* bash -vc "$( sed -n 's#^ \* \(rm .*\)$#\1#p' test.tmpfile2.cpp )"
*
* Command:
* rm -f /tmp/testfile? test.tmpfile2 && g++ test.tmpfile2.cpp -o
test.tmpfile2 && ./test.tmpfile2 && ls -lah /tmp/testfile?
*
* System details:
* i686, Linux 3.19.0-16-generic, Ubuntu GLIBC 2.21-0ubuntu4, Ubuntu GCC
4.9.2-10ubuntu13
*
* Proposed solution:
* modify FileDescriptor.cxx:FileDescriptor::Open(...) to use
syscall(SYS_open, ...) instead of open(...)
* version this to glibc <= 2.21 (__GLIBC__, __GLIBC_MINOR__ ?)
*/
#define _FILE_OFFSET_BITS 64
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
int main() {
int flags = O_WRONLY;
char path[PATH_MAX];
// problem: false
int fd0 = open("/tmp/testfile0", O_CREAT|flags, 0666);
close(fd0);
// problem: true
int fd1 = open("/tmp", O_TMPFILE|flags, 0666);
snprintf(path, sizeof(path), "/proc/self/fd/%d", fd1);
linkat
( AT_FDCWD, path
, AT_FDCWD, "/tmp/testfile1"
, AT_SYMLINK_FOLLOW
);
close(fd1);
// problem: false
int fd2 = syscall
( SYS_open
, "/tmp"
, O_TMPFILE|flags
, 0666
);
snprintf(path, sizeof(path), "/proc/self/fd/%d", fd2);
linkat
( AT_FDCWD, path
, AT_FDCWD, "/tmp/testfile2"
, AT_SYMLINK_FOLLOW
);
close(fd2);
}
_______________________________________________
mpd-devel mailing list
[email protected]
http://mailman.blarg.de/listinfo/mpd-devel