Giter VIP home page Giter VIP logo

demoiccmax's Issues

documenting tags

I'd like to start documenting enums in IccProfLib/icProfileHeader.h something like this, which could be hyperlinked to specification in generated docs, and wanted to check if the format and such before I start doing a bunch:

`
/**

  • public tags and sizes
  • @see ICC.2:2003 Section 9
  • @see ICC.2:2003 Section 12
    /
    typedef enum {
    icSigAToB0Tag = 0x41324230, /
    'A2B0' §9.2.1 /
    icSigAToB1Tag = 0x41324231, /
    'A2B1' §9.2.2 /
    icSigAToB2Tag = 0x41324232, /
    'A2B2' §9.2.3 /
    icSigAToB3Tag = 0x41324233, /
    'A2B3' §9.2.4 /
    icSigAToM0Tag = 0x41324d30, /
    'A2M0' §9.2.5 /
    icSigBlueColorantTag = 0x6258595A, /
    'bXYZ' §12.2.3.2.1 /
    icSigBlueMatrixColumnTag = 0x6258595A, /
    'bXYZ' §12.2.3.2.1 /
    icSigBlueTRCTag = 0x62545243, /
    'bTRC' /
    icSigBrdfColorimetricParameter0Tag = 0x62637030, /
    'bcp0' §9.2.6 /
    icSigBrdfColorimetricParameter1Tag = 0x62637031, /
    'bcp1' §9.2.7 /
    icSigBrdfColorimetricParameter2Tag = 0x62637032, /
    'bcp2' §9.2.8 /
    icSigBrdfColorimetricParameter3Tag = 0x62637033, /
    'bcp3' §9.2.9 /
    icSigBrdfSpectralParameter0Tag = 0x62737030, /
    'bsp0' §9.2.10 /
    icSigBrdfSpectralParameter1Tag = 0x62737031, /
    'bsp1' §9.2.11 /
    icSigBrdfSpectralParameter2Tag = 0x62737032, /
    'bsp2' §9.2.12 /
    icSigBrdfSpectralParameter3Tag = 0x62737033, /
    'bsp3' §9.2.13 /
    icSigBRDFAToB0Tag = 0x62414230, /
    'bAB0' §9.2.14 /
    icSigBRDFAToB1Tag = 0x62414231, /
    'bAB1' §9.2.15 /
    icSigBRDFAToB2Tag = 0x62414232, /
    'bAB2' §9.2.16 /
    icSigBRDFAToB3Tag = 0x62414233, /
    'bAB3' §9.2.17 /
    icSigBRDFDToB0Tag = 0x62444230, /
    'bDB0' §9.2.26 /
    icSigBRDFDToB1Tag = 0x62444231, /
    'bDB1' §9.2.27 /
    icSigBRDFDToB2Tag = 0x62444232, /
    'bDB2' §9.2.28 /
    icSigBRDFDToB3Tag = 0x62444233, /
    'bDB3' §9.2.29 /
    icSigBRDFMToB0Tag = 0x624D4230, /
    'bMB0' §9.2.30 /
    icSigBRDFMToB1Tag = 0x624D4231, /
    'bMB1' §9.2.31*/
    icSigBRDFMToB2Tag = 0x624D4232, /* 'bMB2' §9.2.32 /
    icSigBRDFMToB3Tag = 0x624D4233, /
    'bMB3' §9.2.33 /
    icSigBRDFMToS0Tag = 0x624D5330, /
    'bMS0' §9.2.34 /
    icSigBRDFMToS1Tag = 0x624D5331, /
    'bMS1' §9.2.35 /
    icSigBRDFMToS2Tag = 0x624D5332, /
    'bMS2' §9.2.36 /
    icSigBRDFMToS3Tag = 0x624D5333, /
    'bMS3' §9.2.37 /
    icSigBToA0Tag = 0x42324130, /
    'B2A0' §9.2.38 /
    icSigBToA1Tag = 0x42324131, /
    'B2A1' §9.2.39 /
    icSigBToA2Tag = 0x42324132, /
    'B2A2' §9.2.40 /
    icSigBToA3Tag = 0x42324133, /
    'B2A3' §9.2.41 /
    icSigCalibrationDateTimeTag = 0x63616C74, /
    'calt' §9.2.46 /
    icSigCharTargetTag = 0x74617267, /
    'targ' §9.2.47 /
    icSigChromaticAdaptationTag = 0x63686164, /
    'chad' /
    icSigChromaticityTag = 0x6368726D, /
    'chrm' /
    icSigCicpTag = 0x63696370, /
    'cicp' §9.2.48 /
    icSigColorEncodingParamsTag = 0x63657074, /
    'cept' §9.2.49 /
    icSigColorSpaceNameTag = 0x63736e6d, /
    'csnm' §9.2.50 /
    icSigColorantInfoTag = 0x636c696e, /
    'clin' §9.2.53 /
    icSigColorantInfoOutTag = 0x636c696f, /
    'clio' §9.2.54 /
    icSigColorantOrderTag = 0x636C726F, /
    'clro' §9.2.51 /
    icSigColorantOrderOutTag = 0x636c6f6f, /
    'cloo' §9.2.52 /
    icSigColorantTableTag = 0x636C7274, /
    'clrt' /
    icSigColorantTableOutTag = 0x636C6F74, /
    'clot' /
    icSigColorimetricIntentImageStateTag = 0x63696973, /
    'ciis' §9.2.55 /
    icSigCopyrightTag = 0x63707274, /
    'cprt' §9.2.56 /
    icSigCrdInfoTag = 0x63726469, /
    'crdi' Removed in V4 /
    icSigCustomToStandardPccTag = 0x63327370, /
    'c2sp' §9.2.57 /
    icSigCxFTag = 0x43784620, /
    'CxF ' §9.2.58 /
    icSigDataTag = 0x64617461, /
    'data' Removed in V4 /
    icSigDateTimeTag = 0x6474696D, /
    'dtim' Removed in V4 /
    #if 0 // not documented!
    icSigDeviceMediaWhitePointTag = 0x646d7770, /
    'dmwp' /
    #endif
    icSigDeviceMfgDescTag = 0x646D6E64, /
    'dmnd' §9.2.59 /
    icSigDeviceModelDescTag = 0x646D6464, /
    'dmdd' §9.2.60 /
    icSigDeviceSettingsTag = 0x64657673, /
    'devs' Removed in V4 /
    icSigDToB0Tag = 0x44324230, /
    'D2B0' §9.2.77 /
    icSigDToB1Tag = 0x44324231, /
    'D2B1' §9.2.78 /
    icSigDToB2Tag = 0x44324232, /
    'D2B2' §9.2.79 /
    icSigDToB3Tag = 0x44324233, /
    'D2B3' §9.2.80 /
    icSigBToD0Tag = 0x42324430, /
    'B2D0' §9.2.42 /
    icSigBToD1Tag = 0x42324431, /
    'B2D1' §9.2.43 /
    icSigBToD2Tag = 0x42324432, /
    'B2D2' §9.2.44 /
    icSigBToD3Tag = 0x42324433, /
    'B2D3' §9.2.45 /
    icSigGamutTag = 0x67616D74, /
    'gamt' /
    icSigGamutBoundaryDescription0Tag = 0x67626430, /
    'gbd0' §9.2.81 /
    icSigGamutBoundaryDescription1Tag = 0x67626431, /
    'gbd1' §9.2.82 /
    icSigGamutBoundaryDescription2Tag = 0x67626432, /
    'gbd2' §9.2.83 /
    icSigGamutBoundaryDescription3Tag = 0x67626433, /
    'gbd3' §9.2.84 /
    icSigHToS0Tag = 0x48325330, /
    'H2S0' §9.2.85 /
    icSigHToS1Tag = 0x48325331, /
    'H2S1' §9.2.86 /
    icSigHToS2Tag = 0x48325332, /
    'H2S2' §9.2.87 /
    icSigHToS3Tag = 0x48325333, /
    'H2S3' §9.2.88 /
    icSigGrayTRCTag = 0x6b545243, /
    'kTRC' /
    icSigGreenColorantTag = 0x6758595A, /
    'gXYZ' §12.2.3.2.2 /
    icSigGreenMatrixColumnTag = 0x6758595A, /
    'gXYZ' §12.2.3.2.2 /
    icSigGreenTRCTag = 0x67545243, /
    'gTRC' /
    icSigLuminanceTag = 0x6C756d69, /
    'lumi' /
    icSigMaterialDefaultValuesTag = 0x6D647620, /
    'mdv ' §9.2.89 /
    icSigMaterialTypeArrayTag = 0x6d637461, /
    'mcta' §9.2.90 /
    icSigMToA0Tag = 0x4d324130, /
    'M2A0' §9.2.95 /
    icSigMToB0Tag = 0x4d324230, /
    'M2B0' §9.2.96 /
    icSigMToB1Tag = 0x4d324231, /
    'M2B1' §9.2.97 /
    icSigMToB2Tag = 0x4d324232, /
    'M2B2' §9.2.98 /
    icSigMToB3Tag = 0x4d324233, /
    'M2B3' §9.2.99 /
    icSigMToS0Tag = 0x4d325330, /
    'M2S0' §9.2.100 /
    icSigMToS1Tag = 0x4d325331, /
    'M2S1' §9.2.101 /
    icSigMToS2Tag = 0x4d325332, /
    'M2S2' §9.2.102 /
    icSigMToS3Tag = 0x4d325333, /
    'M2S3' §9.2.103 /
    icSigMeasurementTag = 0x6D656173, /
    'meas' /
    icSigMediaBlackPointTag = 0x626B7074, /
    'bkpt' /
    icSigMediaWhitePointTag = 0x77747074, /
    'wtpt' §9.2.93 /
    icSigMetaDataTag = 0x6D657461, /
    'meta' §9.2.94 /
    #if 0
    icSigNamedColorTag = 0x6E636f6C, /
    'ncol' OBSOLETE, use ncl2 /
    #endif
    icSigNamedColorTag = 0x6e6d636C, /
    'nmcl' use for V5 §9.2.104 /
    icSigNamedColor2Tag = 0x6E636C32, /
    'ncl2' /
    icSigOutputResponseTag = 0x72657370, /
    'resp' /
    icSigPerceptualRenderingIntentGamutTag = 0x72696730, /
    'rig0' §9.2.105 /
    icSigPreview0Tag = 0x70726530, /
    'pre0' /
    icSigPreview1Tag = 0x70726531, /
    'pre1' /
    icSigPreview2Tag = 0x70726532, /
    'pre2' /
    icSigPrintConditionTag = 0x7074636e, /
    'ptcn' /
    icSigProfileDescriptionTag = 0x64657363, /
    'desc' §9.2.106 /
    icSigProfileSequenceDescTag = 0x70736571, /
    'pseq' /
    icSigProfileSequceIdTag = 0x70736964, /
    'psid' /
    icSigPs2CRD0Tag = 0x70736430, /
    'psd0' Removed in V4 /
    icSigPs2CRD1Tag = 0x70736431, /
    'psd1' Removed in V4 /
    icSigPs2CRD2Tag = 0x70736432, /
    'psd2' Removed in V4 /
    icSigPs2CRD3Tag = 0x70736433, /
    'psd3' Removed in V4 /
    icSigPs2CSATag = 0x70733273, /
    'ps2s' Removed in V4 /
    icSigPs2RenderingIntentTag = 0x70733269, /
    'ps2i' Removed in V4 /
    icSigRedColorantTag = 0x7258595A, /
    'rXYZ' §12.2.3.2.3 /
    icSigRedMatrixColumnTag = 0x7258595A, /
    'rXYZ' §12.2.3.2.3 /
    icSigRedTRCTag = 0x72545243, /
    'rTRC' /
    icSigReferenceNameTag = 0x72666e6d, /
    'rfnm' §9.2.108 /
    icSigSaturationRenderingIntentGamutTag = 0x72696732, /
    'rig2' §9.2.109 /
    icSigScreeningDescTag = 0x73637264, /
    'scrd' Removed in V4 /
    icSigScreeningTag = 0x7363726E, /
    'scrn' Removed in V4 /
    icSigSpectralDataInfoTag = 0x7364696e, /
    'sdin' /
    icSigSpectralWhitePointTag = 0x73777074, /
    'swpt' §9.2.112 /
    icSigSpectralViewingConditionsTag = 0x7376636e, /
    'svcn' §9.2.111 /
    icSigStandardToCustomPccTag = 0x73326370, /
    's2cp' §9.2.113 /
    icSigSurfaceMapTag = 0x736D6170, /
    'smap' §9.2.114 /
    icSigTechnologyTag = 0x74656368, /
    'tech' §9.2.115 /
    icSigUcrBgTag = 0x62666420, /
    'bfd ' Removed in V4 /
    icSigViewingCondDescTag = 0x76756564, /
    'vued' /
    icSigViewingConditionsTag = 0x76696577, /
    'view' */

/* Private tags*/
icSigEmbeddedV5ProfileTag = 0x49434335, /* 'ICC5' */
} icTagSignature;
`

