Skip to content

Commit 035e517

Browse files
committed
Add bounds checks and extend XMP namespace handling
Add numerous safety checks, new XMP namespace constants, and extended XMP->portable mapping/parsing. Key changes: - Introduce JPEG/TIFF size limits and helper functions (kMaxJpegSegmentPayload, jpeg_segment_length_u16, set_jpeg_segment_limit_error, append_jpeg_segment) and enforce payload limits when emitting/compiling JPEG segments and building C2PA sign requests. - Replace unchecked arithmetic with checked helpers (ifd_directory_size_bytes_checked, checked_u32_add, checked_u32_add_size, checked_align_to_2) to avoid integer overflow when computing IFD and data cursor sizes; enforce max TIFF/EXIF bytes. - Add many new XMP namespace constants and prefix mappings in xmp_decode/xmp_dump (stDim, stEvt, stFnt, stJob, stMfs, stRef, stVer, xmpBJ, xmpDM, xmpTPg, xmpG, etc.) and update portable property/shape logic accordingly. - Add new parsing/resolution helpers for qualified and indexed structured XMP property names (resolve_qualified_xmp_property_name, resolve_existing_xmp_component_to_portable, parse_indexed_structured_indexed_nested_xmp_property_name) and new PortableIndexedStructuredIndexedNestedProperty struct plus related promotions and shape rules. - Improve bounds checks in maker-note decoders and container scanner (Nikon, Olympus, Sony, container_scan) to guard against small/invalid inputs and large entry counts/offsets. - Tighten checks when copying/patching TIFF data and when validating value offsets to prevent out-of-range accesses. These changes harden parsing/emission code against malformed or malicious inputs and expand XMP handling for additional structured/qualified fields.
1 parent f5fe9da commit 035e517

13 files changed

Lines changed: 7386 additions & 426 deletions

