Chrome IPC Internals – Part I

Chrome IPC mechanism has provided software developers to split the code with different trust level into two different levels. In this way we can easily draw a boundary between codes with different trust levels. There are few links that explains about the implementation details. First link is the design document of this IPC mechanism and following two links talk about the implementation for chrome.

http://www.chromium.org/developers/design-documents/inter-process-communication
http://blog.azimuthsecurity.com/2010/05/chrome-sandbox-part-1-of-3-overview.html
http://blog.azimuthsecurity.com/2010/08/chrome-sandbox-part-2-of-3-ipc.html

Some more points from the above links and source code:

1. Main Interprocess Communication mechanism:

PIPE
Socketpair (POSIX)

2. A named pipe is allocated for each renderer process for communication with the browser process (chrome browser).

3. Channels on windows are named by default and accessible from other processes. Channels on POSIX are anonymous by default and not accessible from other processes. Named channels work via named UNIX domain sockets.

4. IPC::ChannelProxy is useful when you wish to run an IPC Channel on a background thread.

5. An IPC::ChannelProxy can have a IPC:: ChannelProxy::MessageFilter associated with it, which will be notified of incoming messages on the IPC::Channel’s thread.

6. IPC:Channel handles the communication between client and server.

7. IPC::Message handles the message part.

8. IPC::Listener listens for events on the channel. There are three kinds of events we can expect from IPC::Channel::ChannelImpl and IPC::internal::ChannelReader.

a. OnMessageReceived() -> When a message is received.

b. OnChannelConnected() -> When the channel is connected.

c. OnChannelError() -> When an error is detected that causes the channel to close.

9. IPC:Sender is a pure virtual class with just a single function Send().

10. IPC:Channel has a member of type IPC::Channel::ChannelImpl for communicating with the platform. We need to rewrite the IPC::Channel::ChannelImpl for each and every platform we support.

a. ipc_channel_win.h/.cc -> Windows Platform

b. ipc_channel_posix.h/.cc -> UNIX Platform

c. ipc_channel_nacl.h/.cc -> NACL

11. In windows, IPC::Channel::ChannelImpl is implemented using named pipes.

12. In POSIX, IPC::Channel::ChannelImpl is implemented using socketpair() or UNIX domain sockets.

13. Most of the calls to IPC:Channel is forwarded to IPC::Channel::ChannelImpl.

14. IPC::Channel::ChannelImpl is inheriting from IPC:: internal::ChannelReader and base::MessagePumpForIO::IOHandler.

15. IPC:: internal::ChannelReader with the help of base::MessagePumpForIO::IOHandler reads the data(in OVERLAPPED mode) and pass that to the IPC::Listener.

16. We use base::MessagePumpForIO::IOHandler for asynchronous read operation from the channel.

17. IPC::MessageIterator class is used for reading the fields contained within a message.

18. By default, Chrome IPC (in windows) creates a PIPE with the name “\\.\pipe\chrome.” Appended with the name of the channel handle.

19. A client can be validated using a shared “secret”. In that case, when you create a channel you need to pass a name like “NAME\SECRET”. This “SECRET” value should fit into 32-bit value. Client needs to send this SECRET in the HELLO Message in-order for connection to succeed.

When you create a channel with shared SECRET, a PIPE (in windows) is created with the name “\\.\pipe\chrome.NAME”

20. IPC::Message inherits from base::Pickle. base::Pickle provides facilities for basic binary value packing and unpacking.

21. Each Message has a header defined in IPC::Message::Header. IPC::Message::Header inherited from base::Pickle::Header.

22. IPC::Message::Header follows this format.

                              clip_image002

           The payload follows this header of size “payload_size”.

23. In a single read, we may receive multiple Message’s. “payload_size” field is used to iterate over the messages.

24. Each and every message has a priority associated with it.

PRIORITY_LOW

PRIORITY_NORMAL

PRIORITY_HIGH

25. First Message from both the end should be a Message with

type == Channel::HELLO_MESSAGE_TYPE and routingID == MSG_ROUTING_NONE

26. In the Channel::HELLO_MESSAGE_TYPE Message, we just send the PID of the process connecting too. If we have enabled client validation then we will send the shared secret too.

27. Once we have seen the HELLO message then we will call OnChannelConnected() of Listener.

28. For each and every other non-HELLO Message , we will call Listener’s OnMessageReceived() function.

29. In the end, when the connection is closed, we will call Listener’s OnChannelError().

30. In the Listener’s OnMessageReceived(), you can use IPC_BEGIN_MESSAGE_MAP()/IPC_MESSAGE_HANDLER()/IPC_END_MESSAGE_MAP() to create a different callback for each and every message Type.

31. IPC_BEGIN_MESSAGE_MAP()/IPC_MESSAGE_HANDLER()/IPC_END_MESSAGE_MAP() creates a switch case internally to handle various message types.

Advertisements
This entry was posted in Chrome, Cr-48, Internals and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s