Commit 7499ad060 for imagemagick.org
commit 7499ad060e4e5730242a33afa917a1a26385e197
Author: Cristy <urban-warrior@imagemagick.org>
Date: Fri Apr 17 21:57:53 2026 -0400
allow namespace::pattern when checking policy rights
diff --git a/MagickCore/blob.c b/MagickCore/blob.c
index 262013fa8..f4c175734 100644
--- a/MagickCore/blob.c
+++ b/MagickCore/blob.c
@@ -1475,7 +1475,7 @@ MagickExport void *FileToBlob(const char *filename,const size_t extent,
return(NULL);
}
#if defined(O_NOFOLLOW)
- status=IsRightsAuthorized(SystemPolicyDomain,ReadPolicyRights,"follow");
+ status=IsRightsAuthorized(SystemPolicyDomain,ReadPolicyRights,"symlink::follow");
if (status == MagickFalse)
flags|=O_NOFOLLOW;
#endif
@@ -1709,7 +1709,7 @@ MagickExport MagickBooleanType FileToImage(Image *image,const char *filename,
flags = O_RDONLY | O_BINARY;
#if defined(O_NOFOLLOW)
- status=IsRightsAuthorized(SystemPolicyDomain,ReadPolicyRights,"follow");
+ status=IsRightsAuthorized(SystemPolicyDomain,ReadPolicyRights,"symlink::follow");
if (status == MagickFalse)
flags|=O_NOFOLLOW;
#endif
@@ -3359,29 +3359,29 @@ MagickExport MagickBooleanType OpenBlob(const ImageInfo *image_info,
{
flags=O_RDONLY;
type="r";
- status=IsRightsAuthorized(SystemPolicyDomain,ReadPolicyRights,"follow");
+ status=IsRightsAuthorized(SystemPolicyDomain,ReadPolicyRights,"symlink::follow");
break;
}
case ReadBinaryBlobMode:
{
flags=O_RDONLY | O_BINARY;
type="rb";
- status=IsRightsAuthorized(SystemPolicyDomain,ReadPolicyRights,"follow");
+ status=IsRightsAuthorized(SystemPolicyDomain,ReadPolicyRights,"symlink::follow");
break;
}
case WriteBlobMode:
{
flags=O_WRONLY | O_CREAT | O_TRUNC;
type="w";
- status=IsRightsAuthorized(SystemPolicyDomain,WritePolicyRights,"follow");
+ status=IsRightsAuthorized(SystemPolicyDomain,WritePolicyRights,"symlink::follow");
break;
}
case WriteBinaryBlobMode:
{
flags=O_RDWR | O_CREAT | O_TRUNC | O_BINARY;
type="w+b";
- status=IsRightsAuthorized(SystemPolicyDomain,ReadPolicyRights,"follow") &&
- IsRightsAuthorized(SystemPolicyDomain,WritePolicyRights,"follow") ?
+ status=IsRightsAuthorized(SystemPolicyDomain,ReadPolicyRights,"symlink::follow") &&
+ IsRightsAuthorized(SystemPolicyDomain,WritePolicyRights,"symlink::follow") ?
MagickTrue : MagickFalse;
break;
}
@@ -3389,15 +3389,15 @@ MagickExport MagickBooleanType OpenBlob(const ImageInfo *image_info,
{
flags=O_WRONLY | O_CREAT | O_APPEND;
type="a";
- status=IsRightsAuthorized(SystemPolicyDomain,WritePolicyRights,"follow");
+ status=IsRightsAuthorized(SystemPolicyDomain,WritePolicyRights,"symlink::follow");
break;
}
case AppendBinaryBlobMode:
{
flags=O_RDWR | O_CREAT | O_APPEND | O_BINARY;
type="a+b";
- status=IsRightsAuthorized(SystemPolicyDomain,ReadPolicyRights,"follow") &&
- IsRightsAuthorized(SystemPolicyDomain,WritePolicyRights,"follow") ?
+ status=IsRightsAuthorized(SystemPolicyDomain,ReadPolicyRights,"symlink::follow") &&
+ IsRightsAuthorized(SystemPolicyDomain,WritePolicyRights,"symlink::follow") ?
MagickTrue : MagickFalse;
break;
}
@@ -3405,7 +3405,7 @@ MagickExport MagickBooleanType OpenBlob(const ImageInfo *image_info,
{
flags=O_RDONLY;
type="r";
- status=IsRightsAuthorized(SystemPolicyDomain,ReadPolicyRights,"follow");
+ status=IsRightsAuthorized(SystemPolicyDomain,ReadPolicyRights,"symlink::follow");
break;
}
}
diff --git a/MagickCore/nt-base-private.h b/MagickCore/nt-base-private.h
index 550c339f0..0cec86eb7 100644
--- a/MagickCore/nt-base-private.h
+++ b/MagickCore/nt-base-private.h
@@ -190,7 +190,7 @@ extern MagickPrivate MagickBooleanType
NTReportEvent(const char *,const MagickBooleanType);
extern MagickExport MagickBooleanType
- NTIsLinkWide(const char *),
+ NTIsSymlinkWide(const char *),
NTLongPathsEnabled(void);
extern MagickPrivate struct dirent
diff --git a/MagickCore/nt-base.c b/MagickCore/nt-base.c
index d2966cf94..67ca97992 100644
--- a/MagickCore/nt-base.c
+++ b/MagickCore/nt-base.c
@@ -1623,19 +1623,19 @@ MagickPrivate void NTGhostscriptUnLoadDLL(void)
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
-% NTIsLinkWide() returns a boolean value indicating whether the specified path
+% NTIsSymlinkWide() returns a boolean value indicating whether the specified path
% is a a link.
%
-% The format of the NTIsLinkWide method is:
+% The format of the NTIsSymlinkWide method is:
%
-% MagickBooleanType NTIsLinkWide(const char *path)
+% MagickBooleanType NTIsSymlinkWide(const char *path)
%
% A description of each parameter follows:
%
% o path: the file path.
%
*/
-MagickExport MagickBooleanType NTIsLinkWide(const char *path)
+MagickExport MagickBooleanType NTIsSymlinkWide(const char *path)
{
DWORD
attributes;
diff --git a/MagickCore/policy.c b/MagickCore/policy.c
index 2d96f5dce..25e9467bf 100644
--- a/MagickCore/policy.c
+++ b/MagickCore/policy.c
@@ -626,7 +626,7 @@ static MagickBooleanType IsPolicyCacheInstantiated(ExceptionInfo *exception)
% The format of the IsRightsAuthorized method is:
%
% MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
-% const PolicyRights rights,const char *pattern)
+% const PolicyRights rights,const char *qualified_pattern)
%
% A description of each parameter follows:
%
@@ -634,13 +634,53 @@ static MagickBooleanType IsPolicyCacheInstantiated(ExceptionInfo *exception)
%
% o rights: the policy rights.
%
-% o pattern: the coder, delegate, filter, or path pattern.
+% o qualified_pattern: the pattern.
%
*/
+
+static inline MagickBooleanType ParseNamespace(
+ const char *restrict qualified_pattern,char **name,char **pattern)
+{
+ const char
+ *p,
+ *separator;
+
+ size_t
+ length;
+
+ if ((qualified_pattern == (const char *) NULL) || (name == (char **) NULL) ||
+ (pattern == (char **) NULL))
+ return(MagickFalse);
+ *name=(char *) NULL;
+ *pattern=(char *) NULL;
+ separator=strstr(qualified_pattern,"::");
+ if (separator == (const char *) NULL)
+ {
+ *pattern=AcquireString(qualified_pattern);
+ return(*pattern != (char *) NULL ? MagickTrue : MagickFalse);
+ }
+ length=(size_t) (separator-qualified_pattern);
+ *name=(char *) AcquireQuantumMemory(length+1,sizeof(char));
+ if (*name == (char *) NULL)
+ return(MagickFalse);
+ (void) CopyMagickString(*name,qualified_pattern,length+1);
+ p=separator+2;
+ *pattern=AcquireString(p);
+ if (*pattern == (char *) NULL)
+ {
+ *name=DestroyString(*name);
+ *name=(char *) NULL;
+ return(MagickFalse);
+ }
+ return(MagickTrue);
+}
+
MagickExport MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
- const PolicyRights rights,const char *pattern)
+ const PolicyRights rights,const char *qualified_pattern)
{
char
+ *name = (char *) NULL,
+ *pattern = (char *) NULL,
*real_pattern = (char *) NULL;
const PolicyInfo
@@ -650,7 +690,7 @@ MagickExport MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
*exception;
MagickBooleanType
- authorized,
+ authorized = MagickTrue,
match;
ElementInfo
@@ -660,13 +700,15 @@ MagickExport MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
(void) LogMagickEvent(PolicyEvent,GetMagickModule(),
"Domain: %s; rights=%s; pattern=\"%s\" ...",
CommandOptionToMnemonic(MagickPolicyDomainOptions,domain),
- CommandOptionToMnemonic(MagickPolicyRightsOptions,rights),pattern);
+ CommandOptionToMnemonic(MagickPolicyRightsOptions,rights),
+ qualified_pattern);
exception=AcquireExceptionInfo();
policy_info=GetPolicyInfo("*",exception);
exception=DestroyExceptionInfo(exception);
if (policy_info == (PolicyInfo *) NULL)
return(MagickTrue);
- authorized=MagickTrue;
+ if (ParseNamespace(qualified_pattern,&name,&pattern) == MagickFalse)
+ return(MagickFalse);
LockSemaphoreInfo(policy_semaphore);
p=GetHeadElementInLinkedList(policy_cache);
while (p != (ElementInfo *) NULL)
@@ -675,7 +717,8 @@ MagickExport MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
*policy;
policy=(const PolicyInfo *) p->value;
- if (policy->domain == domain)
+ if ((policy->domain == domain) &&
+ ((name == (char *) NULL) || (LocaleCompare(name,policy->name) == 0)))
{
if ((policy->domain == PathPolicyDomain) &&
(real_pattern == (const char *) NULL))
@@ -687,8 +730,8 @@ MagickExport MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
if (match != MagickFalse)
{
if ((rights & ReadPolicyRights) != 0)
- authorized=(policy->rights & ReadPolicyRights) != 0 ? MagickTrue :
- MagickFalse;
+ authorized=(policy->rights & ReadPolicyRights) != 0 ?
+ MagickTrue : MagickFalse;
if ((rights & WritePolicyRights) != 0)
authorized=(policy->rights & WritePolicyRights) != 0 ?
MagickTrue : MagickFalse;
@@ -700,6 +743,10 @@ MagickExport MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
p=p->next;
}
UnlockSemaphoreInfo(policy_semaphore);
+ if (pattern != (char *) NULL)
+ pattern=DestroyString(pattern);
+ if (name != (char *) NULL)
+ name=DestroyString(name);
if (real_pattern != (char *) NULL)
real_pattern=DestroyString(real_pattern);
return(authorized);
diff --git a/MagickCore/utility-private.h b/MagickCore/utility-private.h
index ae2928dc5..df6f45054 100644
--- a/MagickCore/utility-private.h
+++ b/MagickCore/utility-private.h
@@ -82,7 +82,7 @@ static inline FILE *fopen_utf8(const char *path,const char *mode)
#endif
}
-static inline MagickBooleanType is_link_utf8(const char *path)
+static inline MagickBooleanType is_symlink_utf8(const char *path)
{
#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
#if defined(MAGICKCORE_POSIX_SUPPORT)
@@ -96,7 +96,7 @@ static inline MagickBooleanType is_link_utf8(const char *path)
return(MagickFalse);
#endif
#else
- return(NTIsLinkWide(path));
+ return(NTIsSymlinkWide(path));
#endif
}
diff --git a/MagickCore/utility.c b/MagickCore/utility.c
index 4258f7f19..edbc8e8be 100644
--- a/MagickCore/utility.c
+++ b/MagickCore/utility.c
@@ -184,7 +184,7 @@ MagickExport MagickBooleanType AcquireUniqueSymbolicLink(const char *source,
Does policy permit symbolic links?
*/
status=IsRightsAuthorized(SystemPolicyDomain,(PolicyRights)
- (ReadPolicyRights | WritePolicyRights),"follow");
+ (ReadPolicyRights | WritePolicyRights),"symlink::follow");
passes=GetPolicyValue("system:shred");
if ((passes != (char *) NULL) || (status == MagickFalse))
passes=DestroyString(passes);