From 540a4126f39a0b09ae68ccd43ae6de21092b4b3a Mon Sep 17 00:00:00 2001
From: Cristy <urban-warrior@imagemagick.org>
Date: Fri, 20 Feb 2026 19:55:20 -0500
Subject: [PATCH] partial TOCTOU patch:
 https://github.com/ImageMagick/ImageMagick/security/advisories/GHSA-493f-jh8w-qhx3

---
 config/policy-secure.xml |  2 ++
 magick/blob.c            | 48 +++++++++++++++++++++++++++++++++++++---
 2 files changed, 47 insertions(+), 3 deletions(-)

Index: ImageMagick-6.8.8-1/magick/blob.c
===================================================================
--- ImageMagick-6.8.8-1.orig/magick/blob.c
+++ ImageMagick-6.8.8-1/magick/blob.c
@@ -63,6 +63,7 @@
 #include "magick/token.h"
 #include "magick/utility.h"
 #include "magick/utility-private.h"
+#include "magick/exception-private.h"
 #if defined(MAGICKCORE_ZLIB_DELEGATE)
 #include "zlib.h"
 #endif
@@ -953,18 +954,39 @@ MagickExport unsigned char *FileToBlob(c
   void
     *map;
 
+  MagickBooleanType
+    status;
+
   assert(filename != (const char *) NULL);
   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
   assert(exception != (ExceptionInfo *) NULL);
   *length=0;
   file=fileno(stdin);
   if (LocaleCompare(filename,"-") != 0)
-    file=open_utf8(filename,O_RDONLY | O_BINARY,0);
+  {
+    int
+      flags = O_RDONLY | O_BINARY;
+#if defined(O_NOFOLLOW)
+    status=IsRightsAuthorized(SystemPolicyDomain,ReadPolicyRights,"follow");
+    if (status == MagickFalse)
+      flags|=O_NOFOLLOW;
+#endif
+    file=open_utf8(filename,flags,0);
+  }
   if (file == -1)
     {
       ThrowFileException(exception,BlobError,"UnableToOpenFile",filename);
       return((unsigned char *) NULL);
     }
+  status=IsRightsAuthorized(PathPolicyDomain,ReadPolicyRights,filename);
+  if (status == MagickFalse)
+    {
+      file=close(file)-1;
+      errno=EPERM;
+      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
+        "NotAuthorized","`%s'",filename);
+      return(NULL);
+    }
   offset=(MagickOffsetType) lseek(file,0,SEEK_END);
   count=0;
   if ((offset < 0) || (offset != (MagickOffsetType) ((ssize_t) offset)))
@@ -1144,19 +1166,41 @@ MagickExport MagickBooleanType FileToIma
   unsigned char
     *blob;
 
+  MagickBooleanType
+    status;
+
+
   assert(image != (const Image *) NULL);
   assert(image->signature == MagickSignature);
   assert(filename != (const char *) NULL);
   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
   file=fileno(stdin);
   if (LocaleCompare(filename,"-") != 0)
-    file=open_utf8(filename,O_RDONLY | O_BINARY,0);
+    {
+      int
+        flags = O_RDONLY | O_BINARY;
+
+#if defined(O_NOFOLLOW)
+      status=IsRightsAuthorized(SystemPolicyDomain,ReadPolicyRights,"follow");
+      if (status == MagickFalse)
+        flags|=O_NOFOLLOW;
+#endif
+      file=open_utf8(filename,flags,0);
+    }
   if (file == -1)
     {
       ThrowFileException(&image->exception,BlobError,"UnableToOpenBlob",
         filename);
       return(MagickFalse);
     }
+  status=IsRightsAuthorized(PathPolicyDomain,ReadPolicyRights,filename);
+  if (status == MagickFalse)
+    {
+      errno=EPERM;
+      (void) ThrowMagickException(&image->exception,GetMagickModule(),
+        PolicyError,"NotAuthorized","`%s'",filename);
+      return(MagickFalse);
+    }
   quantum=(size_t) MagickMaxBufferExtent;
   if ((fstat(file,&file_stats) == 0) && (file_stats.st_size != 0))
     quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
@@ -2639,6 +2683,13 @@ MagickExport MagickBooleanType OpenBlob(
 #endif
                 }
        }
+  if (IsRightsAuthorized(PathPolicyDomain,rights,filename) == MagickFalse)
+    {
+      errno=EPERM;
+      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
+        "NotAuthorized","`%s'",filename);
+      return(MagickFalse);
+    }
   image->blob->status=MagickFalse;
   if (image->blob->type != UndefinedStream)
     image->blob->size=GetBlobSize(image);
