File ImageMagick-CVE-2026-25965.patch of Package ImageMagick.42998
From 4a9dc1075dcad3ab0579e1b37dbe854c882699a5 Mon Sep 17 00:00:00 2001
From: Dirk Lemstra <dirk@lemstra.org>
Date: Tue, 3 Feb 2026 21:09:59 +0100
Subject: [PATCH] Prevent path traversal of paths that are blocked in the
security policy (GHSA-8jvj-p28h-9gm7)
---
MagickCore/module.c | 11 ++--
MagickCore/policy.c | 39 ++++++++----
MagickCore/token.c | 2 +
MagickCore/utility-private.h | 115 +++++++++++++++++++++++++++++++++++
MagickCore/utility.c | 28 ++++++---
5 files changed, 169 insertions(+), 26 deletions(-)
Index: ImageMagick-7.1.0-9/MagickCore/module.c
===================================================================
--- ImageMagick-7.1.0-9.orig/MagickCore/module.c
+++ ImageMagick-7.1.0-9/MagickCore/module.c
@@ -581,15 +581,16 @@ static MagickBooleanType GetMagickModule
(void) ConcatenateMagickString(path,DirectorySeparator,
MagickPathExtent);
(void) ConcatenateMagickString(path,filename,MagickPathExtent);
-#if defined(MAGICKCORE_HAVE_REALPATH)
{
char
- resolved_path[PATH_MAX+1];
+ *real_path = realpath_utf8(path);
- if (realpath(path,resolved_path) != (char *) NULL)
- (void) CopyMagickString(path,resolved_path,MagickPathExtent);
+ if (real_path != (char *) NULL)
+ {
+ (void) CopyMagickString(path,real_path,MagickPathExtent);
+ real_path=DestroyString(real_path);
+ }
}
-#endif
if (IsPathAccessible(path) != MagickFalse)
{
module_path=DestroyString(module_path);
Index: ImageMagick-7.1.0-9/MagickCore/policy.c
===================================================================
--- ImageMagick-7.1.0-9.orig/MagickCore/policy.c
+++ ImageMagick-7.1.0-9/MagickCore/policy.c
@@ -620,6 +620,9 @@ static MagickBooleanType IsPolicyCacheIn
MagickExport MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
const PolicyRights rights,const char *pattern)
{
+ char
+ *real_pattern = (char *) NULL;
+
const PolicyInfo
*policy_info;
@@ -627,7 +630,8 @@ MagickExport MagickBooleanType IsRightsA
*exception;
MagickBooleanType
- authorized;
+ authorized,
+ match;
PolicyInfo
*p;
@@ -648,22 +652,33 @@ MagickExport MagickBooleanType IsRightsA
p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
while (p != (PolicyInfo *) NULL)
{
- if ((p->domain == domain) &&
- (GlobExpression(pattern,p->pattern,MagickFalse) != MagickFalse))
+ if (p->domain == domain)
{
- if ((rights & ReadPolicyRights) != 0)
- authorized=(p->rights & ReadPolicyRights) != 0 ? MagickTrue :
- MagickFalse;
- if ((rights & WritePolicyRights) != 0)
- authorized=(p->rights & WritePolicyRights) != 0 ? MagickTrue :
- MagickFalse;
- if ((rights & ExecutePolicyRights) != 0)
- authorized=(p->rights & ExecutePolicyRights) != 0 ? MagickTrue :
- MagickFalse;
+ if ((p->domain == PathPolicyDomain) &&
+ (real_pattern == (const char *) NULL))
+ real_pattern=realpath_utf8(pattern);
+ if (real_pattern != (char*) NULL)
+ match=GlobExpression(real_pattern,p->pattern,MagickFalse);
+ else
+ match=GlobExpression(pattern,p->pattern,MagickFalse);
+ if (match != MagickFalse)
+ {
+ if ((rights & ReadPolicyRights) != 0)
+ authorized=(p->rights & ReadPolicyRights) != 0 ? MagickTrue :
+ MagickFalse;
+ if ((rights & WritePolicyRights) != 0)
+ authorized=(p->rights & WritePolicyRights) != 0 ?
+ MagickTrue : MagickFalse;
+ if ((rights & ExecutePolicyRights) != 0)
+ authorized=(p->rights & ExecutePolicyRights) != 0 ?
+ MagickTrue : MagickFalse;
+ }
}
p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
}
UnlockSemaphoreInfo(policy_semaphore);
+ if (real_pattern != (char *) NULL)
+ real_pattern=DestroyString(real_pattern);
return(authorized);
}
Index: ImageMagick-7.1.0-9/MagickCore/token.c
===================================================================
--- ImageMagick-7.1.0-9.orig/MagickCore/token.c
+++ ImageMagick-7.1.0-9/MagickCore/token.c
@@ -534,12 +534,14 @@ MagickExport MagickBooleanType GlobExpre
target=DestroyString(target);
break;
}
+#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
case '\\':
{
pattern+=GetUTFOctets(pattern);
if (GetUTFCode(pattern) == 0)
break;
}
+#endif
default:
{
if (case_insensitive != MagickFalse)
Index: ImageMagick-7.1.0-9/MagickCore/utility-private.h
===================================================================
--- ImageMagick-7.1.0-9.orig/MagickCore/utility-private.h
+++ ImageMagick-7.1.0-9/MagickCore/utility-private.h
@@ -228,6 +228,121 @@ static inline FILE *popen_utf8(const cha
#endif
}
+static inline char *realpath_utf8(const char *path)
+{
+#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
+#if defined(MAGICKCORE_HAVE_REALPATH)
+ return(realpath(path,(char *) NULL));
+#else
+ return(AcquireString(path));
+#endif
+#else
+ char
+ *real_path;
+
+ DWORD
+ final_path_length,
+ full_path_length;
+
+ HANDLE
+ file_handle;
+
+ int
+ length,
+ utf8_length;
+
+ wchar_t
+ *clean_path,
+ *full_path,
+ *wide_path;
+
+ /*
+ Convert UTF-8 to UTF-16.
+ */
+ if (path == (const char *) NULL)
+ return((char *) NULL);
+ length=MultiByteToWideChar(CP_UTF8,0,path,-1,NULL,0);
+ if (length <= 0)
+ return((char *) NULL);
+ wide_path=(wchar_t *) AcquireQuantumMemory(length,sizeof(wchar_t));
+ if (wide_path == (wchar_t *) NULL)
+ return((char *) NULL);
+ MultiByteToWideChar(CP_UTF8,0,path,-1,wide_path,length);
+ /*
+ Normalize syntactically.
+ */
+ full_path_length=GetFullPathNameW(wide_path,0,NULL,NULL);
+ if (full_path_length == 0)
+ {
+ wide_path=(wchar_t *) RelinquishMagickMemory(wide_path);
+ return((char *) NULL);
+ }
+ full_path=(wchar_t *) AcquireQuantumMemory(full_path_length,sizeof(wchar_t));
+ if (full_path == (wchar_t *) NULL)
+ {
+ wide_path=(wchar_t *) RelinquishMagickMemory(wide_path);
+ return((char *) NULL);
+ }
+ GetFullPathNameW(wide_path,full_path_length,full_path,NULL);
+ wide_path=(wchar_t *) RelinquishMagickMemory(wide_path);
+ /*
+ Open the file/directory to resolve symlinks.
+ */
+ file_handle=CreateFileW(full_path,GENERIC_READ,FILE_SHARE_READ |
+ FILE_SHARE_WRITE | FILE_SHARE_DELETE,NULL,OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,NULL);
+ if (file_handle != INVALID_HANDLE_VALUE)
+ {
+ /*
+ Resolve final canonical path.
+ */
+ final_path_length=GetFinalPathNameByHandleW(file_handle,NULL,0,
+ FILE_NAME_NORMALIZED);
+ if (final_path_length == 0)
+ {
+ CloseHandle(file_handle);
+ full_path=(wchar_t *) RelinquishMagickMemory(full_path);
+ return((char *) NULL);
+ }
+ full_path=(wchar_t *) RelinquishMagickMemory(full_path);
+ full_path=(wchar_t *) AcquireQuantumMemory(final_path_length,
+ sizeof(wchar_t));
+ if (full_path == (wchar_t *) NULL)
+ {
+ CloseHandle(file_handle);
+ return((char *) NULL);
+ }
+ GetFinalPathNameByHandleW(file_handle,full_path,final_path_length,
+ FILE_NAME_NORMALIZED);
+ CloseHandle(file_handle);
+ }
+ /*
+ Remove \\?\ prefix for POSIX-like behavior.
+ */
+ clean_path=full_path;
+ if (wcsncmp(full_path,L"\\\\?\\",4) == 0)
+ clean_path=full_path+4;
+ /*
+ Convert UTF-16 to UTF-8.
+ */
+ utf8_length=WideCharToMultiByte(CP_UTF8,0,clean_path,-1,NULL,0,NULL,NULL);
+ if (utf8_length <= 0)
+ {
+ full_path=(wchar_t *) RelinquishMagickMemory(full_path);
+ return NULL;
+ }
+ real_path=(char *) AcquireQuantumMemory(utf8_length,sizeof(char));
+ if (real_path == (char *) NULL)
+ {
+ full_path=(wchar_t *) RelinquishMagickMemory(full_path);
+ return NULL;
+ }
+ WideCharToMultiByte(CP_UTF8,0,clean_path,-1,real_path,utf8_length,NULL,NULL);
+ full_path=(wchar_t *) RelinquishMagickMemory(full_path);
+ return(real_path);
+#endif
+}
+
static inline int remove_utf8(const char *path)
{
#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
Index: ImageMagick-7.1.0-9/MagickCore/utility.c
===================================================================
--- ImageMagick-7.1.0-9.orig/MagickCore/utility.c
+++ ImageMagick-7.1.0-9/MagickCore/utility.c
@@ -1036,16 +1036,23 @@ MagickPrivate MagickBooleanType GetExecu
#if defined(MAGICKCORE_HAVE__NSGETEXECUTABLEPATH)
{
char
- executable_path[PATH_MAX << 1],
- execution_path[PATH_MAX+1];
+ executable_path[PATH_MAX << 1];
uint32_t
length;
length=sizeof(executable_path);
- if ((_NSGetExecutablePath(executable_path,&length) == 0) &&
- (realpath(executable_path,execution_path) != (char *) NULL))
- (void) CopyMagickString(path,execution_path,extent);
+ if (_NSGetExecutablePath(executable_path,&length) == 0)
+ {
+ char
+ *real_path = realpath_utf8(executable_path);
+
+ if (real_path != (char *) NULL)
+ {
+ (void) CopyMagickString(path,real_path,extent);
+ real_path=DestroyString(real_path);
+ }
+ }
}
#endif
#if defined(MAGICKCORE_HAVE_GETEXECNAME)
@@ -1091,10 +1098,13 @@ MagickPrivate MagickBooleanType GetExecu
if (count != -1)
{
char
- execution_path[PATH_MAX+1];
+ *real_path = realpath_utf8(program_name);
- if (realpath(program_name,execution_path) != (char *) NULL)
- (void) CopyMagickString(path,execution_path,extent);
+ if (real_path != (char *) NULL)
+ {
+ (void) CopyMagickString(path,real_path,extent);
+ real_path=DestroyString(real_path);
+ }
}
if (program_name != program_invocation_name)
program_name=(char *) RelinquishMagickMemory(program_name);