Does it possible to create CMYK output icc profile using this SDK?

I'm a newbie with color technology and I'm interested in IccMax SDK.
I want to create a CMYK icc profile from some patches like IT8/7.4 CGATS.

These days I study Icc Profiles specifications V2, V4, Color Management(Wiley) and try to create an icc profile.
wow, it is a complex topic which involves a wide range of disciplines including computer science, numerical analysis, and colour science.

but I encountered some problems.
1)I don't know what data(format, values...) for APIs when I try to use these functions.
2)No any API document that I don't know how to start.
3)I can't find any examples for CMYK output icc profiling.

Q1)Do you have any plan to design CxF3 SDK for reading and writing?
Q2)Could you give me advice about creating CMYK output icc profile?

Thanks

Bugs from Fuzzing

Bug 1 - Heap Buffer Overflow in CIccCLUT::Interp3d | CVE-2023-46866

Patch in PR #64

Severity: Reference Implementation | High

Description

A heap buffer overflow has been identified in the CIccCLUT::Interp3d method. This vulnerability can lead to potential crashes or undefined behavior when certain conditions are met.

Steps to Reproduce

Utilize the CIccCLUT::Interp3d method on a CIccCLUT object under conditions where m_nNumPoints * m_nOutput equals 0.
Attempt to access indices beyond the allocated size of the m_pData array.

Debug Session

(lldb) fr se 5
frame #5: 0x0000000100e8c982 libIccProfLib2.2.dylib`CIccCLUT::Interp3d(this=0x0000614000000440, destPixel=0x00007ff7bfefde80, srcPixel=0x00007ff7bfefde80) const at IccTagLut.cpp:2594:27
   2591	               return;
   2592	           }
   2593
-> 2594	           destPixel[i] = p[n000] * dF0 + p[n001] * dF1 + p[n010] * dF2 + p[n011] * dF3 +
   2595	                          p[n100] * dF4 + p[n101] * dF5 + p[n110] * dF6 + p[n111] * dF7;
   2596	       }
   2597	   }
