From 6955a298f444332c87eb4154a7d02b6e13e3c6cc Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Wed, 19 Aug 2015 11:18:27 +0200 Subject: [PATCH] server: Do not permit FileDispositionInformation to delete a file without write access. --- dlls/ntdll/tests/file.c | 14 ++++++++++++++ server/fd.c | 7 +++++++ 2 files changed, 21 insertions(+) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 57ae15c038a..d215d09b1d0 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -1505,6 +1505,20 @@ static void test_file_disposition_information(void) ok( fileDeleted, "File should have been deleted\n" ); DeleteFileA( buffer ); + /* cannot set disposition on readonly file */ + GetTempFileNameA( tmp_path, "dis", 0, buffer ); + DeleteFileA( buffer ); + handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0); + ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); + fdi.DoDeleteFile = TRUE; + res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation ); + ok( res == STATUS_CANNOT_DELETE, "unexpected FileDispositionInformation result (expected STATUS_CANNOT_DELETE, got %x)\n", res ); + CloseHandle( handle ); + fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "File shouldn't have been deleted\n" ); + SetFileAttributesA( buffer, FILE_ATTRIBUTE_NORMAL ); + DeleteFileA( buffer ); + /* cannot set disposition on readonly file */ GetTempFileNameA( tmp_path, "dis", 0, buffer ); handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0); diff --git a/server/fd.c b/server/fd.c index f607261dbca..0bac57dfde9 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2244,6 +2244,13 @@ static void set_fd_disposition( struct fd *fd, int unlink ) return; } + /* can't unlink files we don't have permission to access */ + if (unlink && !(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) + { + set_error( STATUS_CANNOT_DELETE ); + return; + } + fd->closed->unlink = unlink || (fd->options & FILE_DELETE_ON_CLOSE); }