Commit Graph

164 Commits

Author SHA1 Message Date
Andreas Kling
a0c389846e Revert "LibIPC: Move message decoding from main thread to I/O thread"
This reverts commit 757795ada4.

Appears to have regressed WPT.
2026-01-25 12:19:53 +01:00
Andreas Kling
757795ada4 LibIPC: Move message decoding from main thread to I/O thread
Previously, IPC messages were decoded on the main thread:

1. I/O thread received raw bytes and file descriptors
2. I/O thread stored them in a queue and notified main thread
3. Main thread decoded bytes into Message objects
4. Main thread processed the messages

Now, decoding happens on the I/O thread:

1. I/O thread receives raw bytes and file descriptors
2. I/O thread decodes them using a configurable MessageDecoder
3. I/O thread calls MessageHandler which stores decoded messages
4. I/O thread signals condition variable (for sync waiters)
5. I/O thread wakes main event loop via deferred_invoke()
6. Main thread processes already-decoded messages

This is achieved by:

- Adding MessageDecoder and MessageHandler callbacks to TransportSocket
- Connection template sets up the decoder (tries both endpoints)
- ConnectionBase::initialize_messaging() sets up the handler
- Storing a WeakEventLoopReference to wake the main thread
- Using mutex + condition variable for thread-safe queue access
- Sync message waiting now uses the CV directly instead of polling

The raw message API (read_as_many_messages_as_possible_without_blocking)
is preserved for MessagePort which uses its own decoding logic.

This architecture prepares for future multi-thread dispatch where
different message types could be routed to different handler threads
(e.g., scrolling messages to a dedicated scroll thread).
2026-01-25 09:32:51 +01:00
Andreas Kling
534c4c3736 LibIPC: Log actual decode errors when message parsing fails
Previously, when an IPC message failed to parse, we only logged
"Failed to parse IPC message" followed by a hex dump, making it
difficult to diagnose the actual cause.

Now we log the specific error from each endpoint's decode attempt,
making it much easier to identify issues like size limit violations
or invalid field values.
2026-01-24 15:23:02 +01:00
Andreas Kling
51ddfaafbf LibIPC: Don't apply decode size limit to AnonymousBuffer
AnonymousBuffer is backed by shared memory, not heap allocation.
The MAX_DECODED_SIZE limit in decode_size() is meant to prevent OOM
from malicious peers claiming huge sizes that would cause heap
allocations, but this doesn't apply to AnonymousBuffer since the
memory is already allocated by the sender.

This fixes decoding of large animated images (e.g. 300 frames at
240x240) where the total bitmap data exceeds 64 MiB.
2026-01-24 15:23:02 +01:00
Andreas Kling
2a6045833c LibCore: Make ProxyData::port a u16
TCP ports are always u16 and this prevents invalid values from getting
into this field somehow.
2026-01-22 17:38:15 +01:00
Andreas Kling
b4cbd321d9 LibIPC: Add additional validation for decoded values
Also add upfront bounds checking for variant indices before entering
the recursive template, allowing us to convert the template's fallback
error into VERIFY_NOT_REACHED() since the index is now guaranteed to
be valid when we enter the recursive decode.
2026-01-22 17:38:15 +01:00
Andreas Kling
980f23e58b LibIPC: Add VERIFY assertions to catch encoding bugs
- VERIFY that IPC::File has a valid fd (>= 0) before encoding
- VERIFY that container sizes fit in u32 before encoding

These catch programming errors where we accidentally try to encode
invalid data. Encoding bugs should crash immediately so we catch them
during development.
2026-01-22 17:38:15 +01:00
Andreas Kling
4d344e6cf7 LibIPC: VERIFY message limits when encoding outgoing messages
Add VERIFY assertions to catch bugs where we accidentally try to send
messages that exceed MAX_MESSAGE_PAYLOAD_SIZE or MAX_MESSAGE_FD_COUNT.

These are programming errors and should crash immediately so we catch
them during development, rather than silently sending invalid data.
2026-01-22 17:38:15 +01:00
Andreas Kling
cb3bc3c493 LibIPC: Move IPC message limits to a shared Limits.h header
This consolidates the message size and FD count limits into a single
header file that can be used by both the encoding and decoding sides
of the IPC layer.
2026-01-22 17:38:15 +01:00
Andreas Kling
6188c5a40f LibIPC: Add maximum size limit for decoded containers
A malicious peer could claim that a string, buffer, or vector has an
extremely large size (up to 4 GiB), causing allocation failures or OOM.

Add MAX_DECODED_SIZE (64 MiB) check in decode_size() to reject
excessively large containers before attempting allocation.
2026-01-22 17:38:15 +01:00
Andreas Kling
bef09fc277 LibIPC: Add limits on accumulated unprocessed data in TransportSocket
A malicious or misbehaving peer could send data faster than we process
it, causing unbounded memory growth in the unprocessed bytes buffer
and file descriptor queue.

