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