Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add previewBuffer type as a workaround for Sony preview images #2008

Closed
wants to merge 1 commit into from

Conversation

kevinbackhouse
Copy link
Collaborator

Fixes: #2001

This definitely needs review from somebody who knows Exiv2's architecture better than I do.

This is attempting to fix the problem caused by Sony preview images, which are stored in the main body of the image file, but referenced in the metadata. Previously, we were allocating a buffer of the correct size, but filling it with zeros because we don't have access to the result of the image file while we're parsing the metadata. A malicious file could use that to trigger an out-of-memory crash (see #1881). I have fixed it here by adding a new type called previewBuffer, which is a placeholder that stores the size without actually allocating the memory.

I'm not sure if it's ok to add a fake type in types.hpp like I have done here. If it is ok, then I think this should be a good solution to the problem.

@codecov
Copy link

codecov bot commented Nov 28, 2021

Codecov Report

Merging #2008 (bd35cb8) into main (fde8ed0) will increase coverage by 0.01%.
The diff coverage is 61.76%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2008      +/-   ##
==========================================
+ Coverage   61.16%   61.17%   +0.01%     
==========================================
  Files          96       96              
  Lines       19255    19285      +30     
  Branches     9862     9862              
==========================================
+ Hits        11777    11798      +21     
- Misses       5135     5146      +11     
+ Partials     2343     2341       -2     
Impacted Files Coverage Δ
include/exiv2/types.hpp 70.58% <ø> (ø)
src/types.cpp 87.98% <ø> (ø)
src/value.cpp 72.45% <56.66%> (-0.74%) ⬇️
include/exiv2/value.hpp 83.15% <100.00%> (+0.09%) ⬆️
src/tiffvisitor_int.cpp 76.20% <100.00%> (-0.03%) ⬇️
src/jpgimage.cpp 70.48% <0.00%> (+0.56%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fde8ed0...bd35cb8. Read the comment docs.

@kevinbackhouse kevinbackhouse force-pushed the FixIssue2001 branch 2 times, most recently from 84ecb6f to 5eab1d1 Compare November 29, 2021 10:49
Copy link
Collaborator

@clanmills clanmills left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kevinbackhouse This looks ingenious.

I will confess to being nervous about introducing new classes and typeIds. There could be unexpected "ripple". The simple fix of warning when a preview is > 4mb seems much less brutal and risky.

However, you've put in a solid effort and this deserves detailed inspection with the debugger and I will do that in the next couple of days.

@clanmills
Copy link
Collaborator

This is very good work, @kevinbackhouse. I don't want to accept this into 0.27-maintenance. However, I will approve this for 'main' if you wish.

As the saying goes "when you are in a hole, stop digging". The hole here is that the "external" preview is a Sony violation of the Exif spec. By adding a typeId to deal with this, you are saying it's OK. A simpler solution is to warn that Sony tag 0x2001 is illegal and take no further action (no allocation, do nothing at all).

You are right that an arbitrary preview limit of 1mb, or 4mb can we swamped by adding sufficient previews. The safe limit is to warn and ignore all "external" previews.

I am bothered by the use of 0xffff. Why can't you use previewBuffer = 19 ?

About 12 months ago there was a discussion about SubImages which have an arbitrary restriction of 10. I am suspicious of the Exiv2 Architecture concerning SubImages and the multitude of groups such as Exif.Sony1Cs.LocalAFAreaPoint and Exif.Sony1Cs2.LocalAFAreaPoint. These can be simplified to (as done in tvisitor.cpp) to Exif.Sony.LocalAFAreaPoint. I believe fixing the state machine to correctly handle SubImages and different IfdIds is a major task. That change will be necessary to handle multi-page files. The change proposed in this PR will make re-engineering the state machine more difficult.

BTW, I don't know why there are typeIds for XMP data. I suspect that's another architectural issue that requires investigation and redesign. My suspicion is that it was added in 2005 or 2006 as a "quick fix" to support the XMPsdk and has never been properly addressed.

@clanmills
Copy link
Collaborator

clanmills commented Nov 30, 2021

I thought of something to say in great praise of your design of assigning a new typeId for "external" previews. I recall Andreas talking about those previews and saying that it's probably impossible to rewrite one of those files without damaging the preview. Your design addresses that issue beautifully as you have allocated and stored the preview.

We should modify JpegBase::writeMetadata() to find a suitable location in the file at which to store the preview. I suspect the current code in src/jpgimage.cpp code will require careful change to do this correctly. However, using a new typeId is an ingenious way to preserve the preview when the file is rewritten.

@kevinbackhouse
Copy link
Collaborator Author

@clanmills: I had an idea for a hacky workaround that doesn't involve adding a new type: #2013. The idea is to put a string in the metadata rather than a big buffer full of zeros. Maybe something like that could be a pragmatic solution for the 0.27-maintenance branch?

@kevinbackhouse
Copy link
Collaborator Author

I have converted this to draft so that we can revisit it in the future. The PreviewBufferValue class might be useful if we want to preserve this tag through rewrites, which will involve updating the offset which is stored in the tag when we change the size of the file.

Meanwhile, #2015 is probably a better short-term fix.

@clanmills
Copy link
Collaborator

@kevinbackhouse I think you're right AND you're incorrect.

You're right: When you floated the concept of previewBuffer, I thought "That's inginenous. We will allocate and track previews and that should make the rewrite easy".

You're incorrect: Now that I've tracked down and found a test file, I thinking that we don't need to store offset/length. These previews are JPEG artefacts and should not be cross referenced in the Exif data.

However, let's hold this. If David @dhoulder works on this during "The Holidays" the truth will emerge.

We don't have an spec for 0x2001. If it's an offset/length to the preview, we might need to write the whole file, and then use a fixup to edit the offset/length in 0x2001. However, I suspect the reason the 0x2001 count is zero in some files is because you can find the preview by parsing the JPEG and don't need the offset/length at all! For sure, my Nikon D5300 stores previews in this way without the need for an equivalent to Sony/0x2001.

Together, we're making good progress with this.

@piponazo
Copy link
Collaborator

Hi all. I noticed that #2015 already fixed #2001 . Do you still want to keep this PR alive?

By the way, kudos to you guys for the investigation done around this issue and solving it. I am looking forward to spend more time on Exiv2 and join to the party 😉

@clanmills
Copy link
Collaborator

You're always welcome to contribute @piponazo. Good to have you here. You did very good work this week on #2018.

I think this PR can be closed as it was superceded by #2015. However, let's leave it to @kevinbackhouse to close this and delete the branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

exiv2 occasionally crashes
3 participants