Add MAX_UNPROCESSED_BUFFER_SIZE (128 MiB) and MAX_UNPROCESSED_FDS (512)
limits. When exceeded, the peer is disconnected gracefully rather than
allowing memory exhaustion.
2026-01-22 17:38:15 +01:00
Andreas Kling
bdca85f985 LibIPC: Add maximum limits for IPC message size and FD count
Reject messages from peers that exceed reasonable limits:
- Maximum payload size: 64 MiB
- Maximum file descriptor count: 128

Also use checked arithmetic for message size calculations to prevent
integer overflow attacks.

These limits prevent malicious peers from causing excessive memory
allocation or resource exhaustion.
2026-01-22 17:38:15 +01:00
Andreas Kling
8235506d5f LibIPC: Use TRY instead of MUST in post_message()
post_message() returns ErrorOr but was using MUST internally for
transfer_message(). If the transfer fails (e.g., socket error), we
would crash instead of propagating the error to the caller.
2026-01-22 17:38:15 +01:00
Andreas Kling
d15acc46d6 LibIPC: Use checked arithmetic for message size calculations
The message parsing loop performs arithmetic on payload_size (u32) and
index (size_t). While overflow is unlikely on 64-bit systems, use
Checked<size_t> to explicitly validate:

1. message_size = payload_size + sizeof(MessageHeader)
2. new_index = index + payload_size + sizeof(MessageHeader)

This prevents potential integer overflow attacks from malicious peers.
2026-01-22 17:38:15 +01:00
Andreas Kling
9e34434f3b LibIPC: Handle allocation failures gracefully in TransportSocket
Replace crash-on-OOM patterns with graceful error handling:

- Use try_append() instead of append() for buffer operations
- Handle ByteBuffer::copy() failure instead of using MUST()

A malicious peer could send messages with large payload sizes to
trigger OOM conditions. Instead of crashing, we now disconnect
the misbehaving peer.
2026-01-22 17:38:15 +01:00
Andreas Kling
a85abca388 LibIPC: Use try_resize() when decoding Vector of arithmetic types
The previous code used Vector::resize() which internally uses MUST(),
causing a crash if memory allocation fails. A malicious peer could
send a message with a large vector size to trigger OOM and crash the
recipient.

Use try_resize() instead to propagate the error gracefully.
2026-01-22 17:38:15 +01:00
Andreas Kling
1a213a9020 LibIPC: Harden TransportSocket against malicious FD count values
A malicious peer could exploit the file descriptor acknowledgement
protocol in several ways:

1. Send messages with fd_count values that overflow when accumulated
2. Send acknowledgements claiming more FDs were received than we sent

Both attacks would crash the recipient via VERIFY failures in
Queue::dequeue() or integer overflow.

Fix by using Checked<u32> for fd counters and validating the queue
isn't empty before dequeuing acknowledged FDs.
2026-01-22 17:38:15 +01:00
Andreas Kling
f94deb4afb LibIPC: Use try_dequeue() when decoding IPC::File
A malicious peer could send a message declaring an IPC::File parameter
without actually including the file descriptor. This would cause
Queue::dequeue() to crash via VERIFY(!is_empty()).

Use try_dequeue() instead, which returns an error that propagates up
through the decode chain, ultimately disconnecting the misbehaving peer.
2026-01-22 17:38:15 +01:00
Andreas Kling
ff7e568a7b LibIPC: Handle decode failures gracefully instead of crashing
A misbehaving or malicious IPC peer could send data that triggers
crashes during message decoding:

- A Vector size that would overflow when multiplied by element size
- An out-of-bounds Variant index

Instead of using VERIFY (which crashes), return errors that propagate
up through the decode chain. This causes try_parse_message() to return
nullptr, triggering graceful peer disconnection.
2026-01-22 17:38:15 +01:00
Andreas Kling
01c07a9f78 LibIPC: Replace crash-on-error with graceful peer disconnect
A misbehaving or compromised IPC peer (e.g. a WebContent process running
malicious JavaScript) could previously crash the UI process by sending
malformed messages. This was a problem: untrusted peers should only be
able to kill their own connection, not crash the process handling them.

Replace VERIFY_NOT_REACHED() and VERIFY() calls in error paths with
graceful disconnection using the existing shutdown infrastructure
(m_peer_eof, IOThreadState::Stopped, ShouldShutdown::Yes, etc.)

Affected error paths:
- Malformed IPC messages that fail to parse
- poll() errors and POLLERR/POLLNVAL conditions
- Unexpected send/receive errors on the socket
- Invalid message header types
- Protocol violations (e.g. bad FileDescriptorAcknowledgement)

