[{"id":39856,"web_url":"https://patchwork.libcamera.org/comment/39856/","msgid":"<20260725154423.GD1059400@killaraus.ideasonboard.com>","date":"2026-07-25T15:44:23","subject":"Re: [PATCH v2 2/2] libcamera: Harden control serializer size and\n\tinput validation","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Sat, Jul 25, 2026 at 03:14:07PM +0200, Magdum wrote:\n> Add overflow-safe size computations before writing 32-bit wire\n> fields, centralize control-name size accounting, and validate\n> deserialized local control direction values. Strengthen tests\n> with alignment-safe packet mutation, deterministic malformed\n> name-offset corruption, and max-length control-name boundary\n> coverage.\n> \n> Signed-off-by: Magdum <magdum.foss@gmail.com>\n> ---\n> <<I feel like this function could go into the previous patch.\n> Agreed. Moved serializedControlNameSize into the patch that first introduces it.\n\nThe proper way to reply to review comments is to reply to the e-mail\nfrom the reviewer, not adding comments in the next version.\n\n> <<You can adjust this:\n> <<   if (rhs && lhs > std::numeric_limits<size_t>::max() / rhs)\n> <<     return false;\n> << and drop the previous `if`.\n> Good simplification — the rhs && guard makes the explicit zero-case branch unnecessary since lhs * 0 = 0 falls through correctly anyway.\n> \n> <<You can just say `return *out >= lhs;` and drop the `if`.\n> Done\n> \n> << But in any case I am a bit wary of these ad-hoc implementations here. Given that\n> <<only clang and gcc are supported as compilers, I think it would be preferable to\n> <<use the overflow checking builtins: https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html\n> <<Specifically `__builtin_{add,mul}_overflow`, possibly hidden inside some trivial\n> <<wrappers in `utils.h`.\n> Good call — replaced both ad-hoc implementations with __builtin_add_overflow / __builtin_mul_overflow wrapped as utils::addOverflow / utils::mulOverflow in utils.h, following the pattern of the existing utils helpers.\n> \n> <<You can use `utils::to_underlying()`.\n> Done\n> \n> <<You can just say `case (kDirectionIn | kDirectionOut):` here\n> Done\n> \n> <<But you can also simplify the function greatly, e.g.:\n> <<   constexpr unsigned int valid = utils::to_underlying(ControlId::Direction::In) | utils::to_underlying(ControlId::Direction::Out);\n> <<   return (direction & valid) && !(direction & ~valid);\n> Done\n> \n> ========================================================================\n> CHANGELOG / COMMENTS FROM REPLY.TXT:\n> ========================================================================\n\nWhat is REPLY.TXT ?\n\nThis makes me feel you're using generative AI to write those patches.\nWriting an AI policy for libcamera is on my todo list. It will forbid\nthe use of generative AI to contribute to the project. As such, I don't\nthink this series is acceptable.\n\n> ========================================================================\n>  include/libcamera/base/utils.h               |  12 ++\n>  src/libcamera/control_serializer.cpp         | 196 ++++++++++++++++---\n>  test/serialization/control_serialization.cpp |  86 ++++++--\n>  3 files changed, 257 insertions(+), 37 deletions(-)\n> \n> diff --git a/include/libcamera/base/utils.h b/include/libcamera/base/utils.h\n> index 9835fd798..d73db428c 100644\n> --- a/include/libcamera/base/utils.h\n> +++ b/include/libcamera/base/utils.h\n> @@ -449,6 +449,18 @@ constexpr details::defopt_t defopt;\n>  std::ostream &operator<<(std::ostream &os, const Duration &d);\n>  #endif\n>  \n> +template<typename T>\n> +bool addOverflow(T lhs, T rhs, T *result)\n> +{\n> +\treturn __builtin_add_overflow(lhs, rhs, result);\n> +}\n> +\n> +template<typename T>\n> +bool mulOverflow(T lhs, T rhs, T *result)\n> +{\n> +\treturn __builtin_mul_overflow(lhs, rhs, result);\n> +}\n> +\n>  } /* namespace utils */\n>  \n>  } /* namespace libcamera */\n> diff --git a/src/libcamera/control_serializer.cpp b/src/libcamera/control_serializer.cpp\n> index a420d4700..ceafff326 100644\n> --- a/src/libcamera/control_serializer.cpp\n> +++ b/src/libcamera/control_serializer.cpp\n> @@ -8,11 +8,13 @@\n>  #include \"libcamera/internal/control_serializer.h\"\n>  \n>  #include <algorithm>\n> +#include <limits>\n>  #include <memory>\n>  #include <vector>\n>  \n>  #include <libcamera/base/log.h>\n>  #include <libcamera/base/span.h>\n> +#include <libcamera/base/utils.h>\n>  \n>  #include <libcamera/control_ids.h>\n>  #include <libcamera/controls.h>\n> @@ -53,7 +55,31 @@ bool idMapRequiresLocalIds(enum ipa_controls_id_map_type idMapType)\n>  size_t serializedControlNameSize(const ControlId *id,\n>  \t\tenum ipa_controls_id_map_type idMapType)\n>  {\n> -\treturn idMapRequiresLocalIds(idMapType) ? id->name().size() + 1 : 1;\n> +\treturn idMapRequiresLocalIds(idMapType) ? id->name().size() : 1;\n> +}\n> +\n> +bool fitsU32(size_t value)\n> +{\n> +\treturn value <= std::numeric_limits<uint32_t>::max();\n> +}\n> +\n> +bool safeMulSizeT(size_t lhs, size_t rhs, size_t *out)\n> +{\n> +\treturn !utils::mulOverflow(lhs, rhs, out);\n> +}\n> +\n> +bool safeAddSizeT(size_t lhs, size_t rhs, size_t *out)\n> +{\n> +\treturn !utils::addOverflow(lhs, rhs, out);\n> +}\n> +\n> +bool isValidDirection(uint8_t direction)\n> +{\n> +\tconstexpr unsigned int valid =\n> +\t\tutils::to_underlying(ControlId::Direction::In) |\n> +\t\tutils::to_underlying(ControlId::Direction::Out);\n> +\n> +\treturn (direction & valid) && !(direction & ~valid);\n>  }\n>  \n>  } /* namespace */\n> @@ -190,14 +216,27 @@ size_t ControlSerializer::binarySize(const ControlInfo &info)\n>   */\n>  size_t ControlSerializer::binarySize(const ControlInfoMap &infoMap)\n>  {\n> -\tsize_t size = sizeof(struct ipa_controls_header)\n> -\t\t    + infoMap.size() * sizeof(struct ipa_control_info_entry);\n> +\tsize_t entriesSize;\n> +\tif (!safeMulSizeT(infoMap.size(), sizeof(struct ipa_control_info_entry),\n> +\t\t\t  &entriesSize))\n> +\t\treturn std::numeric_limits<size_t>::max();\n> +\n> +\tsize_t size;\n> +\tif (!safeAddSizeT(sizeof(struct ipa_controls_header), entriesSize, &size))\n> +\t\treturn std::numeric_limits<size_t>::max();\n> +\n>  \tenum ipa_controls_id_map_type idMapType = idMapTypeFor(infoMap.idmap());\n>  \n>  \tfor (const auto &ctrl : infoMap) {\n> -\t\tsize += binarySize(ctrl.second);\n> -\n> -\t\tsize += serializedControlNameSize(ctrl.first, idMapType);\n> +\t\tsize_t nextSize;\n> +\t\tif (!safeAddSizeT(size, binarySize(ctrl.second), &nextSize))\n> +\t\t\treturn std::numeric_limits<size_t>::max();\n> +\t\tsize = nextSize;\n> +\n> +\t\tsize_t nameSize = serializedControlNameSize(ctrl.first, idMapType);\n> +\t\tif (!safeAddSizeT(size, nameSize, &nextSize))\n> +\t\t\treturn std::numeric_limits<size_t>::max();\n> +\t\tsize = nextSize;\n>  \t}\n>  \n>  \treturn size;\n> @@ -214,10 +253,21 @@ size_t ControlSerializer::binarySize(const ControlInfoMap &infoMap)\n>   */\n>  size_t ControlSerializer::binarySize(const ControlList &list)\n>  {\n> -\tsize_t size = sizeof(struct ipa_controls_header) + list.size() * sizeof(struct ipa_control_list_entry);\n> +\tsize_t entriesSize;\n> +\tif (!safeMulSizeT(list.size(), sizeof(struct ipa_control_list_entry),\n> +\t\t\t  &entriesSize))\n> +\t\treturn std::numeric_limits<size_t>::max();\n> +\n> +\tsize_t size;\n> +\tif (!safeAddSizeT(sizeof(struct ipa_controls_header), entriesSize, &size))\n> +\t\treturn std::numeric_limits<size_t>::max();\n>  \n> -\tfor (const auto &ctrl : list)\n> -\t\tsize += binarySize(ctrl.second);\n> +\tfor (const auto &ctrl : list) {\n> +\t\tsize_t nextSize;\n> +\t\tif (!safeAddSizeT(size, binarySize(ctrl.second), &nextSize))\n> +\t\t\treturn std::numeric_limits<size_t>::max();\n> +\t\tsize = nextSize;\n> +\t}\n>  \n>  \treturn size;\n>  }\n> @@ -264,23 +314,70 @@ int ControlSerializer::serialize(const ControlInfoMap &infoMap,\n>  \tenum ipa_controls_id_map_type idMapType = idMapTypeFor(infoMap.idmap());\n>  \n>  \t/* Compute entries and data required sizes. */\n> -\tsize_t entriesSize = infoMap.size()\n> -\t\t\t   * sizeof(struct ipa_control_info_entry);\n> +\tsize_t entriesSize;\n> +\tif (!safeMulSizeT(infoMap.size(), sizeof(struct ipa_control_info_entry),\n> +\t\t\t  &entriesSize)) {\n> +\t\tLOG(Serializer, Error)\n> +\t\t\t<< \"ControlInfoMap entries size overflows\";\n> +\t\treturn -E2BIG;\n> +\t}\n> +\n>  \tsize_t valuesSize = 0;\n>  \tfor (const auto &ctrl : infoMap) {\n> -\t\tvaluesSize += binarySize(ctrl.second);\n> -\t\tvaluesSize += idMapRequiresLocalIds(idMapType)\n> -\t\t\t\t      ? ctrl.first->name().size()\n> -\t\t\t\t      : 0;\n> +\t\tsize_t valueSize = binarySize(ctrl.second);\n> +\t\tsize_t nextValuesSize;\n> +\t\tif (!safeAddSizeT(valuesSize, valueSize, &nextValuesSize)) {\n> +\t\t\tLOG(Serializer, Error)\n> +\t\t\t\t<< \"ControlInfoMap values size overflows\";\n> +\t\t\treturn -E2BIG;\n> +\t\t}\n> +\t\tvaluesSize = nextValuesSize;\n> +\n> +\t\tsize_t nameSize = serializedControlNameSize(ctrl.first, idMapType);\n> +\t\tif (!safeAddSizeT(valuesSize, nameSize, &nextValuesSize)) {\n> +\t\t\tLOG(Serializer, Error)\n> +\t\t\t\t<< \"ControlInfoMap names size overflows\";\n> +\t\t\treturn -E2BIG;\n> +\t\t}\n> +\t\tvaluesSize = nextValuesSize;\n> +\t}\n> +\n> +\tif (!fitsU32(infoMap.size()) || !fitsU32(entriesSize) ||\n> +\t    !fitsU32(valuesSize)) {\n> +\t\tLOG(Serializer, Error)\n> +\t\t\t<< \"ControlInfoMap serialization size exceeds wire limits\";\n> +\t\treturn -E2BIG;\n> +\t}\n> +\n> +\tsize_t totalSize;\n> +\tif (!safeAddSizeT(sizeof(struct ipa_controls_header), entriesSize,\n> +\t\t\t  &totalSize) ||\n> +\t    !safeAddSizeT(totalSize, valuesSize, &totalSize)) {\n> +\t\tLOG(Serializer, Error)\n> +\t\t\t<< \"ControlInfoMap packet size overflows\";\n> +\t\treturn -E2BIG;\n> +\t}\n> +\n> +\tsize_t dataOffset;\n> +\tif (!safeAddSizeT(sizeof(struct ipa_controls_header), entriesSize,\n> +\t\t\t  &dataOffset)) {\n> +\t\tLOG(Serializer, Error)\n> +\t\t\t<< \"ControlInfoMap data offset overflows\";\n> +\t\treturn -E2BIG;\n> +\t}\n> +\tif (!fitsU32(totalSize) || !fitsU32(dataOffset)) {\n> +\t\tLOG(Serializer, Error)\n> +\t\t\t<< \"ControlInfoMap packet header exceeds wire limits\";\n> +\t\treturn -E2BIG;\n>  \t}\n>  \n>  \t/* Prepare the packet header. */\n>  \tstruct ipa_controls_header hdr = {};\n>  \thdr.version = IPA_CONTROLS_FORMAT_VERSION;\n>  \thdr.handle = serial_;\n> -\thdr.entries = infoMap.size();\n> -\thdr.size = sizeof(hdr) + entriesSize + valuesSize;\n> -\thdr.data_offset = sizeof(hdr) + entriesSize;\n> +\thdr.entries = static_cast<uint32_t>(infoMap.size());\n> +\thdr.size = static_cast<uint32_t>(totalSize);\n> +\thdr.data_offset = static_cast<uint32_t>(dataOffset);\n>  \thdr.id_map_type = idMapType;\n>  \n>  \tbuffer.write(&hdr);\n> @@ -389,18 +486,62 @@ int ControlSerializer::serialize(const ControlList &list,\n>  \telse\n>  \t\tidMapType = IPA_CONTROL_ID_MAP_V4L2;\n>  \n> -\tsize_t entriesSize = list.size() * sizeof(struct ipa_control_list_entry);\n> +\tsize_t entriesSize;\n> +\tif (!safeMulSizeT(list.size(), sizeof(struct ipa_control_list_entry),\n> +\t\t\t  &entriesSize)) {\n> +\t\tLOG(Serializer, Error)\n> +\t\t\t<< \"ControlList entries size overflows\";\n> +\t\treturn -E2BIG;\n> +\t}\n> +\n>  \tsize_t valuesSize = 0;\n> -\tfor (const auto &ctrl : list)\n> -\t\tvaluesSize += binarySize(ctrl.second);\n> +\tfor (const auto &ctrl : list) {\n> +\t\tsize_t nextValuesSize;\n> +\t\tif (!safeAddSizeT(valuesSize, binarySize(ctrl.second),\n> +\t\t\t\t  &nextValuesSize)) {\n> +\t\t\tLOG(Serializer, Error)\n> +\t\t\t\t<< \"ControlList values size overflows\";\n> +\t\t\treturn -E2BIG;\n> +\t\t}\n> +\t\tvaluesSize = nextValuesSize;\n> +\t}\n> +\n> +\tif (!fitsU32(list.size()) || !fitsU32(entriesSize) ||\n> +\t    !fitsU32(valuesSize)) {\n> +\t\tLOG(Serializer, Error)\n> +\t\t\t<< \"ControlList serialization size exceeds wire limits\";\n> +\t\treturn -E2BIG;\n> +\t}\n> +\n> +\tsize_t totalSize;\n> +\tif (!safeAddSizeT(sizeof(struct ipa_controls_header), entriesSize,\n> +\t\t\t  &totalSize) ||\n> +\t    !safeAddSizeT(totalSize, valuesSize, &totalSize)) {\n> +\t\tLOG(Serializer, Error)\n> +\t\t\t<< \"ControlList packet size overflows\";\n> +\t\treturn -E2BIG;\n> +\t}\n> +\n> +\tsize_t dataOffset;\n> +\tif (!safeAddSizeT(sizeof(struct ipa_controls_header), entriesSize,\n> +\t\t\t  &dataOffset)) {\n> +\t\tLOG(Serializer, Error)\n> +\t\t\t<< \"ControlList data offset overflows\";\n> +\t\treturn -E2BIG;\n> +\t}\n> +\tif (!fitsU32(totalSize) || !fitsU32(dataOffset)) {\n> +\t\tLOG(Serializer, Error)\n> +\t\t\t<< \"ControlList packet header exceeds wire limits\";\n> +\t\treturn -E2BIG;\n> +\t}\n>  \n>  \t/* Prepare the packet header. */\n>  \tstruct ipa_controls_header hdr = {};\n>  \thdr.version = IPA_CONTROLS_FORMAT_VERSION;\n>  \thdr.handle = infoMapHandle;\n> -\thdr.entries = list.size();\n> -\thdr.size = sizeof(hdr) + entriesSize + valuesSize;\n> -\thdr.data_offset = sizeof(hdr) + entriesSize;\n> +\thdr.entries = static_cast<uint32_t>(list.size());\n> +\thdr.size = static_cast<uint32_t>(totalSize);\n> +\thdr.data_offset = static_cast<uint32_t>(dataOffset);\n>  \thdr.id_map_type = idMapType;\n>  \n>  \tbuffer.write(&hdr);\n> @@ -586,6 +727,13 @@ ControlInfoMap ControlSerializer::deserialize<ControlInfoMap>(ByteStreamBuffer &\n>  \n>  \t\t/* If we're using a local id map, populate it with the restored name. */\n>  \t\tif (localIdMap) {\n> +\t\t\tif (!isValidDirection(entry->direction)) {\n> +\t\t\t\tLOG(Serializer, Error)\n> +\t\t\t\t\t<< \"Control direction is invalid: \"\n> +\t\t\t\t\t<< static_cast<unsigned int>(entry->direction);\n> +\t\t\t\treturn {};\n> +\t\t\t}\n> +\n>  \t\t\tstd::string ctrlName(reinterpret_cast<const char *>(nameData),\n>  \t\t\t\t\t     entry->name_len);\n>  \n> diff --git a/test/serialization/control_serialization.cpp b/test/serialization/control_serialization.cpp\n> index b1638db9f..1fb8cc8b7 100644\n> --- a/test/serialization/control_serialization.cpp\n> +++ b/test/serialization/control_serialization.cpp\n> @@ -6,6 +6,7 @@\n>   */\n>  \n>  #include <iostream>\n> +#include <cstring>\n>  \n>  #include <libcamera/camera.h>\n>  #include <libcamera/control_ids.h>\n> @@ -224,11 +225,13 @@ protected:\n>  \n>  \t\t/* Reject malformed packets with over-sized names. */\n>  \t\tvector<uint8_t> badNameLenData = infoData;\n> -\t\tauto *badNameLenHeader =\n> -\t\t\treinterpret_cast<ipa_controls_header *>(badNameLenData.data());\n> -\t\tauto *badNameLenEntry = reinterpret_cast<ipa_control_info_entry *>(\n> -\t\t\tbadNameLenData.data() + sizeof(*badNameLenHeader));\n> -\t\tbadNameLenEntry->name_len = 2048;\n> +\t\tipa_control_info_entry badNameLenEntry;\n> +\t\tstd::memcpy(&badNameLenEntry,\n> +\t\t\t    badNameLenData.data() + sizeof(ipa_controls_header),\n> +\t\t\t    sizeof(badNameLenEntry));\n> +\t\tbadNameLenEntry.name_len = 2048;\n> +\t\tstd::memcpy(badNameLenData.data() + sizeof(ipa_controls_header),\n> +\t\t\t    &badNameLenEntry, sizeof(badNameLenEntry));\n>  \n>  \t\tControlSerializer badNameLenDeserializer(ControlSerializer::Role::Worker);\n>  \t\tbuffer = ByteStreamBuffer(const_cast<const uint8_t *>(badNameLenData.data()),\n> @@ -238,15 +241,31 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>  \n> -\t\t/* Reject malformed packets with non-null-terminated names. */\n> -\t\tvector<uint8_t> badTermData = infoData;\n> -\t\tbadTermData.back() = 'X';\n> +\t\t/* Reject malformed packets with inconsistent name offsets. */\n> +\t\tvector<uint8_t> badNameOffsetData = infoData;\n> +\t\tipa_control_info_entry badNameOffsetEntry;\n> +\t\tstd::memcpy(&badNameOffsetEntry,\n> +\t\t\t    badNameOffsetData.data() + sizeof(ipa_controls_header),\n> +\t\t\t    sizeof(badNameOffsetEntry));\n> +\n> +\t\tif (badNameOffsetEntry.id != kV4L2TestControlId ||\n> +\t\t    badNameOffsetEntry.type != ControlTypeInteger32 ||\n> +\t\t    badNameOffsetEntry.def.type != ControlTypeInteger32 ||\n> +\t\t    badNameOffsetEntry.def.is_array || badNameOffsetEntry.def.count != 1 ||\n> +\t\t    badNameOffsetEntry.name_len != kV4L2ControlName.size()) {\n> +\t\t\tcerr << \"Malformed test packet layout for bad name offset test\" << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tbadNameOffsetEntry.name_offset += 1;\n> +\t\tstd::memcpy(badNameOffsetData.data() + sizeof(ipa_controls_header),\n> +\t\t\t    &badNameOffsetEntry, sizeof(badNameOffsetEntry));\n>  \n> -\t\tControlSerializer badTermDeserializer(ControlSerializer::Role::Worker);\n> -\t\tbuffer = ByteStreamBuffer(const_cast<const uint8_t *>(badTermData.data()),\n> -\t\t\t\t\t  badTermData.size());\n> -\t\tif (!badTermDeserializer.deserialize<ControlInfoMap>(buffer).empty()) {\n> -\t\t\tcerr << \"Control name without null terminator should be rejected\" << endl;\n> +\t\tControlSerializer badNameOffsetDeserializer(ControlSerializer::Role::Worker);\n> +\t\tbuffer = ByteStreamBuffer(const_cast<const uint8_t *>(badNameOffsetData.data()),\n> +\t\t\t\t\t  badNameOffsetData.size());\n> +\t\tif (!badNameOffsetDeserializer.deserialize<ControlInfoMap>(buffer).empty()) {\n> +\t\t\tcerr << \"Control with inconsistent name offset should be rejected\" << endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>  \n> @@ -278,6 +297,47 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>  \n> +\t\t/* Accept names at the configured length limit. */\n> +\t\tvector<unique_ptr<ControlId>> maxNameControlIds;\n> +\t\tControlIdMap maxNameIdMap;\n> +\t\tstring maxName(1024, 'm');\n> +\n> +\t\tmaxNameControlIds.emplace_back(std::make_unique<ControlId>(\n> +\t\t\t0x009a2003, maxName, \"v4l2\", ControlTypeInteger32,\n> +\t\t\tControlId::Direction::In));\n> +\t\tmaxNameIdMap.emplace(0x009a2003, maxNameControlIds.back().get());\n> +\n> +\t\tControlInfoMap::Map maxNameInfo;\n> +\t\tmaxNameInfo.emplace(maxNameControlIds.back().get(),\n> +\t\t\t\t    ControlInfo(ControlValue(int32_t{ 0 }),\n> +\t\t\t\t\t\tControlValue(int32_t{ 255 }),\n> +\t\t\t\t\t\tControlValue(int32_t{ 16 })));\n> +\t\tControlInfoMap maxNameInfoMap(std::move(maxNameInfo), maxNameIdMap);\n> +\n> +\t\tControlSerializer maxNameSerializer(ControlSerializer::Role::Proxy);\n> +\t\tControlSerializer maxNameDeserializer(ControlSerializer::Role::Worker);\n> +\n> +\t\tsize = maxNameSerializer.binarySize(maxNameInfoMap);\n> +\t\tinfoData.resize(size);\n> +\t\tbuffer = ByteStreamBuffer(infoData.data(), infoData.size());\n> +\n> +\t\tret = maxNameSerializer.serialize(maxNameInfoMap, buffer);\n> +\t\tif (ret < 0 || buffer.overflow()) {\n> +\t\t\tcerr << \"Max-length control name should serialize successfully\" << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tbuffer = ByteStreamBuffer(const_cast<const uint8_t *>(infoData.data()),\n> +\t\t\t\t\t  infoData.size());\n> +\t\tControlInfoMap maxNameInfoMapDes =\n> +\t\t\tmaxNameDeserializer.deserialize<ControlInfoMap>(buffer);\n> +\t\tauto maxNameIdIt = maxNameInfoMapDes.idmap().find(0x009a2003);\n> +\t\tif (maxNameIdIt == maxNameInfoMapDes.idmap().end() ||\n> +\t\t    maxNameIdIt->second->name() != maxName) {\n> +\t\t\tcerr << \"Max-length control name round-trip failed\" << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n>  \t\treturn TestPass;\n>  \t}\n>  };","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 050F5BE080\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSat, 25 Jul 2026 15:44:28 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id DE3C667F46;\n\tSat, 25 Jul 2026 17:44:26 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 6FE0E67E5C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 25 Jul 2026 17:44:25 +0200 (CEST)","from killaraus.ideasonboard.com\n\t(2001-14ba-70f3-e800--a06.rev.dnainternet.fi\n\t[IPv6:2001:14ba:70f3:e800::a06])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id B33853A4;\n\tSat, 25 Jul 2026 17:43:22 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"vhEaOTmn\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1784994202;\n\tbh=ftLSOCpoUWQQHT2G11lvNZr9LWoaLSm5YiOhQnTzIUM=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=vhEaOTmnAlREgfjnH0wFHt55aAmyqe4mvU9rieuXVF9B9k4OG72CCJObbncIPyGsw\n\tixAVCKbMzjER97/P1+kXaDxEqYpaRAOEmzXbd+FHafhv9+3uNr1oQbrhnZDnf7Y+Zc\n\tJMjALLtudP0gEn/9lIKt0Yml/a83wxQQ5Xzcpavw=","Date":"Sat, 25 Jul 2026 18:44:23 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Magdum <magdum.foss@gmail.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH v2 2/2] libcamera: Harden control serializer size and\n\tinput validation","Message-ID":"<20260725154423.GD1059400@killaraus.ideasonboard.com>","References":"<20260723174644.6580-3-magdum.foss@gmail.com>\n\t<20260725131932.13509-1-magdum.foss@gmail.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20260725131932.13509-1-magdum.foss@gmail.com>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]