(lldb) frame variable
(CIccCLUT *) this = 0x0000614000000440
(icFloatNumber *) destPixel = 0x00007ff7bfefde80
(const icFloatNumber *) srcPixel = 0x00007ff7bfefde80
(icUInt8Number) mx = '\xff'
(icUInt8Number) my = '\xff'
(icUInt8Number) mz = '\xff'
(icFloatNumber) x = 0
(icFloatNumber) y = 0
(icFloatNumber) z = 0
(icUInt32Number) ix = 0
(icUInt32Number) iy = 0
(icUInt32Number) iz = 0
(icFloatNumber) u = 0
(icFloatNumber) t = 0
(icFloatNumber) s = 0
(icFloatNumber) ns = 1
(icFloatNumber) nt = 1
(icFloatNumber) nu = 1
(icFloatNumber) dF0 = 1
(icFloatNumber) dF1 = 0
(icFloatNumber) dF2 = 0
(icFloatNumber) dF3 = 0
(icFloatNumber) dF4 = 0
(icFloatNumber) dF5 = 0
(icFloatNumber) dF6 = 0
(icFloatNumber) dF7 = 0
(icUInt32Number) maxIndex = 50331647
(icFloatNumber *) pStart = 0x00006020000002d0
(int) i = 0
(icFloatNumber *) p = 0x00006020000002d0
(lldb) dis -s $pc-32 -c 24
libIccProfLib2.2.dylib`CIccCLUT::Interp3d:
    0x100e8c962 <+2978>: loopne 0x100e8c961               ; <+2977> at IccTagLut.cpp

Symptoms

  • The program crashes with an AddressSanitizer report indicating a heap-buffer-overflow in CIccCLUT::Interp3d.
  • The value of m_nNumPoints * m_nOutput is 0, indicating that the m_pData array might not have been allocated or is of size 0.
  • Attempts are made to access indices as high as 3 and potentially up to 50331647 (as indicated by the maxIndex variable).

Potential Causes

  • Improper initialization or setup of the CIccCLUT object.
  • Possible errors in the copy constructor or assignment operator of CIccCLUT.
    -The m_pData array might be reallocated with a different size elsewhere in the code.
    -Invalid or corrupt input data affecting the CIccCLUT object's construction.

Bug 2 - Segmentation Fault in CIccXformMatrixTRC::GetCurve | CVE-2023-46867

Severity: Reference Implementation | High

Description

A segmentation fault (SEGV) has been identified in the CIccXformMatrixTRC::GetCurve method within the IccCmm.cpp file, specifically at line 5240. The crash appears to be due to a read memory access at the zero address, suggesting a potential null pointer dereference.

Steps to Reproduce

Invoke the CIccXformMatrixTRC::GetCurve method with specific input that triggers the SEGV.
The exact input causing this behavior needs further investigation.
Observe the crash due to a segmentation fault.

Crash Details

AddressSanitizer:DEADLYSIGNAL
=================================================================
==59095==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x000104511cd4 bp 0x7ff7bc556550 sp 0x7ff7bc556500 T0)
==59095==The signal is caused by a READ memory access.
==59095==Hint: address points to the zero page.
    #0 0x104511cd4 in CIccXformMatrixTRC::GetCurve(unsigned int) const IccCmm.cpp:5240
    #1 0x10451107a in CIccXformMatrixTRC::Begin() IccCmm.cpp:5100
    #2 0x1045394a8 in CIccCmm::Begin(bool, bool) IccCmm.cpp:8297
    #3 0x1045905a4 in CIccEvalCompare::EvaluateProfile(CIccProfile*, unsigned char, icRenderingIntent, icXformInterp, bool) IccEval.cpp:110
    #4 0x104591419 in CIccEvalCompare::EvaluateProfile(char const*, unsigned char, icRenderingIntent, icXformInterp, bool) IccEval.cpp:197
    #5 0x1039ae0d2 in main iccRoundTrip.cpp:168
    #6 0x7ff80dee53a5 in start+0x795 (dyld:x86_64+0xfffffffffff5c3a5)

==59095==Register values:
rax = 0x0000000000000000  rbx = 0x00007ff7bc556900  rcx = 0x0000100000000000  rdx = 0x0000000000000000
rdi = 0x00007ff7bc5562c0  rsi = 0x00007ff7bc556320  rbp = 0x00007ff7bc556550  rsp = 0x00007ff7bc556500
 r8 = 0x0000604000001610   r9 = 0xf3f3f300f1f1f100  r10 = 0x00007fffffffffff  r11 = 0xffffffffffffff20
r12 = 0x00007ff7bc557590  r13 = 0x0000000000000000  r14 = 0x00000001039addb0  r15 = 0x00007ff7bc557710
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV IccCmm.cpp:5240 in CIccXformMatrixTRC::GetCurve(unsigned int) const

Symptoms

The program crashes with an AddressSanitizer report indicating a SEGV in CIccXformMatrixTRC::GetCurve.
The memory access causing the SEGV is a read operation from address 0x000000000000, which points to the zero page.
The crash occurs specifically at line IccCmm.cpp:5240.

Potential Causes

Dereferencing a null pointer or uninitialized pointer in the CIccXformMatrixTRC::GetCurve method.
An invalid curve index or parameter passed to the method, leading to out-of-bounds memory access.
Memory corruption elsewhere in the application affecting the behavior of the CIccXformMatrixTRC::GetCurve method.

Bugs 3 - 6

Bug Report: Undefined Behavior in IccTagLut.cpp and IccProfileXml.cpp

Severity: Reference Implementation | High

The UndefinedBehaviorSanitizer tool has identified multiple instances of undefined behavior within the IccTagLut.cpp and IccProfileXml.cpp files.

Bug 3 Description

File: IccTagLut.cpp
Line: 1798
Issue: Index -1 is being used to access an array of type icUInt32Number[16], which results in out-of-bounds access.

Bug 4 Description

File: IccTagLut.cpp
Line: 1799
Issue: Index -1 is being used to access an array of type icUInt8Number[16], which results in out-of-bounds access.

Bug 5 Description

File: IccProfileXml.cpp
Line: 128
Issue: Loading a value 2543294359 which is not a valid value for the type icPlatformSignature.

Bug 6 Description

File: IccProfileXml.cpp
Line: 129
Issue: Loading a value 2543294359 which is not a valid value for the type icPlatformSignature.

Bug 7 - Heap Buffer Overflow in CIccXmlArrayType::ParseText | CVE-2023-47249

Severity: Reference Implementation | High

Description

A heap buffer overflow has been identified in the function CIccXmlArrayType::ParseText at IccUtilXml.cpp:1003:10. This function is designed to parse text into an array, with a specific instantiation for unsigned short. The buffer overflow occurs during the parsing process, specifically in a loop condition where a buffer bound check fails, leading to an out-of-bounds read.

Variables at Crash Time:
pBuf: A pointer to the buffer where parsed data is stored.
nSize: The size of the buffer (4096).
szText: A pointer to the text being parsed.
n: Counter variable, which is also 4096 at the time of the crash.
Crash Location in Code:

The crash occurs in the loop: while (*szText && n<nSize) {.
The error indicates that when n equals nSize, the loop still attempts to read *szText, which is beyond the allocated buffer.

Steps to Reproduce

PoC

Testing % ./iccFromXML mcs/17ChanWithSpots-MVIS.xml mcs/17ChanWithSpots-MVIS.icc

Crash Details

mcs % ../iccFromXML 17ChanWithSpots-MVIS.xml 17ChanWithSpots-MVIS.icc
...
SUMMARY: AddressSanitizer: heap-buffer-overflow IccUtilXml.cpp:1003 in CIccXmlArrayType<unsigned short, (icTagTypeSignature)1969828150>::ParseText(unsigned short*, unsigned int, char const*)

Bug 8 - Floating Point Error in iccSpecSepToTiff.cpp at line 120

Patch in PR #64

Reproduction

./iccSpecSepToTiff out.tif 0 0 Overprint/17ChanData.txt 1 2 ~/Documents/2225-original.icc

Description

Arithmetic Error:

The crashing line (-> 0x100006251 <+1585>: idivl 0x230(%rbx)) suggests a division operation.
The corresponding source code line (120 n = (end-start)/step + 1;) is performing a division operation. If step is zero, this operation will cause a division by zero error, leading to an FPE.

Bug 9 SUMMARY: AddressSanitizer: heap-buffer-overflow IccUtilXml.cpp:1062 in CIccXmlArrayType<float, (icTagTypeSignature)1717793824>::ParseText(float*, unsigned int, char const*)

mcs % lldb -- ../../Build/Tools/IccFromXml/iccFromXML 18ChanWithSpots-MVIS.xml 18ChanWithSpots-MVIS.icc
(lldb) target create "../../Build/Tools/IccFromXml/iccFromXML"
Current executable set to 'DemoIccMAX-master/Build/Tools/IccFromXml/iccFromXML' (x86_64).
(lldb) settings set -- target.run-args  "18ChanWithSpots-MVIS.xml" "18ChanWithSpots-MVIS.icc"
(lldb) r
Process 79070 launched: 'DemoIccMAX-master/Build/Tools/IccFromXml/iccFromXML' (x86_64)
=================================================================
==79070==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x00010040340c at pc 0x000100990dc5 bp 0x7ff7bfefac70 sp 0x7ff7bfefac68
READ of size 1 at 0x00010040340c thread T0
    #0 0x100990dc4 in CIccXmlArrayType<float, (icTagTypeSignature)1717793824>::ParseText(float*, unsigned int, char const*) IccUtilXml.cpp:1062
    #1 0x100992462 in CIccXmlArrayType<float, (icTagTypeSignature)1717793824>::ParseTextArrayNum(char const*, unsigned int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) IccUtilXml.cpp:818
    #2 0x10094e784 in icCLutFromXml(_xmlNode*, int, int, icConvertType, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) IccTagXml.cpp:3544
    #3 0x1008b46ff in CIccMpeXmlExtCLUT::ParseXml(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) IccMpeXml.cpp:1935
    #4 0x1008bf990 in CIccMpeXmlCalculator::ParseImport(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) IccMpeXml.cpp:2577
    #5 0x1008d170f in CIccMpeXmlCalculator::ParseXml(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) IccMpeXml.cpp:3094
    #6 0x10095561d in CIccTagXmlMultiProcessElement::ParseElement(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) IccTagXml.cpp:4081
    #7 0x1009567b9 in CIccTagXmlMultiProcessElement::ParseXml(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) IccTagXml.cpp:4141
    #8 0x10090b119 in CIccProfileXml::ParseTag(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) IccProfileXml.cpp:711
    #9 0x10090c924 in CIccProfileXml::ParseXml(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) IccProfileXml.cpp:820
    #10 0x10090cd5b in CIccProfileXml::LoadXml(char const*, char const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*) IccProfileXml.cpp:877
    #11 0x10000406c in main IccFromXml.cpp:68
    #12 0x7ff816e9f365 in start+0x795 (dyld:x86_64+0xfffffffffff5c365)

0x00010040340c is located 0 bytes after 2259980-byte region [0x0001001db800,0x00010040340c)
allocated by thread T0 here:
    #0 0x101743a20 in wrap_malloc+0xa0 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xdca20)
    #1 0x10094d4f1 in icCLutFromXml(_xmlNode*, int, int, icConvertType, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) IccTagXml.cpp:3439
    #2 0x1008b46ff in CIccMpeXmlExtCLUT::ParseXml(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) IccMpeXml.cpp:1935
    #3 0x1008bf990 in CIccMpeXmlCalculator::ParseImport(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) IccMpeXml.cpp:2577
    #4 0x1008d170f in CIccMpeXmlCalculator::ParseXml(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) IccMpeXml.cpp:3094
    #5 0x10095561d in CIccTagXmlMultiProcessElement::ParseElement(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) IccTagXml.cpp:4081
    #6 0x1009567b9 in CIccTagXmlMultiProcessElement::ParseXml(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) IccTagXml.cpp:4141
    #7 0x10090b119 in CIccProfileXml::ParseTag(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) IccProfileXml.cpp:711
    #8 0x10090c924 in CIccProfileXml::ParseXml(_xmlNode*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) IccProfileXml.cpp:820
    #9 0x10090cd5b in CIccProfileXml::LoadXml(char const*, char const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*) IccProfileXml.cpp:877
    #10 0x10000406c in main IccFromXml.cpp:68
    #11 0x7ff816e9f365 in start+0x795 (dyld:x86_64+0xfffffffffff5c365)

SUMMARY: AddressSanitizer: heap-buffer-overflow IccUtilXml.cpp:1062 in CIccXmlArrayType<float, (icTagTypeSignature)1717793824>::ParseText(float*, unsigned int, char const*)
Shadow bytes around the buggy address:
  0x000100403180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x000100403200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x000100403280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x000100403300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x000100403380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x000100403400: 00[04]fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x000100403480: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x000100403500: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x000100403580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x000100403600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x000100403680: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==79070==ABORTING

Clang Static Analyzer Report

Logic error

Assigned value is garbage or undefined 2
Called C++ object pointer is null 3
Dereference of null pointer 13
Garbage return value 1
Result of operation is garbage or undefined 4
Uninitialized argument value 6
Unix API 4

Memory error

Bad deallocator 7
Double free 2
Memory leak 10
Use-after-free 8

Unix API

Allocator sizeof operand mismatch 1

Unused code

Dead assignment 28
Dead increment 3
Dead initialization 20
Dead nested assignment 1

Knowledgebase

https://bugs.chromium.org/p/project-zero/issues/detail?id=2225
https://bugs.chromium.org/p/project-zero/issues/detail?id=2226
https://srd.cx/cve-2022-26730/
https://srd.cx/cve-2023-32443/
Clang Static Analyzer Report https://xss.cx/2023/10/29/src/demomax-clang-static-analysis/
Pull Request #53
icFixXml function [CVE-2023-46602]
CIccPRMG::GetChroma function [CVE-2023-46603]

Debugging Aids

Build

cmake -DCMAKE_INSTALL_PREFIX=$HOME/.local \
      -DCMAKE_BUILD_TYPE=Debug \
      -DCMAKE_CXX_FLAGS="-g -fsanitize=address -fno-omit-frame-pointer -Wall -std=c++17 -fprofile-instr-generate -fcoverage-mapping" \
      ../Build/Cmake
make

Other Overflow Examples

DemoIccMAX-master/Build/Tools/IccFromXml/iccFromXml DemoIccMAX-master/Testing/CMYK-3DLUTs/CMYK-3DLUTs2.xml DemoIccMAX-master/Testing/CMYK-3DLUTs/CMYK-3DLUTs2.icc
DemoIccMAX-master/Build/Tools/IccFromXml/iccFromXml DemoIccMAX-master/Testing/ICS/Rec2100HlgFull-Part1.xml DemoIccMAX-master/Testing/ICS/Rec2100HlgFull-Part1.icc
DemoIccMAX-master/Build/Tools/IccFromXml/iccFromXml DemoIccMAX-master/Testing/ICS/Rec2100HlgFull-Part2.xml DemoIccMAX-master/Testing/ICS/Rec2100HlgFull-Part2.icc
DemoIccMAX-master/Build/Tools/IccFromXml/iccFromXml DemoIccMAX-master/Testing/Overprint/17ChanPart1.xml DemoIccMAX-master/Testing/Overprint/17ChanPart1.icc

IccEval.cpp at Line 139 - 172

    //  * Modified by @h02332 | David Hoyt
    // determine granularity
    if (!nGran) {
      CIccTag* tag = pProfile->FindTag(icSigAToB0Tag + (nIntent == icAbsoluteColorimetric ? icRelativeColorimetric : nIntent));

      if (!tag) {
          std::cerr << "Tag is nullptr!" << std::endl;
          return icCmmStatColorNotFound;
      }
      
      try {
          if (dynamic_cast<CIccTagLut16*>(tag) != nullptr) {
              std::cerr << "Unexpected object type detected!" << std::endl;
              // If there's a method to get more details about the tag, use it. If not, skip this line.
              // std::cerr << "Tag details: " << tag->GetDetails() << std::endl;
              std::cerr << "Actual object type: " << typeid(*tag).name() << std::endl;
          } else {
              std::cerr << "Tag is not of expected type!" << std::endl;
              std::cerr << "Actual object type: " << typeid(*tag).name() << std::endl;
          }
      } catch (const std::bad_typeid& e) {
          std::cerr << "Caught bad_typeid exception: " << e.what() << std::endl;
          return icCmmStatBadLutType;
      }

      CIccTagLutAtoB* pTag = dynamic_cast<CIccTagLutAtoB*>(tag);

      // Check if pTag is valid. If it's not, we set nGran to default value and skip further checks.
      if (!pTag || ndim == 3) {
          nGran = 33;
      } else {
          CIccCLUT* pClut = pTag->GetCLUT();
          nGran = pClut ? (pClut->GridPoints() + 2) : 33;
      }
    }

IccTagLut.cpp at Line 2523 - 2666

/**
 ******************************************************************************
 * Name: CIccCLUT::Interp3d
 * 
 * Purpose: Three dimensional interpolation function
 *
 * Args:
 *  Pixel = Pixel value to be found in the CLUT. Also used to store the result.
 * Modified by @h02332 | David Hoyt
 *******************************************************************************
 */
void CIccCLUT::Interp3d(icFloatNumber *destPixel, const icFloatNumber *srcPixel) const
{
    icUInt8Number mx = m_MaxGridPoint[0];
    icUInt8Number my = m_MaxGridPoint[1];
    icUInt8Number mz = m_MaxGridPoint[2];

    icFloatNumber x = UnitClip(srcPixel[0]) * mx;
    icFloatNumber y = UnitClip(srcPixel[1]) * my;
    icFloatNumber z = UnitClip(srcPixel[2]) * mz;

    icUInt32Number ix = (icUInt32Number)x;
    icUInt32Number iy = (icUInt32Number)y;
    icUInt32Number iz = (icUInt32Number)z;

    icFloatNumber u = x - ix;
    icFloatNumber t = y - iy;
    icFloatNumber s = z - iz;

    if (ix == mx) {
        ix--;
        u = 1.0;
    }
    if (iy == my) {
        iy--;
        t = 1.0;
    }
    if (iz == mz) {
        iz--;
        s = 1.0;
    }

    icFloatNumber ns = (icFloatNumber)(1.0 - s);
    icFloatNumber nt = (icFloatNumber)(1.0 - t);
    icFloatNumber nu = (icFloatNumber)(1.0 - u);

    icUInt32Number maxIndex = (mx + 1) * (my + 1) * (mz + 1) * m_nOutput - 1;

    icFloatNumber dF0 = ns * nt * nu;
    icFloatNumber dF1 = ns * nt * u;
    icFloatNumber dF2 = ns * t * nu;
    icFloatNumber dF3 = ns * t * u;
    icFloatNumber dF4 = s * nt * nu;
    icFloatNumber dF5 = s * nt * u;
    icFloatNumber dF6 = s * t * nu;
    icFloatNumber dF7 = s * t * u;

     icFloatNumber *pStart = &m_pData[ix * n001 + iy * n010 + iz * n100];

     for (int i = 0; i < m_nOutput; i++) {
         icFloatNumber *p = pStart + i;

         // Logging statements before the problematic line:
              std::cout << "Pointer p: " << p << std::endl;
              std::cout << "n000: " << n000 << ", Value: " << p[n000] << std::endl;
              std::cout << "n001: " << n001 << ", Value: " << p[n001] << std::endl;
              std::cout << "n010: " << n010 << ", Value: " << p[n010] << std::endl;
              std::cout << "n011: " << n011 << ", Value: " << p[n011] << std::endl;
              std::cout << "n100: " << n100 << ", Value: " << p[n100] << std::endl;
              std::cout << "n101: " << n101 << ", Value: " << p[n101] << std::endl;
              std::cout << "n110: " << n110 << ", Value: " << p[n110] << std::endl;
              std::cout << "n111: " << n111 << ", Value: " << p[n111] << std::endl;
         
          // ... Similarly for other indices ...
         
         // Log the maximum possible index and the current index
         std::cout << "Max Index: " << maxIndex << ", Current Index: " << (p + n111 - m_pData) << std::endl;

         if (p + n111 > m_pData + maxIndex) {
             std::cerr << "Potential overflow detected. Aborting." << std::endl;
             return;
         }

         // Try to safely access the value at p[n000]
         if (p + n000 > m_pData + maxIndex) {
             std::cerr << "Potential overflow detected. Aborting." << std::endl;
             return;
         } else {
             std::cout << "Value at (p + n000): " << p[n000] << std::endl;
         }

         if ((p + n001) >= (m_pData + maxIndex)) {
             std::cerr << "Out-of-bounds access detected for n001." << std::endl;
         }

         if ((p + n010) >= (m_pData + maxIndex)) {
             std::cerr << "Out-of-bounds access detected for n010." << std::endl;
         }

         if ((p + n011) >= (m_pData + maxIndex)) {
             std::cerr << "Out-of-bounds access detected for n011." << std::endl;
         }
         
         if ((p + n100) >= (m_pData + maxIndex)) {
             std::cerr << "Out-of-bounds access detected for n100." << std::endl;
         }
        
         if ((p + n101) >= (m_pData + maxIndex)) {
             std::cerr << "Out-of-bounds access detected for n101." << std::endl;
         }
         
         if ((p + n110) >= (m_pData + maxIndex)) {
             std::cerr << "Out-of-bounds access detected for n110." << std::endl;
         }
         
         if ((p + n111) >= (m_pData + maxIndex)) {
             std::cerr << "Out-of-bounds access detected for n111." << std::endl;
         }
         // Add logging statements before the problematic line:
          std::cout << "n000: " << n000 << std::endl;
          std::cout << "n001: " << n001 << std::endl;
          std::cout << "n010: " << n010 << std::endl;
          std::cout << "n011: " << n011 << std::endl;
          std::cout << "n100: " << n100 << std::endl;
          std::cout << "n101: " << n101 << std::endl;
          std::cout << "n110: " << n110 << std::endl;
          std::cout << "n111: " << n111 << std::endl;
         std::cout << "ix: " << ix << std::endl;
             std::cout << "iy: " << iy << std::endl;
             std::cout << "iz: " << iz << std::endl;
             std::cout << "n001: " << n001 << std::endl;
             std::cout << "n010: " << n010 << std::endl;
             std::cout << "n100: " << n100 << std::endl;
             std::cout << "pStart address: " << pStart << std::endl;
         
         // Before the problematic line
         std::cout << "Pointer p: " << p << std::endl;
         std::cout << "n000: " << n000 << std::endl;
         std::cout << "Address (p + n000): " << p + n000 << std::endl;

         
         destPixel[i] = p[n000] * dF0 + p[n001] * dF1 + p[n010] * dF2 + p[n011] * dF3 +
                        p[n100] * dF4 + p[n101] * dF5 + p[n110] * dF6 + p[n111] * dF7;
     }
 }

IccUtilXml.cpp at Line 421 - 491

//  * Modified by @h02332 | David Hoyt
class CIccDumpXmlCLUT : public IIccCLUTExec
{
public:
  CIccDumpXmlCLUT(std::string *xml, icConvertType nType, std::string blanks, icUInt16Number nSamples, icUInt8Number nPixelsPerRow)
  {
    m_xml = xml;
    m_nType = nType;
    m_blanks = blanks;
    m_nSamples = nSamples;
    m_nPixelsPerRow = nPixelsPerRow;
    m_nCurPixel = 0;
  }

    virtual void PixelOp(icFloatNumber* pGridAdr, icFloatNumber* pData)
    {
        if (!pData) {
            std::cerr << "Error: pData is nullptr." << std::endl;
            return;  // Early return if pData is null
        }

        int i;
        char buf[128];

        if (!(m_nCurPixel % m_nPixelsPerRow))
            *m_xml += m_blanks;

        switch(m_nType) {
            case icConvert8Bit:
                for (i=0; i<m_nSamples; i++) {
                    if (&pData[i] == nullptr) {  // Check if accessing pData[i] is valid
                        std::cerr << "Error: pData[i] is out of bounds." << std::endl;
                        return;
                    }
                    sprintf(buf, " %3d", (icUInt8Number)(pData[i]*255.0 + 0.5));
                    *m_xml += buf;
                }
                break;
            case icConvert16Bit:
                for (i=0; i<m_nSamples; i++) {
                    sprintf(buf, " %5d", (icUInt16Number)(pData[i]*65535.0 + 0.5));
                    *m_xml += buf;
                }
                break;
            case icConvertFloat:
            default:
                for (i=0; i<m_nSamples; i++) {
                    sprintf(buf, " %13.8f", pData[i]);
                    *m_xml += buf;
                }
                break;
        }
        m_nCurPixel++;
        if (!(m_nCurPixel % m_nPixelsPerRow)) {
            *m_xml += "\n";
        }
    }

    void Finish()
    {
        if (m_nCurPixel % m_nPixelsPerRow) {
            *m_xml += "\n";
        }
    }

    std::string *m_xml;
    icConvertType m_nType;
    std::string m_blanks;
    icUInt16Number m_nSamples;
    icUInt8Number m_nPixelsPerRow;
    icUInt32Number m_nCurPixel;
};

DORKs for IccXmlLib or IccProfLib

intext:"libiccxml" OR intext:"iccproflib" "International Color Consortium" filetype:pdf OR filetype:txt OR filetype:md OR filetype:xml OR filetype:txt OR filetype:cpp
"Libiccxml" OR "iccproflib"
"iccxmllib" OR "iccproflib"

What kind of data that I need to prepare for creating an Icc Profile?

I'm a newcomer in Icc profile.

I saw a lot of examples in IccProfLib and RefIccMax, but I still no any ideas to create an Icc profile.
I have a big problem that what kind of data for creating an Icc Profile.
All examples are compiled success, but I don't know how to use it. because I don't known how to prepare data for input.
for example: create_CLUT_profile command tool

Could you give me some advice?
thanks

Minor alignment issue for B Curve parsing in CIccTagLutAtoB::Read

Though I doubt this comes up in actual ICC profiles, I noticed that when parsing the B curves for the AtoB / BtoA LUT types, the offset realignment is wrong - it realigns based on the offset for the matrix instead of the B curve offset. You can see that the M & A curves are both correct and align to their respective offsets, so it's just the B curve that has this wrong. It's a minor thing that tripped me up when I was checking how the parsing code handles curve alignment.

See the diff below for the proposed fix. It feels a bit silly to do a pull request for a literal one-character change, but I can do that if it would be helpful.

diff --git a/IccProfLib/IccTagLut.cpp b/IccProfLib/IccTagLut.cpp                     
index 28bb070..3289370 100644                                                        
--- a/IccProfLib/IccTagLut.cpp                                                       
+++ b/IccProfLib/IccTagLut.cpp                                                       
@@ -3846,7 +3846,7 @@ bool CIccTagLutAtoB::Read(icUInt32Number size, CIccIO *pIO)    
       if (!pCurves[i]->Read(nEnd - pIO->Tell(), pIO))                               
         return false;                                                               
                                                                                     
-      if (!pIO->Sync32(Offset[1]))                                                  
+      if (!pIO->Sync32(Offset[0]))                                                  
         return false;                                                               
     }                                                                               
   }                                                                                 

Lut16 / Lut8 Handling of PCSXYZ Color Space doesn't set up curves/matrix

The Lut16 & Lut8 types are supposed to have special handling when the input color space is PCSXYZ, which is the only time the matrix coefficients get used. From what I can tell, this special handling exists but never actually loads the matrix coefficients in or loads new curves into the B curves section. Is this correct, in that "in-the-wild" ICC profiles don't ever actually use the matrix coefficients correctly and they should thus be ignored, or should they be loaded in? If they should be ignored, perhaps the code that generates a new matrix and curves can be removed?

I took the Lut8 section of code I'm talking about and annotated it below:

void CIccTagLut8::SetColorSpaces(icColorSpaceSignature csInput, icColorSpaceSignature csOutput)
{
  if (csInput==icSigXYZData) {
    int i;

    if (!m_CurvesM && IsInputMatrix()) { //Transfer ownership of curves
      m_CurvesM = m_CurvesB;
      m_CurvesB = NULL;

      // 👇 Why does this code allocate a new set of curves and do nothing with it?
      LPIccCurve *pCurves = NewCurvesB();
      CIccTagCurve *pCurve; 
      for (i=0; i<m_nInput; i++) {
        pCurves[i] = pCurve = (CIccTagCurve*)CIccTag::Create(icSigCurveType);
        pCurve->SetSize(0); 
      } 

      m_bUseMCurvesAsBCurves = true;
    } 

    if (!m_Matrix) {
      // 👇 Why does this code allocate a new matrix and do nothing with it?
      CIccMatrix *pMatrix = NewMatrix();
      for (i=0; i<9; i++) {
        pMatrix->m_e[i] = icFtoD(m_XYZMatrix[i]);
      }

      pMatrix->m_bUseConstants=false;
    } 
  } 
  else {
    m_XYZMatrix[0] = m_XYZMatrix[4] = m_XYZMatrix[8] = icDtoF(1.0);
    m_XYZMatrix[1] = m_XYZMatrix[2] = m_XYZMatrix[3] = 
    m_XYZMatrix[5] = m_XYZMatrix[6] = m_XYZMatrix[7] = 0;
  } 

  CIccMBB::SetColorSpaces(csInput, csOutput);
}

CMake option to exclude IccXML extension in build (and therefore libxml2 depdendency)

I am considering using IccProfLib to process some ICC profiles in a program. I do not need the (de)serialization of ICC profiles to(from) XML that the IccLibXML extension provides.

Unfortunately to build the project for IccProfLib without modification, we are forced to build IccXML, which means that we must have libxml2 installed as a dependency. This makes it more difficult to build IccProfLib using a cross compiler, because we must first cross-compile libxml2.

It would be nice to have a CMake var, for example, ENABLE_ICCXML that we can set to OFF (default ON to preserve existing behavior).

export path libIccXML2.so.2

for me the correct export path was export LD_LIBRARY_PATH=$HOME/.local/lib64:$LD_LIBRARY_PATH
this is for the debug build flag in the instructions example

version-independent interpretation of bytes 84..99

I noticed that the IccProflib reports an error in v2.x.y profile versions of the ICC profiles if the bytes corresponding to the "Profile ID" of v4.3.0 (bytes 84..99) are not zero and do not correspond to the md5 sum above the ICC header.

However, the spec for v2.x.y states that bytes 84..99 are reserved (see https://www.color.org/ICC_Minor_Revision_for_Web.pdf, page 12).

My question:

Is interpreting bytes 84..99 in v2.x.y profile versions a bug in IccProfLib?
If no, what did I interpret wrong?

IccProfLib public header list

Here comes a list of potential headers to be installed into a system location for API users. Comments are appreciated on what to exclude or what is missed.
SET( HEADERS_PUBLIC
${SRC_PATH}/IccProfLib/IccApplyBPC.h
${SRC_PATH}/IccProfLib/IccArrayBasic.h
${SRC_PATH}/IccProfLib/IccArrayFactory.h
${SRC_PATH}/IccProfLib/IccCAM.h
${SRC_PATH}/IccProfLib/IccCmm.h
${SRC_PATH}/IccProfLib/IccConvertUTF.h
${SRC_PATH}/IccProfLib/IccDefs.h
${SRC_PATH}/IccProfLib/IccEncoding.h
${SRC_PATH}/IccProfLib/IccEnvVar.h
${SRC_PATH}/IccProfLib/IccEval.h
${SRC_PATH}/IccProfLib/IccIO.h
${SRC_PATH}/IccProfLib/IccMatrixMath.h
${SRC_PATH}/IccProfLib/IccMpeACS.h
${SRC_PATH}/IccProfLib/IccMpeBasic.h
${SRC_PATH}/IccProfLib/IccMpeCalc.h
${SRC_PATH}/IccProfLib/IccMpeFactory.h
${SRC_PATH}/IccProfLib/IccMpeSpectral.h
${SRC_PATH}/IccProfLib/IccPcc.h
${SRC_PATH}/IccProfLib/IccPrmg.h
${SRC_PATH}/IccProfLib/IccProfile.h
${SRC_PATH}/IccProfLib/IccProfLibConf.h
${SRC_PATH}/IccProfLib/IccProfLibVer.h
${SRC_PATH}/IccProfLib/IccSolve.h
${SRC_PATH}/IccProfLib/IccSparseMatrix.h
${SRC_PATH}/IccProfLib/IccStructBasic.h
${SRC_PATH}/IccProfLib/IccStructFactory.h
${SRC_PATH}/IccProfLib/IccTagBasic.h
${SRC_PATH}/IccProfLib/IccTagComposite.h
${SRC_PATH}/IccProfLib/IccTagDict.h
${SRC_PATH}/IccProfLib/IccTagFactory.h
${SRC_PATH}/IccProfLib/IccTag.h
${SRC_PATH}/IccProfLib/IccTagLut.h
${SRC_PATH}/IccProfLib/IccTagMPE.h
${SRC_PATH}/IccProfLib/IccTagProfSeqId.h
${SRC_PATH}/IccProfLib/IccUtil.h
${SRC_PATH}/IccProfLib/IccWrapper.h
${SRC_PATH}/IccProfLib/IccXformFactory.h
${SRC_PATH}/IccProfLib/icProfileHeader.h
${SRC_PATH}/IccProfLib/MainPage.h
)

Library names

It might be worthwhile to consider related library names, as the two previous projects moved into a single on.

SampleICC (past): libSampleICC.a
IccXML (past): libIccXML.a
IccProfLib (now): libIccProfLib.a

proposed:
IccProfLib: libRefIccMaxProf.a
IccXML: libRefIccMaxXml.a

other ideas welcome

AddressSanitizer: heap-buffer-overflow on IccTagXml

Tested on OS - Ubuntu 22.04 LTS 5.15.0-72-generic #79-Ubuntu SMP x86_64 x86_64 x86_64 GNU/Linux

A heap based buffer overflow was identified on IccToXml while fuzzing the vulnerability is triggered with a crafted .icc profile file. Attaching the same for reference.

GDB:

(gdb) r sample.icc /dev/null 
Starting program: /DemoIccMAX/Build/Cmake/Tools/IccToXml/iccToXml sample.icc /dev/null
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7f6bc9c in icCurvesToXml (xml="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<IccProfile>\n  <Header>\n    <PreferredCMMType>ADBE</PreferredCMMType>\n    <ProfileVersion>4.20</ProfileVersion>\n    <ProfileDeviceClass>scnr</ProfileDeviceClass>"..., szName=0x7ffff7f99874 "MCurves", pCurves=pCurves@entry=0x61f7a0, numCurve=<optimized out>, numCurve@entry=3, nType=nType@entry=icConvertVariable, blanks=...) at /DemoIccMAX/IccXML/IccLibXML/IccTagXml.cpp:2991
2991	      IIccExtensionTag *pTag = pCurves[i]->GetExtension();
(gdb) 
(gdb) bt
#0  0x00007ffff7f6bc9c in icCurvesToXml (
    xml="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<IccProfile>\n  <Header>\n    <PreferredCMMType>ADBE</PreferredCMMType>\n    <ProfileVersion>4.20</ProfileVersion>\n    <ProfileDeviceClass>scnr</ProfileDeviceClass>"..., szName=0x7ffff7f99874 "MCurves", pCurves=pCurves@entry=0x61f7a0, numCurve=<optimized out>, numCurve@entry=3, 
    nType=nType@entry=icConvertVariable, blanks=...) at /DemoIccMAX/IccXML/IccLibXML/IccTagXml.cpp:2991
#1  0x00007ffff7f6cfc7 in icMBBToXml (
    xml="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<IccProfile>\n  <Header>\n    <PreferredCMMType>ADBE</PreferredCMMType>\n    <ProfileVersion>4.20</ProfileVersion>\n    <ProfileDeviceClass>scnr</ProfileDeviceClass>"..., pMBB=pMBB@entry=0x61f4b0, nType=nType@entry=icConvertVariable, blanks=..., bSaveGridPoints=true)
    at /DemoIccMAX/IccXML/IccLibXML/IccTagXml.cpp:3151
#2  0x00007ffff7f6f86c in CIccTagXmlLutAtoB::ToXml (this=0x61f4b0, 
    xml="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<IccProfile>\n  <Header>\n    <PreferredCMMType>ADBE</PreferredCMMType>\n    <ProfileVersion>4.20</ProfileVersion>\n    <ProfileDeviceClass>scnr</ProfileDeviceClass>"..., blanks=...) at /DemoIccMAX/IccXML/IccLibXML/IccTagXml.cpp:3798
#3  0x00007ffff7f58331 in CIccProfileXml::ToXmlWithBlanks (this=<optimized out>, this@entry=0x7fffffffe1e8, xml=..., blanks=...)
    at /DemoIccMAX/IccXML/IccLibXML/IccProfileXml.cpp:264
#4  0x00007ffff7f557ec in CIccProfileXml::ToXml (this=0x7fffffffe1e8, 
    xml="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<IccProfile>\n  <Header>\n    <PreferredCMMType>ADBE</PreferredCMMType>\n    <ProfileVersion>4.20</ProfileVersion>\n    <ProfileDeviceClass>scnr</ProfileDeviceClass>"...) at /DemoIccMAX/IccXML/IccLibXML/IccProfileXml.cpp:79
#5  0x0000000000403696 in main (argc=<optimized out>, argv=0x7fffffffe3b8) at /DemoIccMAX/IccXML/CmdLine/IccToXml/IccToXml.cpp:38
(gdb) i r
rax            0x61f7a0            6420384
rbx            0x1                 1
rcx            0x1                 1
rdx            0x624               1572
rsi            0x60c010            6340624
rdi            0x0                 0
rbp            0x1                 0x1
rsp            0x7fffffffd3f0      0x7fffffffd3f0
r8             0x624580            6440320
r9             0x0                 0
r10            0x7fffffffc9b0      140737488341424
r11            0xb6ff62935fcf2779  -5260377454638323847
r12            0x7fffffffd488      140737488344200
r13            0x61f7e0            6420448
r14            0x6                 6
r15            0x7fffffffd478      140737488344184
rip            0x7ffff7f6bc9c      0x7ffff7f6bc9c <icCurvesToXml(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char const*, CIccCurve**, int, icConvertType, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)+588>
eflags         0x10202             [ IF RF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0
(gdb) 
rax            0x61f7a0            6420384
rbx            0x1                 1
rcx            0x1                 1
rdx            0x624               1572
rsi            0x60c010            6340624
rdi            0x0                 0
rbp            0x1                 0x1
rsp            0x7fffffffd3f0      0x7fffffffd3f0
r8             0x624580            6440320
r9             0x0                 0
r10            0x7fffffffc9b0      140737488341424
r11            0xb6ff62935fcf2779  -5260377454638323847
r12            0x7fffffffd488      140737488344200
r13            0x61f7e0            6420448
r14            0x6                 6
r15            0x7fffffffd478      140737488344184
rip            0x7ffff7f6bc9c      0x7ffff7f6bc9c <icCurvesToXml(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char const*, CIccCurve**, int, icConvertType, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)+588>
eflags         0x10202             [ IF RF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0
(gdb)

ASAN:

==115400==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000118 at pc 0x7ffff7f03d71 bp 0x7fffffffb7d0 sp 0x7fffffffb7c8
READ of size 8 at 0x602000000118 thread T0
    #0 0x7ffff7f03d70 in icCurvesToXml(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char const*, CIccCurve**, int, icConvertType, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) DemoIccMAX/IccXML/IccLibXML/IccTagXml.cpp:2991:32
    #1 0x7ffff7f07440 in icMBBToXml(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, CIccMBB*, icConvertType, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool) DemoIccMAX/IccXML/IccLibXML/IccTagXml.cpp:3151:12
    #2 0x7ffff7f10e17 in CIccTagXmlLutAtoB::ToXml(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) DemoIccMAX/IccXML/IccLibXML/IccTagXml.cpp:3798:13
    #3 0x7ffff7ebff07 in CIccProfileXml::ToXmlWithBlanks(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) DemoIccMAX/IccXML/IccLibXML/IccProfileXml.cpp:264:27
    #4 0x7ffff7eb930e in CIccProfileXml::ToXml(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&) DemoIccMAX/IccXML/IccLibXML/IccProfileXml.cpp:79:10
    #5 0x4d3da5 in main DemoIccMAX/IccXML/CmdLine/IccToXml/IccToXml.cpp:38:16
    #6 0x7ffff7319d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #7 0x7ffff7319e3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #8 0x4224d4 in _start (DemoIccMAX/Build/Cmake/Tools/IccToXml/iccToXml+0x4224d4)

0x602000000118 is located 0 bytes to the right of 8-byte region [0x602000000110,0x602000000118)
allocated by thread T0 here:
    #0 0x4d128d in operator new[](unsigned long) (DemoIccMAX/Build/Cmake/Tools/IccToXml/iccToXml+0x4d128d)
    #1 0x7ffff7d260b8 in CIccMBB::NewCurvesM() DemoIccMAX/IccProfLib/IccTagLut.cpp:3595:15
    #2 0x7ffff7d260b8 in CIccTagLutAtoB::Read(unsigned int, CIccIO*) DemoIccMAX/IccProfLib/IccTagLut.cpp:3877:27
    #3 0x7ffff7c240e3 in CIccProfile::LoadTag(IccTagEntry*, CIccIO*, bool) DemoIccMAX/IccProfLib/IccProfile.cpp:1188:14
    #4 0x7ffff7c275d0 in CIccProfile::Read(CIccIO*, bool) DemoIccMAX/IccProfLib/IccProfile.cpp:748:10

SUMMARY: AddressSanitizer: heap-buffer-overflow DemoIccMAX/IccXML/IccLibXML/IccTagXml.cpp:2991:32 in icCurvesToXml(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char const*, CIccCurve**, int, icConvertType, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)
Shadow bytes around the buggy address:
  0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff8000: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
  0x0c047fff8010: fa fa fd fa fa fa fd fa fa fa 00 04 fa fa 00 fa
=>0x0c047fff8020: fa fa 00[fa]fa fa fd fa fa fa fa fa fa fa fa fa
  0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==115400==ABORTING

sample.icc.zip

Doesn't build on macOS

iccProfLib uses C++11 features (e.g. {} syntax for object initialisation), but the projects use the Xcode default for C++ dialect, which is C++98.

iccProfLib also contains invalid code, that casts enums to integers and tries to use values outside their valid range (e.g. in GetMeasurementFlareName) which is undefined behaviour. Clang errors on this by default, which can technically be silenced with -Wno-enum-constexpr-conversion although that's not a real solution (Clang doesn't guarantee the runtime behaviour will be as the code expects) and a performance pessimisation.

Beyond that, the iccProfLib builds as x86-64 only but all the subprojects (e.g. IccApplyNamedCmm) use the default value for the target architectures (which is currently x86_64 and arm64). So they all fail to link due to the missing arm64 slice.

RefIccMAXCmm also fails to build because it's using ColorSync types (e.g. CMError) which seemingly don't exist anymore (they were deprecated more than a decade ago, so I assume they've finally be outright removed from the framework).

The macOS deployment target is also being set to (or defaulting to?) 10.11, but modern Xcode doesn't support earlier than 10.13. This nominally just results in a warning, although it's possible it's screwing other things up too (hard to tell with so many other errors occurring in parallel).

IccLibXML.xcodeproj is missing targets for the actual command line tools - IccToXML et al.

Custom Names Color Space or Profile

Hi, I am trying to figure out how to programatically create a "Spot Color" for use when generating a PDF programatically. I am hoping someone here may have some knowledge on whether it is possible to do that by creating a custom color space.

Unfortunately I know very little about creating a custom color space.

The application is developed in Swift on macOS and generates print ready PDF files. Some printing required the use of SPOT colors - so solid colors that cannot be printed using normal CMYK printing.

The printers need the PDF to have these elements printed using a custom named color space so their print systems will automatically pick up the components to be printed with the spot color.

I am hoping that perhaps I can use the DemoIccMAX libraries to create a custom profile of some sort that can be installed on macOS and subsequently used programatically.

So the related questions I have are:

  1. Is it possible to define a custom profile with a single color in XML and then use the DemoIccMAX libraries to generate a icc profile that can be installed on macOS. This single color can be green - the print shop doesn't use the actual color, they just use the specific name to identify the objects to be printed. They have a separate process to load the actual ink color. Typically this is required when printing white on black substrate - they need to use a solid white ink since you can't do white in CMYK.

  2. Is it possible to use these libraries to generate such a profile on the fly such that it can be used programatically by the macOS APIs such as

CGColorSpace.init(iccData:)
Creates an ICC-based color space using the ICC profile contained in the specified data.

Any assistance will be much appreciated.

Build Instructions, Cherry Picking Example | Compile Errors in PR 69

Compile Errors from PR #69
Commit b90ac3933da99179df26351c39d8d9d706ac1cc6

Passing Compile in PR #66
Commit f891074a0f1c9d61a3dfa53749265f8c14ed4ee6

PR 66 Reproduction

cd /tmp
wget https://github.com/InternationalColorConsortium/DemoIccMAX/archive/f891074a0f1c9d61a3dfa53749265f8c14ed4ee6.zip
unzip f891074a0f1c9d61a3dfa53749265f8c14ed4ee6.zip
cd DemoIccMAX-f891074a0f1c9d61a3dfa53749265f8c14ed4ee6/Build
cmake -DCMAKE_INSTALL_PREFIX=$HOME/.local -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-g -fsanitize=address,undefined -fno-omit-frame-pointer -Wall" -Wno-dev  Cmake
make -j$(nproc) 2>&1 | grep 'error:'

Result: Passing

PR 69 Reproduction

cd /tmp
wget https://github.com/InternationalColorConsortium/DemoIccMAX/archive/b90ac3933da99179df26351c39d8d9d706ac1cc6.zip
unzip b90ac3933da99179df26351c39d8d9d706ac1cc6.zip
cd DemoIccMAX-b90ac3933da99179df26351c39d8d9d706ac1cc6/Build
cmake -DCMAKE_INSTALL_PREFIX=$HOME/.local -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-g -fsanitize=address,undefined -fno-omit-frame-pointer -Wall" -Wno-dev  Cmake
make -j$(nproc) 2>&1 | grep 'error:'
...
DemoIccMAX-b90ac3933da99179df26351c39d8d9d706ac1cc6/Build/Cmake/../../IccProfLib/IccCmm.h:1246:23: error: unknown type name 'CIccXformNDLut'
DemoIccMAX-b90ac3933da99179df26351c39d8d9d706ac1cc6/Build/Cmake/../../IccProfLib/IccCmm.h:1246:23: error: unknown type name 'CIccXformNDLut'
DemoIccMAX-b90ac3933da99179df26351c39d8d9d706ac1cc6/Build/Cmake/../../IccProfLib/IccCmm.h:1246:23: error: unknown type name 'CIccXformNDLut'
DemoIccMAX-b90ac3933da99179df26351c39d8d9d706ac1cc6/Build/Cmake/../../IccProfLib/IccCmm.h:1246:23: error: unknown type name 'CIccXformNDLut'
DemoIccMAX-b90ac3933da99179df26351c39d8d9d706ac1cc6/IccProfLib/IccCmm.cpp:1923:22: error: out-of-line definition of 'CIccApplyNDLutXform' does not match any declaration in 'CIccApplyNDLutXform'
DemoIccMAX-b90ac3933da99179df26351c39d8d9d706ac1cc6/IccProfLib/IccCmm.cpp:1923:22: error: out-of-line definition of 'CIccApplyNDLutXform' does not match any declaration in 'CIccApplyNDLutXform'
DemoIccMAX-b90ac3933da99179df26351c39d8d9d706ac1cc6/IccProfLib/IccCmm.cpp:6306:33: error: no matching constructor for initialization of 'CIccApplyNDLutXform'
DemoIccMAX-b90ac3933da99179df26351c39d8d9d706ac1cc6/IccProfLib/IccCmm.cpp:6306:33: error: no matching constructor for initialization of 'CIccApplyNDLutXform'
DemoIccMAX-b90ac3933da99179df26351c39d8d9d706ac1cc6/Build/Cmake/../../IccProfLib/IccCmm.h:1246:23: error: unknown type name 'CIccXformNDLut'

Result: Not Passing

Inconsistent validation results (missing validation checks)

Hi,
we included IccProfLib into one of our image validation tools. The tool calls CIccProfile::ReadValidate on embedded profiles.

We noticed that profiles validated with the IccDumpProfile CI Tool to be non-compliant, are still valid and compliant when tested with this IccProfLib call.
One real-world example we encountered: First tag data that is on an offset rather than immediately after tag table (as expected by the ICC standard).

It seems IccDumpProfile implements more non-compliant checks and warnings.
--> https://github.com/InternationalColorConsortium/DemoIccMAX/blob/master/Tools/CmdLine/IccDumpProfile/iccDumpProfile.cpp#L241-L304

Would it be possible to include those into IccProfLib as well to get consistent validation results and reports across all tools and libs in this project?

make error IccCmm.h:1246:37: error: expected ‘)’ before ‘*’ token

System:

Ubuntu 22,04.4, AMD_64

Commands:

gh repo clone InternationalColorConsortium/DemoIccMAX
cd ~/DemoIccMAX
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$HOME/.local ../Build/Cmake
make help
make

Output from make:

[  0%] Building CXX object IccProfLib/CMakeFiles/IccProfLib2.dir/home/ott/DemoIccMAX/IccProfLib/IccApplyBPC.cpp.o
In file included from /home/ott/DemoIccMAX/IccProfLib/IccApplyBPC.h:74,
                 from /home/ott/DemoIccMAX/IccProfLib/IccApplyBPC.cpp:71:
/home/ott/DemoIccMAX/IccProfLib/IccCmm.h:1246:37: error: expected ‘)’ before ‘*’ token
 1246 |   CIccApplyNDLutXform(CIccXformNDLut* pXform, CIccApplyCLUT* pApply);
      |                      ~              ^
      |                                     )
make[2]: *** [IccProfLib/CMakeFiles/IccProfLib2.dir/build.make:76: IccProfLib/CMakeFiles/IccProfLib2.dir/home/ott/DemoIccMAX/IccProfLib/IccApplyBPC.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:381: IccProfLib/CMakeFiles/IccProfLib2.dir/all] Error 2
make: *** [Makefile:136: all] Error 2

Excessive memory consumption and bad performance for Google SKIA profiles/fuzz/curv_size_overflow.icc

When running "iccDumpProfile" CLI utility on PC or Linux with the Google SKIA file "profiles/fuzz/curv_size_overflow.icc" and either or both -v or all options, RefIccMax consumes excessive memory (multiple GBs) and is exceptionally slow as a result. wxDumpProfile on PC is much faster and does not seem to suffer this (but I did not check the code). Without -v or all options "iccDumpProfile" runs very quickly like wxDumpProfile.

As the ICC profile filename suggests, the root cause is that the RGB TRC 'curv' have counts (n) of 2,147,484,348 which then attempts to allocate gigantic buffers * sizeof(float)! This is because the ICC file has been fuzzed and the corresponding bytes for count in the file are all 0xFF... (so, yes, it is malformed).

Problematic code is in IccProfLib/IccTagLut.cpp, function bool CIccTagCurve::SetSize(...) from line 442 (https://github.com/InternationalColorConsortium/RefIccMAX/blob/8da81e9151581161a582dbc4ca0ed8220aba02a9/IccProfLib/IccTagLut.cpp#L442). Would suggest that santity checks on the magnitude of count (n) prior to doing malloc/icRealloc are required. There may even be a maximum possible value for count given that the data for 'curv' are all uInt16Numbers according to ICC.1 v4.3.0 and the curves may have some precision requirements but all that color theory is beyond me...

Also suggest checking that all other malloc/icRealloc calls in the codebase are also range-checked prior to calls.

To get the Google SKIA ICC corpus and skcms/profiles/fuzz/curv_size_overflow.icc:

git clone https://skia.googlesource.com/skcms    ## quite small repo (~180MB), with corpus in 'profiles' folder and below
cd skcms/profiles/fuzz

Markup issues in some Testing examples

In RefIccMax-2.0.16:
A couple of minor issues with the mark-up in the xml examples in the Testing folder:
In several 'camera' examples including CameraModel.xml:
... is closed with instead of
is closed with

When these are corrected, there is a stack underflow at line 72: [mul] 33

CIccTagSpectralViewingConditions + CIccProfile mismatch in allocation and deallocation methods

PR for CIccTagSpectralViewingConditions + CIccProfile

PR will be based on Commit: f891074

Memory Management Issues

Description: The code in CIccTagSpectralViewingConditions and CIccProfile exhibits improper memory management practices.
There is a mismatch in allocation and deallocation methods for dynamically allocated memory.
This leads to the detection of alloc-dealloc-mismatch errors by AddressSanitizer.

Issue 1

File: IccTagBasic.cpp
Line: 10908
Incorrect use of delete[] for memory allocated using malloc.
CIccProfile Cleanup Function:

Code Segment Analysis

The provided code segment shows the allocation of m_observer using malloc:

if (pChild->children && pChild->children->content) {
    CIccFloatArray vals;
    vals.ParseTextArray((icChar*)pChild->children->content);
    if (vals.GetSize() != m_observerRange.steps * 3)
        return false;
    m_observer = (icFloatNumber*)malloc(m_observerRange.steps * 3 * sizeof(icFloatNumber));
    if (!m_observer)
        return false;
    icFloatNumber *pBuf = vals.GetBuf();
    memcpy(m_observer, pBuf, m_observerRange.steps * 3 * sizeof(icFloatNumber));
}

Corrected Destructor

Given that m_observer is allocated using malloc, it should be deallocated using free in the destructor.

Here is the corrected destructor code:

Refactored Code

/**
 ****************************************************************************
 * Name: CIccTagSpectralViewingConditions::~CIccTagSpectralViewingConditions
 * 
 * Purpose: Destructor
 * 
 *****************************************************************************
 */
CIccTagSpectralViewingConditions::~CIccTagSpectralViewingConditions()
{
  if (m_observer)
    free(m_observer);  // Correct deallocation for malloc

  if (m_illuminant)
    free(m_illuminant);  // Correct deallocation for malloc
}

Additional Considerations
Ensure All Allocations Match: Verify that m_illuminant is also allocated using malloc. If not, adjust the deallocation method accordingly.

Memory Management Consistency: Ensure that all memory allocations and deallocations within the class are consistent to prevent similar issues.

Error Handling: Consider adding error handling to ensure that the destructor handles null pointers gracefully, although free and delete[] are safe to call with null pointers.

Issue 2

File: IccProfile.cpp
Line: 263
Improper handling of dynamically allocated memory using manual delete and free operations.

Refactored Code

/**
 ****************************************************************************
 * Name: CIccProfile::Cleanup
 * 
 * Purpose: Detach from a pending IO object
 *****************************************************************************
 */
void CIccProfile::Cleanup()
{
  // Delete the attached IO object if it exists
  if (m_pAttachIO) {
    delete m_pAttachIO;
    m_pAttachIO = nullptr;
  }

  // Iterate through the tag values and delete them if they are not null
  for (auto &tagVal : *m_TagVals) {
    if (tagVal.ptr != nullptr) {
      delete tagVal.ptr;
      tagVal.ptr = nullptr;
    }
  }

  // Clear the tag lists
  m_Tags->clear();
  m_TagVals->clear();

  // Reset the header to zero
  std::memset(&m_Header, 0, sizeof(m_Header));
}

Explanation of Changes

Nullptr Assignment: Replaced NULL with nullptr for better type safety and clarity. After deleting pointers, set them to nullptr to avoid dangling pointers.

Range-based Loop: Replaced the manual iterator loop with a range-based loop for better readability and to reduce the potential for errors.

Clear Lists: Clear the tag lists using the clear method of the standard library containers.

Memset: Used std::memset instead of memset to adhere to C++ standards.

Memory Allocation Consistency: Ensure that the memory for m_pAttachIO and tagVal.ptr is consistently allocated with new if they are deleted with delete.

Common Weakness Enumeration (CWE)

CWE-762: Mismatched Memory Management Routines
CWE-401: Improper Release of Memory Before Removing Last Reference ('Memory Leak')

Exploit Value

Crashes occurring in destructors due to zero-page dereferences are typically considered benign and are often just null pointer dereferences without significant security implications. However, crashes occurring in constructors are more concerning as they may indicate a product defect or a security vulnerability.

Exploitable if:

Crash on write instruction
Crash executing invalid address
Crash calling an invalid address
Illegal instruction exception
Abort due to -fstack-protector, _FORTIFY_SOURCE, heap corruption detected
Stack trace of crashing thread contains certain functions such as malloc, free, szone_error, objc_MsgSend, etc.

Not exploitable if:

Divide by zero exception
Stack grows too large due to recursion
Null dereference (read or write)
Other abort
Crash on read instruction

Caveat

A reference implementation is not production code. In general, any Code being used in production should undergo additional security reviews and product testing.

A/B input/output confusion.

While attempting to use iccToXml and iccFromXml to create a profile for "A CMYK (four channel)" to "B Lab (three channel)" the tool segfaulted. The issue is a confusion about properly keeping track of which of A and B are the input and the output. The "AtoB" and "BtoA" types do this fairly well, but the "Lut8" and "Lut16" types currently appear to always assume B is the input. This kinda works in a somewhat confusing way, but only when A and B have the same number of channels.

By creating a hack like bungeman@a963b3b (originally against sample-icc and iccxml-code because that's what I found first) I am able to create and round trip a simple CMYK profile like cmyk2x2.zip (zipped since I cannot attach a bare icc file here). Since this change isn't very clean at the moment I've decided to open this as an issue instead of as a pull request. Note that the messy part of this change is around informing the Lut classes of their direction, the changes to the classes to output correctly when they have the proper direction set seems to be correct.

problem with compiling

since two days I am trying to compile the project with no success unfortunately.
I have followed whatever instructions were mentioned on the home page of the project for Windows OS (e.g. setting up all the necessary system variables LIBXML2, LIBTIFF...etc.) and yet it doesn't work!

I needed however actually to include the libraries explicitly in all the projects in visual studio solution and still it doesn't work.

Clearer instructions would be appreciated on how to make it runs.

Color management result by CMM may be "-nan(ind)"

I noticed that when I apply the profile below to CMM, "-nan(ind)" may be returned.

InputProfile : ICCProfile_sRGB_v5.xml.icc
OutputProfile : ICCProfile_AdobeRGB_v5.xml.icc

For example, if you input a RGB device value = ( 0, 0, 64) (normalized RGB value = ( 0, 0, 0.2510),
the output will be a normalized RGB value = ( -nan(ind), -nan(ind), 0.2462).

This is because x is slightly negative in the calculation of pow (float x, float y) in the following part, probably because of a calculation error, and it is out of the definition range.

default:
return (icFloatNumber)(pow(m_params[1] * v + m_params[2], m_params[0]) + m_params[3]);

Before calculating the pow, I think it might be a good idea to include a process such as rounding the range of x to 0-1.
Alternatively, improvements may be needed elsewhere.

I attached the sample code and profiles.
TestSample.zip

Thank you for your contribution.

problem with compiling and linking using macOS

I can't get the CMake or XCode builds to work properly on MacOS and produce scripts that are portable to other Macs. Any advice on this would be much appreciated.

My system is:

  • MacOS Catalina (10.15.6)
  • XCode 12.2

CMake

The closest build command I've figured out is:

brew install libtiff
mkdir dist/ && cd dist/ && cmake -DENABLE_STATIC_LIBS=ON -DENABLE_SHARED_LIBS=OFF ../Build/Cmake && make && make install

This produces a valid build for my machine, but the scripts have a link to libtiff - as installed by homebrew, libtiff doesn't come installed on MacOS by default. So this script is does not work on other people's machines.

$ otool -L Tools/IccApplyProfiles/iccApplyProfiles
	/usr/local/opt/libtiff/lib/libtiff.5.dylib (compatibility version 11.0.0, current version 11.0.0)
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon (compatibility version 2.0.0, current version 164.0.0)
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
	/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 904.4.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.0.0)

Is there a way to build iccApplyProfiles on MacOS so that it can be used on other Macs? I think this might be called "relocatable packages" and involve including libtiff within the builds somehow - but I'm not sure. I haven't been able to figure it out.

XCode

I also tried building using XCode, but it did not work.

after copying the required files, as per the README:

$ cd Build/XCode && ./BuildAll.sh   
Command line invocation:
    /Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -target IccProfLib-macOS -configuration Release

note: Using new build system
note: Planning build
note: Using build description from disk

** BUILD SUCCEEDED **

cp: Build/Release/usr is a directory (not copied).
Command line invocation:
    /Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -target IccLibXML-macOS -configuration Release

note: Using new build system
note: Planning build
note: Using build description from disk

** BUILD SUCCEEDED **

cp: build/Release/usr is a directory (not copied).
Command line invocation:
    /Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -target IccApplyNamedCMM -configuration Release

note: Using new build system
note: Planning build
note: Using build description from disk
error: The linked library 'libIccProfLib.a' is missing one or more architectures required by this target: arm64. (in target 'IccApplyNamedCMM' from project 'IccApplyNamedCMM')

** BUILD FAILED **

cp: build/Release/IccApplyNamedCmm: No such file or directory
...

Supporting internal 8bit encoding for XYZ color space

In IccCmm.cpp, inside the methods CIccCmm::ToInternalEncoding (line 8045) and CIccCmm::FromInternalEncoding (line 8354), an encoding of 8 bits while using the XYZ color space is currently not implemented, I was wondering whether this encoding is possible with the XYZ space or not?
Thanks

XCode project contains fixed paths

Running BuildAll.sh on OS X fails because project contains fixed paths

ex.
clang: error: no such file or directory: '/Development/ICC/ICCMax/RefIccMAX-2.0.17/IccXML/IccLibXML/IccMpeXml.cpp'

CLI tools do not report underlying IccProfLib version

It would be extremely handy if all the CLI tools reported the version of the underlying IccProfLib as otherwise there is no known way to identify versioning information across multiple instances or from log files. Compile dates are obviously unreliable.

wxProfileDump already has the equivalent in the Help | About dialog.

The simplistic way is adding 2 lines of code to each CLI main program:

#include "IccProfLibVer.h"
...
printf("Built with IccProfLib version " ICCPROFLIBVER "\n");

Or you may prefer to implement as a method.
If you let me know your preference I am happy to make said changes... or you can do.

gamutBoundaryDescType encoding in IccFromXml

When a gamutBoundaryDescType tag is created in XML, only values from the first two vertices seem to be encoded in the profile by IccFromXml. After the first device value for the second vertex, the remainder of the data are encoded as zeros.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.