All error paths now log via dbgln() for debugging before disconnecting.
2026-01-22 17:38:15 +01:00
Andreas Kling
dacd6b4530 LibIPC: Handle EAGAIN on non-blocking wakeup pipe read
The wakeup pipe is created with O_NONBLOCK, but MUST() was used for
reads. This could cause crashes on spurious wakeups when EAGAIN is
returned. Since the read is just to drain the pipe and wake the IO
thread, we can safely ignore any errors.
2026-01-13 21:05:58 +01:00
Arran Ireland
bd82dfa048 AK+LibURL: Use AK::IPv4/6 in Host
This resolves two FIXME comments.
2025-12-31 10:24:56 +01:00
Shannon Booth
89dbdd3411 LibURL: Add domain concept to URL::Origin to fix same-origin-domain
The same-origin domain check always returned true if only the scheme
matched. This was because of missing steps to check for the origin's
domain, which didn't exist. Add this concept to URL::Origin, even
though we do not use it at this stage in document.domain setter.

Co-Authored-By: Luke Wilde <luke@ladybird.org>
2025-12-30 13:02:10 +01:00
R-Goc
b9f1c7084b LibIPC: Add missing include and impl on win32
This commit adds a missing include to MessageWindows after header
cleanup. It also implement IPC::File which had its implementation moved
out of the header, without the matching change to the windows
implementation.
2025-12-05 07:07:52 -05:00
Timothy Flynn
674075f79e Everywhere: Remove LibCore/System.h includes from header files
This reduces the number of compilation jobs when System.h changes from
about 750 to 60. (There are still a large number of linker jobs.)
2025-12-04 15:40:46 +00:00
Andreas Kling
94fc8c47c0 LibIPC: Decode Vector<T> in one swoop for trivial arithmetic types
This avoids having the CPU churn through the vector one little integer
at a time.
2025-12-01 15:12:52 +01:00
Andreas Kling
096eddfd5a LibIPC: Encode spans of trivial arithmetic types more efficiently
For stuff like Span<u8>, we should obviously grow the message buffer
once, and then copy all the bytes in one go.
2025-12-01 15:12:52 +01:00
Aliaksandr Kalenik
b5db79be6d LibIPC: Change TransportSocket to read and write on I/O thread
Previously, TransportSocket sent queued messages from a separate thread
but performed all reading on the main thread. With this change, both
reading and writing are handled on the same I/O thread. This would allow
us to read IPC messages even while the main thread is blocked and
process them on a different thread (e.g., a rendering thread).
2025-11-02 22:43:10 +01:00
Aliaksandr Kalenik
509c86dca0 LibIPC: Simplify IPC read hook
- Return `PeerEOF` enum instead of `Error` containing string from
  `drain_messages_from_peer()`. There are no other error types to return
  from this function, so boolean-like enum is sufficient.
- Don't override read hook in `ConnectionFromClient` constructor. It was
  previously redefined only to suppress EOF error returned by
  `drain_messages_from_peer()`.
2025-10-21 09:31:22 +02:00
Rocco Corsi
b6b56910e8 LibIPC: Shutdown IPC handler when transport is lost during sync event
If the Ladybird process crashes or just ends normally, the IPC transport
connection with WebContent may be shutdown after a send sync event (for
example: WebContentClient DidRequestCookie) was sent from WebContent,
but before the Ladybird process provided the matching sync event
response (for example: WebContentClient DidRequestCookieResponse). This
can lead to a runaway WebContent process if other IPC events (for
example: WebContentServer DidPaint, or SetSystemVisibilityState, or
MouseEvent, or CloseServer, etc...) are also queued when the IPC
connection is shutdown.

At the core of the issue is that the loop waiting for the matching
send sync response will prioritize waiting for the response and remain
spinning even if the IPC connection is reporting that it was shutdown,
but only if there happens to be other unrelated events received before
the IPC shutdown is detected. These unrelated events will not be
processed because the loop is stuck waiting for the response that due
to the Ladybird process having stopped, will never be sent.

Because the shutdown of the IPC connection is not handled when other
events happen to be also present, new events may be posted for transfer
by the WebContent process if the page is very active. If many new events
are posted this could lead to a slow or very quick memory leak in the
WebContent process due to the queue growing large, sometimes all the way
to total system memory exhaustion. If no events or only a few new events
are sent, then the leak may be hard to detect.

