From f78b3464ce5952370299c8e5180fd80d81ae8834 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Wed, 5 Jun 2019 20:42:26 -0700 Subject: [PATCH] sys: meta: fix rare memory leak --- src/sys/meta.c | 8 ++-- tst/winfsp-tests/security-test.c | 70 ++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/src/sys/meta.c b/src/sys/meta.c index f009a7aa..6d51030e 100644 --- a/src/sys/meta.c +++ b/src/sys/meta.c @@ -103,7 +103,7 @@ static inline FSP_META_CACHE_ITEM *FspMetaCacheRemoveExpiredItemAtDpcLevel(FSP_M if (Head == Entry) return 0; FSP_META_CACHE_ITEM *Item = CONTAINING_RECORD(Entry, FSP_META_CACHE_ITEM, ListEntry); - if (!FspExpirationTimeValid2(Item->ExpirationTime, ExpirationTime)) + if (FspExpirationTimeValid2(Item->ExpirationTime, ExpirationTime)) return 0; ULONG HashIndex = Item->ItemIndex % MetaCache->ItemBucketCount; for (FSP_META_CACHE_ITEM **P = (PVOID)&MetaCache->ItemBuckets[HashIndex]; *P; P = &(*P)->DictNext) @@ -202,7 +202,7 @@ UINT64 FspMetaCacheAddItem(FSP_META_CACHE *MetaCache, PCVOID Buffer, ULONG Size) { if (0 == MetaCache) return 0; - FSP_META_CACHE_ITEM *Item; + FSP_META_CACHE_ITEM *Item, *ExpiredItem = 0; FSP_META_CACHE_ITEM_BUFFER *ItemBuffer; UINT64 ItemIndex = 0; KIRQL Irql; @@ -236,12 +236,14 @@ UINT64 FspMetaCacheAddItem(FSP_META_CACHE *MetaCache, PCVOID Buffer, ULONG Size) } KeAcquireSpinLock(&MetaCache->SpinLock, &Irql); if (MetaCache->ItemCount >= MetaCache->MetaCapacity) - FspMetaCacheRemoveExpiredItemAtDpcLevel(MetaCache, (UINT64)-1LL); + ExpiredItem = FspMetaCacheRemoveExpiredItemAtDpcLevel(MetaCache, (UINT64)-1LL); ItemIndex = MetaCache->ItemIndex; ItemIndex = (UINT64)-1LL == ItemIndex ? 1 : ItemIndex + 1; MetaCache->ItemIndex = Item->ItemIndex = ItemIndex; FspMetaCacheAddItemAtDpcLevel(MetaCache, Item); KeReleaseSpinLock(&MetaCache->SpinLock, Irql); + if (0 != ExpiredItem) + FspMetaCacheDereferenceItem(ExpiredItem); return ItemIndex; } diff --git a/tst/winfsp-tests/security-test.c b/tst/winfsp-tests/security-test.c index 5293bfae..b9d8659e 100644 --- a/tst/winfsp-tests/security-test.c +++ b/tst/winfsp-tests/security-test.c @@ -261,8 +261,78 @@ void setsecurity_test(void) } } +void security_stress_meta_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout) +{ +#define NumFiles 200/* 2*FspFsvolDeviceSecurityCacheCapacity */ + + void *memfs = memfs_start_ex(Flags, FileInfoTimeout); + + HANDLE Handles[NumFiles]; + WCHAR FilePath[MAX_PATH]; + BOOL Success; + DWORD Length; + + StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1", + Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs)); + Success = CreateDirectoryW(FilePath, 0); + ASSERT(Success); + + for (int j = 0; NumFiles > j; j++) + { + StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1\\file%d", + Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs), j + 1); + Handles[j] = CreateFileW(FilePath, GENERIC_ALL, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0); + ASSERT(INVALID_HANDLE_VALUE != Handles[j]); + } + + for (int j = 0; NumFiles > j; j++) + { + Success = GetKernelObjectSecurity(Handles[j], + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + 0, 0, &Length); + ASSERT(!Success); + ASSERT(ERROR_INSUFFICIENT_BUFFER == GetLastError()); + } + + for (int j = 0; NumFiles > j; j++) + { + Success = CloseHandle(Handles[j]); + ASSERT(Success); + } + + StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir1", + Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs)); + Success = RemoveDirectoryW(FilePath); + ASSERT(Success); + + memfs_stop(memfs); + +#undef NumFiles +} + +void security_stress_meta_test(void) +{ + if (NtfsTests) + { + WCHAR DirBuf[MAX_PATH]; + GetTestDirectory(DirBuf); + security_stress_meta_dotest(-1, DirBuf, 0); + } + if (WinFspDiskTests) + { + security_stress_meta_dotest(MemfsDisk, 0, 0); + security_stress_meta_dotest(MemfsDisk, 0, 1000); + } + if (WinFspNetTests) + { + security_stress_meta_dotest(MemfsNet, L"\\\\memfs\\share", 0); + security_stress_meta_dotest(MemfsNet, L"\\\\memfs\\share", 1000); + } +} + void security_tests(void) { TEST(getsecurity_test); TEST(setsecurity_test); + TEST_OPT(security_stress_meta_test); }