/* * Copyright (c) 2020, Andreas Kling * Copyright (c) 2023-2025, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #include namespace IPC { // Maximum size for decoded containers (strings, buffers, vectors, etc.) // This prevents a malicious peer from claiming huge sizes to cause OOM. static constexpr size_t MAX_DECODED_SIZE = 64 * MiB; ErrorOr Decoder::decode_size() { auto size = static_cast(TRY(decode())); if (size > MAX_DECODED_SIZE) return Error::from_string_literal("IPC decode: Size exceeds maximum allowed"); return size; } template<> ErrorOr decode(Decoder& decoder) { auto length = TRY(decoder.decode_size()); return String::from_stream(decoder.stream(), length); } template<> ErrorOr decode(Decoder& decoder) { auto is_ascii = TRY(decoder.decode()); auto length_in_code_units = TRY(decoder.decode_size()); return Utf16String::from_ipc_stream(decoder.stream(), length_in_code_units, is_ascii); } template<> ErrorOr decode(Decoder& decoder) { auto length = TRY(decoder.decode_size()); if (length == 0) return ByteString::empty(); return ByteString::create_and_overwrite(length, [&](Bytes bytes) -> ErrorOr { TRY(decoder.decode_into(bytes)); return {}; }); } template<> ErrorOr decode(Decoder& decoder) { auto length = TRY(decoder.decode_size()); if (length == 0) return ByteBuffer {}; auto buffer = TRY(ByteBuffer::create_uninitialized(length)); auto bytes = buffer.bytes(); TRY(decoder.decode_into(bytes)); return buffer; } template<> ErrorOr decode(Decoder& decoder) { auto json = TRY(decoder.decode()); return JsonValue::from_string(json); } template<> ErrorOr decode(Decoder& decoder) { auto nanoseconds = TRY(decoder.decode()); return AK::Duration::from_nanoseconds(nanoseconds); } template<> ErrorOr decode(Decoder& decoder) { auto nanoseconds = TRY(decoder.decode()); return AK::UnixDateTime::from_nanoseconds_since_epoch(nanoseconds); } template<> ErrorOr decode(Decoder& decoder) { auto ipv4 = TRY(decoder.decode()); return IPv4Address(ipv4); } template<> ErrorOr decode(Decoder& decoder) { auto ipv6 = TRY(decoder.decode>()); return IPv6Address(ipv6); } template<> ErrorOr decode(Decoder& decoder) { auto url_string = TRY(decoder.decode()); auto url = URL::Parser::basic_parse(url_string); if (!url.has_value()) return Error::from_string_view("Failed to parse URL in IPC Decode"sv); bool has_blob_url = TRY(decoder.decode()); if (!has_blob_url) return url.release_value(); url->set_blob_url_entry(URL::BlobURLEntry { .object = TRY(decoder.decode()), .environment { .origin = TRY(decoder.decode()) }, }); return url.release_value(); } template<> ErrorOr decode(Decoder& decoder) { auto is_opaque = TRY(decoder.decode()); if (is_opaque) { auto nonce = TRY(decoder.decode()); auto type = TRY(decoder.decode()); return URL::Origin { URL::Origin::OpaqueData { nonce, type } }; } auto scheme = TRY(decoder.decode>()); auto host = TRY(decoder.decode()); auto port = TRY(decoder.decode>()); auto domain = TRY(decoder.decode>()); return URL::Origin { move(scheme), move(host), port, move(domain) }; } template<> ErrorOr decode(Decoder& decoder) { auto value = TRY(decoder.decode()); return URL::Host { move(value) }; } template<> ErrorOr decode(Decoder&) { return Empty {}; } template<> ErrorOr decode(Decoder& decoder) { if (auto valid = TRY(decoder.decode()); !valid) return Core::AnonymousBuffer {}; // NOTE: We don't use decode_size() here since AnonymousBuffer is backed by // shared memory, not heap allocation. The MAX_DECODED_SIZE limit doesn't // apply because the memory is already allocated by the sender. auto size = static_cast(TRY(decoder.decode())); auto anon_file = TRY(decoder.decode()); return Core::AnonymousBuffer::create_from_anon_fd(anon_file.take_fd(), size); } template<> ErrorOr decode(Decoder& decoder) { auto type = TRY(decoder.decode()); auto host_ipv4 = IPv4Address(TRY(decoder.decode())); auto port = TRY(decoder.decode()); return Core::ProxyData { type, host_ipv4, port }; } template<> ErrorOr decode(Decoder& decoder) { return URL::BlobURLEntry::Blob { .type = TRY(decoder.decode()), .data = TRY(decoder.decode()) }; } template<> ErrorOr decode(Decoder&) { return URL::BlobURLEntry::MediaSource {}; } }