This PR fixes the faulty IPC shutdown handling by not getting stuck if
any messages are present in the receive queue. Before returning to the
caller any remaining messages will be immediately processed.
2025-10-07 17:04:32 -05:00
Aliaksandr Kalenik
93d7efa4c3 LibIPC: Delete unused code in Connection 2025-10-01 14:59:23 -04:00
Tomasz Strejczek
6fc4c544de LibIPC: Remove DateTime encoder/decoder
Remove LibCore::DateTime encoder/decoder as it is not longer needed.
2025-09-30 12:39:01 +02:00
Zaggy1024
2aaf53bd2c Everywhere: Use a forward declaration for pointers to Threading::Thread 2025-09-22 17:28:21 -05:00
Tete17
658477620a LibWeb/LibURL/LibIPC: Extend createObjectURL to also accept MediaSources
This required some changes in LibURL & LibIPC since it has its own
definition of an BlobURLEntry. For now, we don't have a concrete usage
of MediaSource in LibURL so it is defined as an empty struct.

This removes one FIXME in an idl file.
2025-08-19 23:50:38 +02:00
Jelle Raaijmakers
63119355e3 LibIPC: Do not try to send a response back if transport was closed
The local handling of some messages might cause the transport to get
closed. If that's the case, we shouldn't try to send back a response.

This fixes many of the "Trying to post_message during IPC shutdown"
errors I was seeing when terminating Ladybird or when abnormally exiting
from LibWeb tests.
2025-08-17 20:51:56 -04:00
Timothy Flynn
13ed6aba71 AK+LibIPC: Implement an encoder/decoder for UTF-16 strings 2025-08-02 10:10:14 -07:00
Timothy Flynn
fd6d868ae2 LibIPC: Add some type aliases and MessageBuffer helpers
To re-use some of these wordy types outside of LibIPC, let's add some
aliases.
2025-07-18 10:09:02 -04:00
ayeteadoe
25f5936dee CMake: Rename serenity_* helper functions/macros to ladybird_* 2025-07-03 23:19:41 +02:00
ayeteadoe
dbba6c0df9 LibWeb: Enable in Windows CI 2025-06-30 10:50:36 -06:00
Shannon Booth
38765fd617 LibURL: Use a nonce to distinguish opaque origins
Opaque origins are meant to be unique in terms of equality from
one another. Since this uniqueness needs to be across processes,
use a nonce to implement the uniqueness check.
2025-06-25 16:47:09 +01:00
stasoid
8af2a49b5c LibIPC: Make TransportSocketWindows responsible for reading entire
messages. Port of a371f84 to Windows.
2025-06-17 15:36:47 -06:00
stasoid
ccf303eefc LibIPC: Move AutoCloseFileDescriptor to its own header 2025-06-17 15:36:47 -06:00
Shannon Booth
e0d7278820 LibURL+LibWeb: Make URL::Origin default constructor private
Instead, porting over all users to use the newly created
Origin::create_opaque factory function. This also requires porting
over some users of Origin to avoid default construction.
2025-06-17 20:54:03 +02:00
rmg-x
a4d931d14a LibCore+LibIPC: Move various encode/decode specializations to LibIPC
This removes a dependency on LibIPC from LibCore.
2025-06-14 16:03:26 -04:00
rmg-x
18f28f398b LibCore+LibIPC: Remove badge on File::leak_fd
This removes a dependency on LibIPC from LibCore.
2025-06-14 16:03:26 -04:00
Andrew Kaster
8095663f86 LibIPC: Chunk sent file descriptors by MAX_TRANSFER_FDS
This limitation of the underlying Unix socket implementation can
cause IPC failures on pages with tons of images and network requests.

Modify the code called from TransportSocket's send thread to limit the
number of fds to MAX_TRANSFER_FDS, and ensure that we will keep sending
as long as we have either bytes or file descriptors to send.
2025-05-24 19:15:06 +03:00
Andrew Kaster
87fbfcadd1 LibIPC: Refactor message header encoding to use a helper method
Manually memcpying into a Vector in the body of post_message is
a bit much.
2025-05-24 19:15:06 +03:00
Timothy Flynn
36da270dbe LibIPC+LibWeb: Flush MessagePort messages before closing
The spec isn't super clear on what disentagling a MessagePort means. But
we are required to send all pending messages before closing the port.

This is a bit tricky because the transport socket performs writes on a
background thread. From the main thread, where the disentanglement will
occur, we don't really know the state of the write thread. So what we do
here is stop the background thread then flush all remaining data from
the main thread.
2025-05-21 06:54:44 -04:00
Timothy Flynn
8b3355ed0d LibIPC: Address a couple of clangd warnings in IPC::TransportSocket
* We need the full definition of IPC::File in the header.
* We need(ed) Core::System in the header. Move AutoCloseFileDescriptor's
  ctor and dtor out-of-line to avoid this.
2025-05-21 06:54:44 -04:00
Timothy Flynn
7280ed6312 Meta: Enforce newlines around namespaces
This has come up several times during code review, so let's just enforce
it using a new clang-format 20 option.
2025-05-14 02:01:59 -06:00