/* 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

Reply via email to