summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta-networking/recipes-support/open-vm-tools/open-vm-tools/CVE-2025-22247.patch378
-rw-r--r--meta-networking/recipes-support/open-vm-tools/open-vm-tools_12.5.0.bb1
2 files changed, 379 insertions, 0 deletions
diff --git a/meta-networking/recipes-support/open-vm-tools/open-vm-tools/CVE-2025-22247.patch b/meta-networking/recipes-support/open-vm-tools/open-vm-tools/CVE-2025-22247.patch
new file mode 100644
index 0000000000..2141443a1f
--- /dev/null
+++ b/meta-networking/recipes-support/open-vm-tools/open-vm-tools/CVE-2025-22247.patch
@@ -0,0 +1,378 @@
1From 7874e572b5aac5a418551dc5e3935c1e74bf6f1f Mon Sep 17 00:00:00 2001
2From: John Wolfe <john.wolfe@broadcom.com>
3Date: Mon, 5 May 2025 15:58:03 -0700
4Subject: [PATCH] Validate user names and file paths
5
6Prevent usage of illegal characters in user names and file paths.
7Also, disallow unexpected symlinks in file paths.
8
9This patch contains changes to common source files not applicable
10to open-vm-tools.
11
12All files being updated should be consider to have the copyright to
13be updated to:
14
15 * Copyright (c) XXXX-2025 Broadcom. All Rights Reserved.
16 * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
17
18The 2025 Broadcom copyright information update is not part of this
19patch set to allow the patch to be easily applied to previous
20open-vm-tools source releases.
21
22CVE: CVE-2025-22247
23Upstream-Status: Backport [https://github.com/vmware/open-vm-tools/blob/CVE-2025-22247.patch/CVE-2025-22247-1230-1250-VGAuth-updates.patch]
24
25Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
26---
27 open-vm-tools/vgauth/common/VGAuthUtil.c | 33 +++++++++
28 open-vm-tools/vgauth/common/VGAuthUtil.h | 2 +
29 open-vm-tools/vgauth/common/prefs.h | 3 +
30 open-vm-tools/vgauth/common/usercheck.c | 22 +++++-
31 open-vm-tools/vgauth/serviceImpl/alias.c | 74 ++++++++++++++++++-
32 open-vm-tools/vgauth/serviceImpl/service.c | 27 +++++++
33 open-vm-tools/vgauth/serviceImpl/serviceInt.h | 1 +
34 7 files changed, 159 insertions(+), 3 deletions(-)
35
36diff --git a/open-vm-tools/vgauth/common/VGAuthUtil.c b/open-vm-tools/vgauth/common/VGAuthUtil.c
37index 76383c46..06f1b51c 100644
38--- a/open-vm-tools/vgauth/common/VGAuthUtil.c
39+++ b/open-vm-tools/vgauth/common/VGAuthUtil.c
40@@ -309,3 +309,36 @@ Util_Assert(const char *cond,
41 #endif
42 g_assert(0);
43 }
44+
45+
46+/*
47++ ******************************************************************************
48+ * Util_Utf8CaseCmp -- */ /**
49+ *
50+ * Case insensitive comparison for utf8 strings which can have non-ascii
51+ * characters.
52+ *
53+ * @param[in] str1 Null terminated utf8 string.
54+ * @param[in] str2 Null terminated utf8 string.
55+ *
56+ ******************************************************************************
57+ */
58+
59+int
60+Util_Utf8CaseCmp(const gchar *str1,
61+ const gchar *str2)
62+{
63+ int ret;
64+ gchar *str1Case;
65+ gchar *str2Case;
66+
67+ str1Case = g_utf8_casefold(str1, -1);
68+ str2Case = g_utf8_casefold(str2, -1);
69+
70+ ret = g_strcmp0(str1Case, str2Case);
71+
72+ g_free(str1Case);
73+ g_free(str2Case);
74+
75+ return ret;
76+}
77diff --git a/open-vm-tools/vgauth/common/VGAuthUtil.h b/open-vm-tools/vgauth/common/VGAuthUtil.h
78index f7f3aa21..ef32a91d 100644
79--- a/open-vm-tools/vgauth/common/VGAuthUtil.h
80+++ b/open-vm-tools/vgauth/common/VGAuthUtil.h
81@@ -105,4 +105,6 @@ gboolean Util_CheckExpiration(const GTimeVal *start, unsigned int duration);
82
83 void Util_Assert(const char *cond, const char *file, int lineNum);
84
85+int Util_Utf8CaseCmp(const gchar *str1, const gchar *str2);
86+
87 #endif
88diff --git a/open-vm-tools/vgauth/common/prefs.h b/open-vm-tools/vgauth/common/prefs.h
89index 6c58f3f4..3299eb26 100644
90--- a/open-vm-tools/vgauth/common/prefs.h
91+++ b/open-vm-tools/vgauth/common/prefs.h
92@@ -167,6 +167,9 @@ msgCatalog = /etc/vmware-tools/vgauth/messages
93 /** Where the localized version of the messages were installed. */
94 #define VGAUTH_PREF_LOCALIZATION_DIR "msgCatalog"
95
96+/** If symlinks or junctions are allowed in alias store file path */
97+#define VGAUTH_PREF_ALLOW_SYMLINKS "allowSymlinks"
98+
99 /*
100 * Pref values
101 */
102diff --git a/open-vm-tools/vgauth/common/usercheck.c b/open-vm-tools/vgauth/common/usercheck.c
103index 3beede2e..8b4cbacb 100644
104--- a/open-vm-tools/vgauth/common/usercheck.c
105+++ b/open-vm-tools/vgauth/common/usercheck.c
106@@ -78,6 +78,8 @@
107 * Solaris as well, but that path is untested.
108 */
109
110+#define MAX_USER_NAME_LEN 256
111+
112 /*
113 * A single retry works for the LDAP case, but try more often in case NIS
114 * or something else has a related issue. Note that a bad username/uid won't
115@@ -354,12 +356,28 @@ Usercheck_UsernameIsLegal(const gchar *userName)
116 * restricted list for local usernames.
117 */
118 size_t len;
119- char *illegalChars = "<>/";
120+ size_t i = 0;
121+ int backSlashCnt = 0;
122+ /*
123+ * As user names are used to generate its alias store file name/path, it
124+ * should not contain path traversal characters ('/' and '\').
125+ */
126+ char *illegalChars = "<>/\\";
127
128 len = strlen(userName);
129- if (strcspn(userName, illegalChars) != len) {
130+ if (len > MAX_USER_NAME_LEN) {
131 return FALSE;
132 }
133+
134+ while ((i += strcspn(userName + i, illegalChars)) < len) {
135+ /*
136+ * One backward slash is allowed for domain\username separator.
137+ */
138+ if (userName[i] != '\\' || ++backSlashCnt > 1) {
139+ return FALSE;
140+ }
141+ ++i;
142+ }
143 return TRUE;
144 }
145
146diff --git a/open-vm-tools/vgauth/serviceImpl/alias.c b/open-vm-tools/vgauth/serviceImpl/alias.c
147index 4e170202..c7040ebf 100644
148--- a/open-vm-tools/vgauth/serviceImpl/alias.c
149+++ b/open-vm-tools/vgauth/serviceImpl/alias.c
150@@ -41,6 +41,7 @@
151 #include "certverify.h"
152 #include "VGAuthProto.h"
153 #include "vmxlog.h"
154+#include "VGAuthUtil.h"
155
156 // puts the identity store in an easy to find place
157 #undef WIN_TEST_MODE
158@@ -66,6 +67,7 @@
159 #define ALIASSTORE_FILE_PREFIX "user-"
160 #define ALIASSTORE_FILE_SUFFIX ".xml"
161
162+static gboolean allowSymlinks = FALSE;
163 static gchar *aliasStoreRootDir = DEFAULT_ALIASSTORE_ROOT_DIR;
164
165 #ifdef _WIN32
166@@ -252,6 +254,12 @@ mapping file layout:
167
168 */
169
170+#ifdef _WIN32
171+#define ISPATHSEP(c) ((c) == '\\' || (c) == '/')
172+#else
173+#define ISPATHSEP(c) ((c) == '/')
174+#endif
175+
176
177 /*
178 ******************************************************************************
179@@ -466,6 +474,7 @@ ServiceLoadFileContentsWin(const gchar *fileName,
180 gunichar2 *fileNameW = NULL;
181 BOOL ok;
182 DWORD bytesRead;
183+ gchar *realPath = NULL;
184
185 *fileSize = 0;
186 *contents = NULL;
187@@ -622,6 +631,22 @@ ServiceLoadFileContentsWin(const gchar *fileName,
188 goto done;
189 }
190
191+ if (!allowSymlinks) {
192+ /*
193+ * Check if fileName is real path.
194+ */
195+ if ((realPath = ServiceFileGetPathByHandle(hFile)) == NULL) {
196+ err = VGAUTH_E_FAIL;
197+ goto done;
198+ }
199+ if (Util_Utf8CaseCmp(realPath, fileName) != 0) {
200+ Warning("%s: Real path (%s) is not same as file path (%s)\n",
201+ __FUNCTION__, realPath, fileName);
202+ err = VGAUTH_E_FAIL;
203+ goto done;
204+ }
205+ }
206+
207 /*
208 * Now finally read the contents.
209 */
210@@ -650,6 +675,7 @@ done:
211 CloseHandle(hFile);
212 }
213 g_free(fileNameW);
214+ g_free(realPath);
215
216 return err;
217 }
218@@ -672,6 +698,7 @@ ServiceLoadFileContentsPosix(const gchar *fileName,
219 gchar *buf;
220 gchar *bp;
221 int fd = -1;
222+ gchar realPath[PATH_MAX] = { 0 };
223
224 *fileSize = 0;
225 *contents = NULL;
226@@ -817,6 +844,23 @@ ServiceLoadFileContentsPosix(const gchar *fileName,
227 goto done;
228 }
229
230+ if (!allowSymlinks) {
231+ /*
232+ * Check if fileName is real path.
233+ */
234+ if (realpath(fileName, realPath) == NULL) {
235+ Warning("%s: realpath() failed. errno (%d)\n", __FUNCTION__, errno);
236+ err = VGAUTH_E_FAIL;
237+ goto done;
238+ }
239+ if (g_strcmp0(realPath, fileName) != 0) {
240+ Warning("%s: Real path (%s) is not same as file path (%s)\n",
241+ __FUNCTION__, realPath, fileName);
242+ err = VGAUTH_E_FAIL;
243+ goto done;
244+ }
245+ }
246+
247 /*
248 * All confidence checks passed; read the bits.
249 */
250@@ -2803,8 +2847,13 @@ ServiceAliasRemoveAlias(const gchar *reqUserName,
251
252 /*
253 * We don't verify the user exists in a Remove operation, to allow
254- * cleanup of deleted user's stores.
255+ * cleanup of deleted user's stores, but we do check whether the
256+ * user name is legal or not.
257 */
258+ if (!Usercheck_UsernameIsLegal(userName)) {
259+ Warning("%s: Illegal user name '%s'\n", __FUNCTION__, userName);
260+ return VGAUTH_E_FAIL;
261+ }
262
263 if (!CertVerify_IsWellFormedPEMCert(pemCert)) {
264 return VGAUTH_E_INVALID_CERTIFICATE;
265@@ -3036,6 +3085,16 @@ ServiceAliasQueryAliases(const gchar *userName,
266 }
267 #endif
268
269+ /*
270+ * We don't verify the user exists in a Query operation to allow
271+ * cleaning up after a deleted user, but we do check whether the
272+ * user name is legal or not.
273+ */
274+ if (!Usercheck_UsernameIsLegal(userName)) {
275+ Warning("%s: Illegal user name '%s'\n", __FUNCTION__, userName);
276+ return VGAUTH_E_FAIL;
277+ }
278+
279 err = AliasLoadAliases(userName, num, aList);
280 if (VGAUTH_E_OK != err) {
281 Warning("%s: failed to load Aliases for '%s'\n", __FUNCTION__, userName);
282@@ -3294,6 +3353,7 @@ ServiceAliasInitAliasStore(void)
283 VGAuthError err = VGAUTH_E_OK;
284 gboolean saveBadDir = FALSE;
285 char *defaultDir = NULL;
286+ size_t len;
287
288 #ifdef _WIN32
289 {
290@@ -3324,6 +3384,10 @@ ServiceAliasInitAliasStore(void)
291 defaultDir = g_strdup(DEFAULT_ALIASSTORE_ROOT_DIR);
292 #endif
293
294+ allowSymlinks = Pref_GetBool(gPrefs,
295+ VGAUTH_PREF_ALLOW_SYMLINKS,
296+ VGAUTH_PREF_GROUP_NAME_SERVICE,
297+ FALSE);
298 /*
299 * Find the alias store directory. This allows an installer to put
300 * it somewhere else if necessary.
301@@ -3337,6 +3401,14 @@ ServiceAliasInitAliasStore(void)
302 VGAUTH_PREF_GROUP_NAME_SERVICE,
303 defaultDir);
304
305+ /*
306+ * Remove the trailing separator if any from aliasStoreRootDir path.
307+ */
308+ len = strlen(aliasStoreRootDir);
309+ if (ISPATHSEP(aliasStoreRootDir[len - 1])) {
310+ aliasStoreRootDir[len - 1] = '\0';
311+ }
312+
313 Log("Using '%s' for alias store root directory\n", aliasStoreRootDir);
314
315 g_free(defaultDir);
316diff --git a/open-vm-tools/vgauth/serviceImpl/service.c b/open-vm-tools/vgauth/serviceImpl/service.c
317index d4716526..e053ed0f 100644
318--- a/open-vm-tools/vgauth/serviceImpl/service.c
319+++ b/open-vm-tools/vgauth/serviceImpl/service.c
320@@ -28,6 +28,7 @@
321 #include "VGAuthUtil.h"
322 #ifdef _WIN32
323 #include "winUtil.h"
324+#include <glib.h>
325 #endif
326
327 static ServiceStartListeningForIOFunc startListeningIOFunc = NULL;
328@@ -283,9 +284,35 @@ static gchar *
329 ServiceUserNameToPipeName(const char *userName)
330 {
331 gchar *escapedName = ServiceEncodeUserName(userName);
332+#ifdef _WIN32
333+ /*
334+ * Adding below pragma only in windows to suppress the compile time warning
335+ * about unavailability of g_uuid_string_random() since compiler flag
336+ * GLIB_VERSION_MAX_ALLOWED is defined to GLIB_VERSION_2_34.
337+ * TODO: Remove below pragma when GLIB_VERSION_MAX_ALLOWED is bumped up to
338+ * or greater than GLIB_VERSION_2_52.
339+ */
340+#pragma warning(suppress : 4996)
341+ gchar *uuidStr = g_uuid_string_random();
342+ /*
343+ * Add a unique suffix to avoid a name collision with an existing named pipe
344+ * created by someone else (intentionally or by accident).
345+ * This is not needed for Linux; name collisions on sockets are already
346+ * avoided there since (1) file system paths to VGAuthService sockets are in
347+ * a directory that is writable only by root and (2) VGAuthService unlinks a
348+ * socket path before binding it to a newly created socket.
349+ */
350+ gchar *pipeName = g_strdup_printf("%s-%s-%s",
351+ SERVICE_PUBLIC_PIPE_NAME,
352+ escapedName,
353+ uuidStr);
354+
355+ g_free(uuidStr);
356+#else
357 gchar *pipeName = g_strdup_printf("%s-%s",
358 SERVICE_PUBLIC_PIPE_NAME,
359 escapedName);
360+#endif
361
362 g_free(escapedName);
363 return pipeName;
364diff --git a/open-vm-tools/vgauth/serviceImpl/serviceInt.h b/open-vm-tools/vgauth/serviceImpl/serviceInt.h
365index 5f420192..f4f88547 100644
366--- a/open-vm-tools/vgauth/serviceImpl/serviceInt.h
367+++ b/open-vm-tools/vgauth/serviceImpl/serviceInt.h
368@@ -441,6 +441,7 @@ VGAuthError ServiceFileVerifyAdminGroupOwnedByHandle(const HANDLE hFile);
369 VGAuthError ServiceFileVerifyEveryoneReadableByHandle(const HANDLE hFile);
370 VGAuthError ServiceFileVerifyUserAccessByHandle(const HANDLE hFile,
371 const char *userName);
372+gchar *ServiceFileGetPathByHandle(HANDLE hFile);
373 #else
374 VGAuthError ServiceFileVerifyFileOwnerAndPerms(const char *fileName,
375 const char *userName,
376--
3772.40.0
378
diff --git a/meta-networking/recipes-support/open-vm-tools/open-vm-tools_12.5.0.bb b/meta-networking/recipes-support/open-vm-tools/open-vm-tools_12.5.0.bb
index d44709a64d..8f7c05b994 100644
--- a/meta-networking/recipes-support/open-vm-tools/open-vm-tools_12.5.0.bb
+++ b/meta-networking/recipes-support/open-vm-tools/open-vm-tools_12.5.0.bb
@@ -43,6 +43,7 @@ SRC_URI = "git://github.com/vmware/open-vm-tools.git;protocol=https;branch=stabl
43 file://0012-hgfsServerLinux-Consider-64bit-time_t-possibility.patch;patchdir=.. \ 43 file://0012-hgfsServerLinux-Consider-64bit-time_t-possibility.patch;patchdir=.. \
44 file://0013-open-vm-tools-Correct-include-path-for-poll.h.patch;patchdir=.. \ 44 file://0013-open-vm-tools-Correct-include-path-for-poll.h.patch;patchdir=.. \
45 file://0014-timeSync-Portable-way-to-print-64bit-time_t.patch;patchdir=.. \ 45 file://0014-timeSync-Portable-way-to-print-64bit-time_t.patch;patchdir=.. \
46 file://CVE-2025-22247.patch;patchdir=.. \
46 " 47 "
47 48
48UPSTREAM_CHECK_GITTAGREGEX = "stable-(?P<pver>\d+(\.\d+)+)" 49UPSTREAM_CHECK_GITTAGREGEX = "stable-(?P<pver>\d+(\.\d+)+)"