src/include/openmeta/xmp_dump.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,30 @@ struct XmpPortableOptions final {
8787
/// bounded lang-alt paths like `title[@xml:lang=x-default]`, bounded
8888
/// one-level structured paths like `CreatorContactInfo/CiEmailWork`,
8989
/// bounded qualified one-level structured child paths like
90-
/// `LocationShown[1]/xmp:Identifier[1]` and
90+
/// `LocationShown[1]/xmp:Identifier[1]`,
9191
/// `LocationShown[1]/exif:GPSLatitude`,
92+
/// `DerivedFrom/stRef:documentID`,
93+
/// `JobRef[1]/stJob:id`,
94+
/// `RenditionOf/stRef:filePath`,
95+
/// `Ingredients[1]/stRef:documentID`,
96+
/// `MaxPageSize/stDim:w`,
97+
/// `Fonts[1]/stFnt:fontName`,
98+
/// `Fonts[1]/stFnt:childFontFiles[1]`,
99+
/// `Colorants[1]/xmpG:swatchName`,
100+
/// `SwatchGroups[1]/xmpG:groupName`,
101+
/// `ProjectRef/path`,
102+
/// `beatSpliceParams/riseInTimeDuration/scale`,
103+
/// `markers/cuePointParams/key`,
104+
/// `contributedMedia[1]/duration/scale`,
105+
/// `resampleParams/quality`,
106+
/// `startTimecode/timeValue`,
107+
/// `timeScaleParams/quality`,
108+
/// `Pantry[1]/InstanceID`,
109+
/// `Pantry[1]/dc:format`,
110+
/// `videoFrameSize/stDim:w`,
111+
/// `videoAlphaPremultipleColor/xmpG:mode`,
112+
/// `Manifest[1]/stMfs:reference/stRef:filePath`, and
113+
/// `Versions[1]/stVer:event/stEvt:action`,
92114
/// bounded indexed-structured paths like `Licensee[1]/LicenseeName`,
93115
/// bounded second-level structured scalar paths like
94116
/// `CreatorContactInfo/CiAdrRegion/ProvinceName`, bounded structured

src/openmeta/container_scan.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4323,6 +4323,9 @@ scan_tiff(std::span<const std::byte> bytes,
43234323
continue;
43244324
}
43254325
entry_count = n64;
4326+
if (entry_count > 0x10000ULL) {
4327+
continue;
4328+
}
43264329
entries_off = ifd_off + 8;
43274330
entry_size = 20;
43284331
next_ifd_off_pos = entries_off + entry_count * entry_size;

src/openmeta/exif_makernote_nikon.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2833,6 +2833,9 @@ decode_nikon_binary_subdirs(std::string_view mk_ifd0, MetaStore& store, bool le,
28332833
0x06ec, 0x06ee, 0x06f0, 0x06f2, 0x06f4, 0x06f6, 0x06f8,
28342834
0x06fa, 0x06fc, 0x06fe, 0x0700, 0x0702,
28352835
};
2836+
if (raw_src.size() < 4U) {
2837+
continue;
2838+
}
28362839

28372840
std::vector<std::byte> dec;
28382841
dec.resize(raw_src.size());
@@ -3107,6 +3110,9 @@ decode_nikon_binary_subdirs(std::string_view mk_ifd0, MetaStore& store, bool le,
31073110
0x0204, 0x0238, 0x023c, 0x023e, 0x0240, 0x0241, 0x0242,
31083111
0x0248, 0x024e, 0x024f, 0x035a,
31093112
};
3113+
if (raw_src.size() < 4U) {
3114+
continue;
3115+
}
31103116

31113117
std::vector<std::byte> dec;
31123118
dec.resize(raw_src.size());

src/openmeta/exif_makernote_olympus.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ namespace {
9595
continue;
9696
}
9797
const uint64_t sub_ifd_off = sub_ifd_off32;
98-
if (sub_ifd_off >= mn.size()) {
98+
if (sub_ifd_off >= mn.size()
99+
|| mn.size() - static_cast<size_t>(sub_ifd_off) < 2U) {
99100
continue;
100101
}
101102

src/openmeta/exif_makernote_sony.cc

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,10 +1563,12 @@ decode_sony_meterinfo_from_tag2010(std::span<const std::byte> bytes,
15631563
if (uint32_t(r.len) > options.limits.max_value_bytes) {
15641564
continue;
15651565
}
1566-
const uint16_t abs_off = uint16_t(meter_off + r.off);
1567-
if (uint64_t(abs_off) + uint64_t(r.len) > bytes.size()) {
1566+
const uint64_t abs_off64 = uint64_t(meter_off) + uint64_t(r.off);
1567+
if (abs_off64 > static_cast<uint64_t>(UINT16_MAX)
1568+
|| abs_off64 + uint64_t(r.len) > bytes.size()) {
15681569
continue;
15691570
}
1571+
const uint16_t abs_off = static_cast<uint16_t>(abs_off64);
15701572
const MetaValue v = make_sony_deciphered_bytes(store.arena(), bytes,
15711573
abs_off, r.len, rounds);
15721574
if (v.kind != MetaValueKind::Bytes) {
@@ -2036,7 +2038,12 @@ decode_sony_faceinfo_from_shotinfo(bool le, std::span<const std::byte> bytes,
20362038
uint32_t out_count = 0;
20372039

20382040
for (uint16_t i = 0; i < face_count; ++i) {
2039-
const uint16_t tag = uint16_t(face_len * i);
2041+
const uint32_t tag32
2042+
= static_cast<uint32_t>(face_len) * static_cast<uint32_t>(i);
2043+
if (tag32 > static_cast<uint32_t>(UINT16_MAX)) {
2044+
continue;
2045+
}
2046+
const uint16_t tag = static_cast<uint16_t>(tag32);
20402047
const uint64_t off = uint64_t(face_off) + uint64_t(face_len) * i;
20412048
uint16_t rect[4];
20422049
bool ok = true;

0 commit comments

Comments
 (0)