Life of a handle in FIDL
This page gives a step-by-step explanation of how FIDL transfers a [Zircon handle] from one process to another. In particular, it focuses on the various meanings of "handle rights" and how handle rights are validated.
Scenario
Consider a simple client and server communicating over the following protocol:
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples.docs/life_of_a_handle.test.fidl" region_tag="protocol" %}
Suppose that we remove zx.rights.WRITE from the handle rights, but only
recompile the server, not the client. What happens when the client creates a VMO
and passes it to Method?
Diagram
In this scenario, the client is acting as sender and the server is acting as receiver. We use those terms below because this is what matters for the purposes of transferring handles. If the method returned a handle, then the same steps would apply with the roles reversed.
See below for a detailed explanation of the diagram.
Explanation {#explanation}
-
User code (sender)
- Assume the sender obtains the VMO using the [
zx_vmo_create] syscall. The returned handleh1has default rights for a VMO:DUPLICATE,TRANSFER,READ,WRITE,MAP,GET_PROPERTY, andSET_PROPERTY. - Call
Method, passingh1to it.
- Assume the sender obtains the VMO using the [
-
FIDL bindings (sender)
- Wrap
h1in a handle disposition specifying the rights from the FIDL type:MAP,READ, andWRITE. This tells the kernel what rights to provide when transferringh1. The bindings don't know what rightsh1actually has. (They don't know for sure that it references a VMO either, but unlike rights this is usually represented in the static type system, making it hard to pass the wrong handle type by accident.)
zx_handle_disposition{ .operation = ZX_HANDLE_OP_MOVE, .handle = h1, .type = ZX_OBJ_TYPE_VMO, .rights = ZX_RIGHT_MAP | ZX_RIGHT_READ | ZX_RIGHT_WRITE, }- Invoke the [
zx_channel_write_etc] syscall (or similar).
- Wrap
-
Kernel
- Ensure that
h1exists in the sender process's handle table. - Ensure that
h1refers to a VMO. - Ensure that
h1has (at least) the rightsMAP,READ, andWRITE. - Restrict the rights to only include
MAP,READ, andWRITE, removing the rightsDUPLICATE,TRANSFER,GET_PROPERTY, andSET_PROPERTY. We'll refer to this restricted handle ash2. This is equivalent to invoking the [zx_handle_replace] syscall. - Enqueue the message with
h2instead ofh1.
- Ensure that
-
FIDL bindings (receiver)
- Invoke the [
zx_channel_read_etc] syscall (or similar). - Unwrap
h2from the returned handle info. Unlike the handle disposition, the handle info stores the handle's actual type and rights as reported by the kernel.
zx_handle_info{ .handle = h2, .type = ZX_OBJ_TYPE_VMO, .rights = ZX_RIGHT_MAP | ZX_RIGHT_READ | ZX_RIGHT_WRITE, }- Get the expected type and rights from the FIDL type:
MAPandREAD. - Ensure that
h2has (at least) those rights. - Since
h2has the unexpected rightWRITE, invoke the [zx_handle_replace] syscall to get a new handleh3that only has the rightsMAPandREAD.
- Invoke the [
-
User code (receiver)
- Service
Methodusing thehargument, which ish3.
- Service
zx_channel_read_etczx_channel_write_etczx_handle_replacezx_vmo_createZircon handle