[Bug 33232] New: Amazon MP3 Downloader crashes during download of mp3 files (ntdll/server fd cache doesn't take FILE_APPEND_DATA flag implicit write access into account)

wine-bugs at winehq.org wine-bugs at winehq.org
Sat Mar 16 17:33:35 CDT 2013


http://bugs.winehq.org/show_bug.cgi?id=33232

             Bug #: 33232
           Summary: Amazon MP3 Downloader crashes during download of mp3
                    files (ntdll/server fd cache doesn't take
                    FILE_APPEND_DATA flag implicit write access into
                    account)
           Product: Wine
           Version: 1.5.26
          Platform: x86
        OS/Version: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: ntdll
        AssignedTo: wine-bugs at winehq.org
        ReportedBy: focht at gmx.net
    Classification: Unclassified


Hello folks,

some time ago newer versions of "Amazon MP3 Downloader" application broke.
The app crashes while trying to download .mp3 files after purchase (during
processing of .amz).

Application log hints at a write error after receiving first data chunk:

--- snip ---
[AMD] [Download::OnCurlWriteData()] Output Stream failed to write, returning
error."
--- snip ---

It seems Wine ntdll/server fd cache only cares for access bit 0-1 when checking
for read-write permissions.

Debug session:

--- snip ---
Wine-dbg>bt
Backtrace:
=>0 0x7bc79c52 add_fd_to_cache(handle=0xe0, fd=0x22, type=FD_TYPE_FILE,
access=0x120114, options=0x60)
[/home/focht/projects/wine/wine-git/dlls/ntdll/server.c:470] in ntdll
(0x00b9e1e8)
  1 0x7bc43707 NtQueryInformationFile+0x192(hFile=<couldn't compute location>,
io=<couldn't compute location>, ptr=<couldn't compute location>, len=<couldn't
compute location>, class=<couldn't compute location>)
[/home/focht/projects/wine/wine-git/dlls/ntdll/file.c:1927] in ntdll
(0x00b9e408)
  2 0x7b83ee76 SetFilePointerEx+0xc2(hFile=<couldn't compute location>,
distance={u={LowPart=0, HighPart=0}, QuadPart=0}, newpos=<couldn't compute
location>, method=<couldn't compute location>)
[/home/focht/projects/wine/wine-git/dlls/kernel32/file.c:1066] in kernel32
(0x00b9e498)
  3 0x7b83ed6f SetFilePointer+0x69(hFile=<couldn't compute location>,
distance=<couldn't compute location>, highword=<couldn't compute location>,
method=<couldn't compute location>)
[/home/focht/projects/wine/wine-git/dlls/kernel32/file.c:1035] in kernel32
(0x00b9e508)
  4 0x006fe405 in amazonmp3downloader (+0x2fe404) (0x00b9e5b4)
  5 0x004b3cfa in amazonmp3downloader (+0xb3cf9) (0x00b9e5d0)
  6 0x0048e9b6 in amazonmp3downloader (+0x8e9b5) (0x00b9e62c)
  7 0x004abd42 in amazonmp3downloader (+0xabd41) (0x00b9e8a0)
  8 0x004acdd3 in amazonmp3downloader (+0xacdd2) (0x00b9e8ac)
  9 0x004b8863 in amazonmp3downloader (+0xb8862) (0x00b9e8b8)
  10 0x004cabe2 in amazonmp3downloader (+0xcabe1) (0x00b9e934)
  11 0x004ca51e in amazonmp3downloader (+0xca51d) (0x00b9e960)
  12 0x004ca416 in amazonmp3downloader (+0xca415) (0x00b9e9ac)
  13 0x007132f3 in amazonmp3downloader (+0x3132f2) (0x00b9e9d4)
  14 0x0064afd5 in amazonmp3downloader (+0x24afd4) (0x00b9ea0c)
  15 0x0064b0fd in amazonmp3downloader (+0x24b0fc) (0x00b9ea18)

Wine-dbg>info locals
0x7bc79dfd add_fd_to_cache+0x1ab: (00b9e098)
    HANDLE handle=0xe0 (parameter [EBP+8])
    int fd=0x22 (parameter [EBP+12])
    enum server_fd_type type=FD_TYPE_FILE (parameter [EBP+16])
    unsigned int access=0x120114 (parameter [EBP+20])
    unsigned int options=0x60 (parameter [EBP+24])
    unsigned int entry=0 (local [EBP-32])
    unsigned int idx=0x37 (local [EBP-12])
    int prev_fd=0xffffffff (local [EBP-28])
--- snip ---

An fd entry with access flags "0x120114" is added.

0x120114 (hard-coded in application code) decodes to:

FILE_APPEND_DATA        0x00000004
FILE_WRITE_EA           0x00000010
FILE_WRITE_ATTRIBUTES   0x00000100
READ_CONTROL            0x00020000 (STANDARD_RIGHTS_READ,
STANDARD_RIGHTS_WRITE, STANDARD_RIGHTS_EXECUTE)
SYNCHRONIZE             0x00100000

It didn't pass "FILE_WRITE_DATA" contained in FILE_GENERIC_WRITE (see end for
explanation):

--- snip ---
#define FILE_GENERIC_WRITE        (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | \
                                   FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | \
                                   FILE_APPEND_DATA | SYNCHRONIZE)
--- snip ---

The fd was created here:

--- snip ---
...
0023:Call KERNEL32.CreateFileW(00cbcaf8 L"C:\\users\\focht\\My Music\\Amazon
MP3\\Harry Gregson - Williams\\D\00e9j\00e0
Vu\\amazon.temp",00120114,00000003,00000000,00000004,00000080,00000000)
ret=006fe144 
...
0023: create_file( access=00120114, attributes=00000040, sharing=00000003,
create=3, options=00000060, attrs=00000080,
objattr={rootdir=0000,sd={},name=L""},
filename="/home/focht/.wine/dosdevices/c:/users/focht/My Music/Amazon MP3/Harry
Gregson - Williams/Déjà Vu/amazon.temp" ) 
...
0023: create_file() = 0 { handle=00f0 }
...
0023:Ret  KERNEL32.CreateFileW() retval=000000f0 ret=006fe144 
--- snip ---

The code that retrieves the cached fd only checks for FILE_READ_DATA |
FILE_WRITE_DATA set:

--- snip ---
Wine-dbg>bt
Backtrace:
=>0 0x7bc79e6e get_cached_fd+0x66(handle=0xe0, type=0xb9e008, access=0xb9de88,
options=0xb9e018) [/home/focht/projects/wine/wine-git/dlls/ntdll/server.c:515]
in ntdll (0x00b9dde8)
  1 0x7bc79fd8 server_get_unix_fd+0x78(handle=0xe0, wanted_access=0x2,
unix_fd=0xb9e020, needs_close=0xb9e01c, type=0xb9e008, options=0xb9e018)
[/home/focht/projects/wine/wine-git/dlls/ntdll/server.c:557] in ntdll
(0x00b9df38)
  2 0x7bc413d7 NtWriteFile+0x110(hFile=<couldn't compute location>,
hEvent=<couldn't compute location>, apc=<couldn't compute location>,
apc_user=<couldn't compute location>, io_status=<couldn't compute location>,
buffer=<couldn't compute location>, length=<couldn't compute location>,
offset=<couldn't compute location>, key=<couldn't compute location>)
[/home/focht/projects/wine/wine-git/dlls/ntdll/file.c:939] in ntdll
(0x00b9e088)
  3 0x7b83dfbc WriteFile+0x176(hFile=<couldn't compute location>,
buffer=<couldn't compute location>, bytesToWrite=<couldn't compute location>,
bytesWritten=<couldn't compute location>, overlapped=<couldn't compute
location>) [/home/focht/projects/wine/wine-git/dlls/kernel32/file.c:555] in
kernel32 (0x00b9e118)
  4 0x006fe6ca in amazonmp3downloader (+0x2fe6c9) (0x00b9e160)
  5 0x004b3bf3 in amazonmp3downloader (+0xb3bf2) (0x00b9e17c)
  6 0x0045c2a4 in amazonmp3downloader (+0x5c2a3) (0x00b9e1a8)
  7 0x0048e754 in amazonmp3downloader (+0x8e753) (0x00b9e1f0)
  8 0x0048d14a in amazonmp3downloader (+0x8d149) (0x00b9e274)
  9 0x00672a99 in amazonmp3downloader (+0x272a98) (0x00cdbad4)

Wine-dbg>info locals
0x7bc79ee1 get_cached_fd+0xd9: (00b9dde8)
    HANDLE handle=0xe0 (parameter [EBP+8])
    enum server_fd_type* type=0xb9e008 (parameter [EBP+12])
    unsigned int* access=0xb9de88 (parameter [EBP+16])
    unsigned int* options=0xb9e018 (parameter [EBP+20])
    unsigned int entry=0 (local [EBP-16])
    unsigned int idx=0x37 (local [EBP-12])
    int fd=0x22 (local [EBP-8])

Wine-dbg>p *access
0

Wine-dbg>n
582        if (!ret && ((access & wanted_access) != wanted_access))
--- snip ---

wanted access: FILE_WRITE_DATA
retrieved access: 0 (only bit 0-1 are preserved, all others got cut off when
the fd cache entry was created -> 2 bits reserved in fd cache entry).

So the WriteFile() call fails in the end.

Wine code:

http://source.winehq.org/git/wine.git/blob/0effd926b6475842baefc5379b9dd932c08ff14e:/dlls/ntdll/server.c#l543

--- snip ---
 543 int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int
*unix_fd,
 544                         int *needs_close, enum server_fd_type *type,
unsigned int *options )
 545 {
 546     sigset_t sigset;
 547     obj_handle_t fd_handle;
 548     int ret = 0, fd;
 549     unsigned int access = 0;
 550 
 551     *unix_fd = -1;
 552     *needs_close = 0;
 553     wanted_access &= FILE_READ_DATA | FILE_WRITE_DATA;
 554 
 555     server_enter_uninterrupted_section( &fd_cache_section, &sigset );
 556 
 557     fd = get_cached_fd( handle, type, &access, options );
 558     if (fd != -1) goto done;
...
 580 done:
 581     server_leave_uninterrupted_section( &fd_cache_section, &sigset );
 582     if (!ret && ((access & wanted_access) != wanted_access))
 583     {
 584         ret = STATUS_ACCESS_DENIED;
 585         if (*needs_close) close( fd );
 586     }
 587     if (!ret) *unix_fd = fd;
 588     return ret;
 589 }
--- snip ---

So what did the application intend by _not_ passing FILE_WRITE_DATA?

Fortunately there is a hint hidden in the MSDN entry for CreateFile() that
explains it:

--- quote ---
You can get atomic append on local files by opening a file with
FILE_APPEND_DATA access and _without_ FILE_WRITE_DATA access. If you do this
then all writes will ignore the the current file pointer and be done at the
end-of file. (Actually, I'm not sure if the current file pointer is updated to
EOF at each write or not, I haven't tested that behavior.) Eg

HANDLE hFile = CreateFile(TEXT("c:\\file.txt"), FILE_APPEND_DATA ,
FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

The append behavior is properly synchronized between multiple writes (with or
without multiple handles), where the typical way I've seen this implemented (by
seeking to EOF and then writing) has a race condition if multiple threads /
processes are appending to the same file.

This behavior is documented in Windows Driver Kit / Device and Driver
Technologies / Installable File System / Reference / IO Manager Routines /
IoCreateFileSpecifyDeviceObject (currently at
http://msdn2.microsoft.com/en-us/library/ms795642.aspx)
--- quote ---

If you fix that, the application no longer crashes and purchased mp3 files are
successfully downloaded (already tested).

$ du -sh AmazonMP3DownloaderInstall.exe 
2.2M    AmazonMP3DownloaderInstall.exe

$ sha1sum AmazonMP3DownloaderInstall.exe 
11b08d68fe11006ed402701a85183565ee8e139e  AmazonMP3DownloaderInstall.exe

$ wine --version
wine-1.5.26-19-g6ed2d9b

Regards

-- 
Configure bugmail: http://bugs.winehq.org/userprefs.cgi?tab=email
Do not reply to this email, post in Bugzilla using the
above URL to reply.
------- You are receiving this mail because: -------
You are watching all bug changes.


More information about the wine-bugs mailing list