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.
From 4eb8afe77064a0cf3d815aa0ffa1ebf815fd1165 Mon Sep 17 00:00:00 2001
From: Vladlen Popolitov <v.popoli...@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