Describe the bug
Hi team~ Thanks for your work in exiv2, I think here's a small bug in types.cpp when handling large numbers in .xmp files.
Root cause
If there's a number Xmp.exif.Flash/exif:Mode =18446744073709551616 in a malicious .xmp file, code in types.cpp will handle it like this at line 580
auto f = stringTo<float>(s, ok);
if (ok)
return static_cast<int64_t>(f); // crash here
f becomes approximately 1.84467e+19 and it is directly casted to int64_t.
Since this value exceeds INT64_MAX (9,223,372,036,854,775,807), the conversion overflows the representable range and triggers undefined behavior.
To Reproduce
Steps to reproduce the behavior:
PoC
poc.xmp
<?xml version="1.0" encoding="UTF-8"?>
<?xpacket begin="" id="AAAAAAAAA"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:exif="http://ns.adobe.com/exif/1.0/"
xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#"
xmlns:aux="&"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:xmp="http://ns.adobe.com/xap/1.0/"
xmlns:stVer="http://ns.adobe.com/xap/1.0/sType/Version#"
xmp:CreateDate="2024-01-01T00:00:00ZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
xmp:MetadataDate="0000-00-00T00:00:00"
exif:SceneCaptureType="1073741823"
exif:StandardOutputSensitivity="2147483648"
exif:FocalPlaneXResolution="99999999999999/1"
exif:GPSLongitudeRef="/dev/urandom"
aux:OwnerName="0o7777777777777777777777">
<xmp:ModifyDate>--01-01</xmp:ModifyDate>
<xmp:Label>XniMYrq/YO8fVX4q6WocH1BeiJu+DvT9DshmaiqBOmadabcwEmndzELuekgPQslq</xmp:Label>
<xmp:Nickname>9223372036854775807LL</xmp:Nickname>
<xmp:Identifier>16777215</xmp:Identifier>
<exif:PixelXDimension>127</exif:PixelXDimension>
<exif:PixelYDimension>255</exif:PixelYDimension>
<exif:ExifVersion>0xFF</exif:ExifVersion>
<exif:ComponentsConfiguration>+0x8000000000000000</exif:ComponentsConfiguration>
<exif:MeteringMode>128</exif:MeteringMode>
<exif:SensingMethod>9223372036854775807</exif:SensingMethod>
<exif:WhiteBalance>255</exif:WhiteBalance>
<exif:ImageUniqueID>-99999999999999999999999999999999999999999999999999</exif:ImageUniqueID>
<exif:ISOSpeedLatitudezzz>16777215</exif:ISOSpeedLatitudezzz>
<exif:ShutterSpeedValue>99999999999999/1</exif:ShutterSpeedValue>
<exif:FocalLength>1/0 2/0 3/0</exif:FocalLength>
<exif:FlashEnergy>-1/0</exif:FlashEnergy>
<exif:DigitalZoomRatio>1/0 2/0 3/0</exif:DigitalZoomRatio>
<exif:GPSLatitude></exif:GPSLatitude>
<exif:GPSAltitude>0/0,0/0,0/0</exif:GPSAltitude>
<exif:GPSSpeed>999,999,999N</exif:GPSSpeed>
<exif:GPSDestDistanceRef>ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ</exif:GPSDestDistanceRef>
<exif:GPSDateStamp>2147483648</exif:GPSDateStamp>
<exif:Flash>
<rdf:Description>
<exif:Fired>1</exif:Fired>
<exif:Return>128</exif:Return>
<exif:Mode>18446744073709551616</exif:Mode>
<exif:Function>no</exif:Function>
<exif:RedEyeMode>True</exif:RedEyeMode>
</rdf:Description>
</exif:Flash>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="r"?>
We can trigger the crash with the command
z5500277@katana2:.../bin/crashes_xmp $ UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1:abort_on_error=1 ../exiv2 -pa poc.xmp
and we can see
z5500277@katana2:.../bin/crashes_xmp $ UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1:abort_on_error=1 ../exiv2 -pa poc.xmp
Warning: Failed to convert Xmp.xmp.ModifyDate to Exif.Image.DateTime (Invalid year in date string)
Warning: Failed to convert Xmp.xmp.CreateDate to Exif.Photo.DateTimeDigitized (Invalid date string, extra chars at end)
/srv/scratch/z5500277/target/exiv2/src/types.cpp:582:33: runtime error: 1.84467e+19 is outside the range of representable values of type 'long'
#0 0x7f6030e72e0d in Exiv2::parseInt64(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, bool&) /srv/scratch/z5500277/target/exiv2/src/types.cpp:582:33
#1 0x7f6030d100ca in Exiv2::Converter::cnvXmpFlash(char const*, char const*) /srv/scratch/z5500277/target/exiv2/src/convert.cpp:1063:22
#2 0x7f6030d1b731 in void std::__invoke_impl<void, void (Exiv2::Converter::* const&)(char const*, char const*), Exiv2::Converter&, char const* const&, char const* const&>(std::__invoke_memfun_ref, void (Exiv2::Converter::* const&)(char const*, char const*), Exiv2::Converter&, char const* const&, char const* const&) /apps/z_install_tree/linux-rocky8-ivybridge/gcc-8.5.0/gcc-12.2.0-64v2gp5krz26bgfwfu32vmbm4ih2vodr/lib/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/invoke.h:67:14
#3 0x7f6030d1b731 in std::__invoke_result<void (Exiv2::Converter::* const&)(char const*, char const*), Exiv2::Converter&, char const* const&, char const* const&>::type std::__invoke<void (Exiv2::Converter::* const&)(char const*, char const*), Exiv2::Converter&, char const* const&, char const* const&>(void (Exiv2::Converter::* const&)(char const*, char const*), Exiv2::Converter&, char const* const&, char const* const&) /apps/z_install_tree/linux-rocky8-ivybridge/gcc-8.5.0/gcc-12.2.0-64v2gp5krz26bgfwfu32vmbm4ih2vodr/lib/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/invoke.h:96:14
#4 0x7f6030d1b731 in std::invoke_result<void (Exiv2::Converter::* const&)(char const*, char const*), Exiv2::Converter&, char const* const&, char const* const&>::type std::invoke<void (Exiv2::Converter::* const&)(char const*, char const*), Exiv2::Converter&, char const* const&, char const* const&>(void (Exiv2::Converter::* const&)(char const*, char const*), Exiv2::Converter&, char const* const&, char const* const&) /apps/z_install_tree/linux-rocky8-ivybridge/gcc-8.5.0/gcc-12.2.0-64v2gp5krz26bgfwfu32vmbm4ih2vodr/lib/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/functional:110:14
#5 0x7f6030d1b731 in Exiv2::Converter::cnvFromXmp() /srv/scratch/z5500277/target/exiv2/src/convert.cpp:513:7
#6 0x7f6030d2199f in Exiv2::copyXmpToExif(Exiv2::XmpData const&, Exiv2::ExifData&) /srv/scratch/z5500277/target/exiv2/src/convert.cpp:1332:13
#7 0x7f6030f0b0ea in Exiv2::XmpSidecar::readMetadata() /srv/scratch/z5500277/target/exiv2/src/xmpsidecar.cpp:85:3
#8 0x55f70747c65f in Action::Print::printList() /srv/scratch/z5500277/target/exiv2/app/actions.cpp:352:10
#9 0x55f707476be2 in Action::Print::run(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&) /srv/scratch/z5500277/target/exiv2/app/actions.cpp
#10 0x55f7074093e5 in main /srv/scratch/z5500277/target/exiv2/app/exiv2.cpp:182:25
#11 0x7f602f14c864 in __libc_start_main (/lib64/libc.so.6+0x3a864) (BuildId: 1faac7cdefc71ce73027e33a84650684eecd1635)
#12 0x55f70733307d in _start (/srv/scratch/z5500277/target/exiv2/build-asan/bin/exiv2+0xa407d)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /srv/scratch/z5500277/target/exiv2/src/types.cpp:582:33 in
Aborted
Expected behavior
I think we an add a small check at line 581 to fix it.
Desktop (please complete the following information):
- OS and version: Linux
- Exiv2 version and source: master
- Compiler and version: Gcc 12.2
- Compilation mode and/or compiler flags: "-O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer" -DCMAKE_SHARED_LINKER_FLAGS="-fsanitize=address,undefined" -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined "
Describe the bug
Hi team~ Thanks for your work in exiv2, I think here's a small bug in
types.cppwhen handling large numbers in.xmpfiles.Root cause
If there's a number
Xmp.exif.Flash/exif:Mode =18446744073709551616in a malicious.xmpfile, code intypes.cppwill handle it like this at line 580fbecomes approximately1.84467e+19and it is directly casted toint64_t.Since this value exceeds INT64_MAX (9,223,372,036,854,775,807), the conversion overflows the representable range and triggers undefined behavior.
To Reproduce
Steps to reproduce the behavior:
PoC
poc.xmp
We can trigger the crash with the command
z5500277@katana2:.../bin/crashes_xmp $ UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1:abort_on_error=1 ../exiv2 -pa poc.xmpand we can see
Expected behavior
I think we an add a small check at line
581to fix it.Desktop (please complete the following information):