Bug and memory leaks with access to file links with long names (Windows, MSVS)
Hi!
PostgreSQL build under Windows with MS Visual Studio has functions to
work with
links (unlike msys2 that has own functions). If a database has link
pointing
to location longer 130 chars, function pgreadlink fails to recognise
this
link and cancels query.
The reason of the error - small buffer for link name - MAX_PATH
symbols, though this
buffer must have the place for at least 2 MAX_PATH : substitution and
print names
of the link.
How to reproduce:
If build directory has length ~100 chars or longer,
pg_rewind/004_pg_xlog_symlink
test will fail (Windows, MSVS build)
Steps to reproduce:
call "C:\Program Files\Microsoft Visual
Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
SET LC_MESSAGES=C
SET
BUILDDIR=c:\postgresql-builds\length_30\length_40\length_50\length_60\length_70\length_80\length_90\length100\
meson setup %BUILDDIR% --prefix=c:\postgresql-builds\install
c:
cd %BUILDDIR%
meson compile -C %BUILDDIR%
meson install -C %BUILDDIR%
meson test -C %BUILDDIR%
Memory leak:
In case of error the function in the code branch reporting the error
does not return
Windows file handle and Windows heap allocation for error message text.
Solution:
Proposed patch fixes link information buffer size changing it to the
documented value
MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
and fixes memory leaks - the message buffer copied to a buffer on stack
with maximal message size 64Kb.
--
Best regards,
Vladlen Popolitov.
Attachments:
v1-0001-Fix-bug-with-access-to-file-links-with-long-name-.patchtext/x-diff; name=v1-0001-Fix-bug-with-access-to-file-links-with-long-name-.patchDownload
From 4eb8afe77064a0cf3d815aa0ffa1ebf815fd1165 Mon Sep 17 00:00:00 2001
From: Vladlen Popolitov <v.popolitov@postgrespro.ru>
Date: Fri, 27 Dec 2024 15:23:30 +0300
Subject: [PATCH v1] Fix bug with access to file links with long name (Windows,
MSVC)
---
src/port/dirmod.c | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/src/port/dirmod.c b/src/port/dirmod.c
index f98d5a7bf2..dbdd8a6e9f 100644
--- a/src/port/dirmod.c
+++ b/src/port/dirmod.c
@@ -310,7 +310,12 @@ pgreadlink(const char *path, char *buf, size_t size)
{
DWORD attr;
HANDLE h;
- char buffer[MAX_PATH * sizeof(WCHAR) + offsetof(REPARSE_JUNCTION_DATA_BUFFER, PathBuffer)];
+/*
+ * The buffer size described in documentation
+ * https://learn.microsoft.com/en-us/windows-hardware/drivers/ifs/fsctl-set-reparse-point
+ * It stores paths for SubstitutaName and PrintName.
+ */
+ char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
REPARSE_JUNCTION_DATA_BUFFER *reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER *) buffer;
DWORD len;
int r;
@@ -350,6 +355,8 @@ pgreadlink(const char *path, char *buf, size_t size)
NULL))
{
LPSTR msg;
+ /* the maximal size of the message returned by FormatMessage is 64Kb */
+ char msgBuffer[0x10000];
errno = 0;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
@@ -358,17 +365,24 @@ pgreadlink(const char *path, char *buf, size_t size)
NULL, GetLastError(),
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
(LPSTR) &msg, 0, NULL);
+ strncpy(msgBuffer, msg, sizeof(msgBuffer));
+ if (strlen(msg) >= sizeof(msgBuffer))
+ {
+ msgBuffer[sizeof(msgBuffer) - 1] = 0;
+ }
#ifndef FRONTEND
+ LocalFree(msg);
+ CloseHandle(h);
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not get junction for \"%s\": %s",
- path, msg)));
+ path, msgBuffer)));
#else
fprintf(stderr, _("could not get junction for \"%s\": %s\n"),
path, msg);
-#endif
LocalFree(msg);
CloseHandle(h);
+#endif
errno = EINVAL;
return -1;
}
--
2.42.0.windows.2