ELF Runner

The ELF runner is the runner responsible for launching components based on standard executable files (ELF format). It is a built-in runner and is available to all components.

Using the ELF Runner

To use the ELF runner, the component's manifest must include a program block, containing:

{
    program: {
        runner: "elf",
        binary: "bin/foo",
    }
}

  • The runner field with the value set to the string elf.
  • The binary field with the value set to a binary output name in the component's package.

Fields

Additionally, the ELF runner accepts a set of optional fields to configure the ELF component's runtime environment.

Arguments

Arguments (that is, argv in most programming languages) can be passed to a component's process using the args field. This field accepts a vector of strings (see the example below). The arguments set will be passed in the same order as declared in the manifest.

{
    program: {
        runner: "elf",
        binary: "bin/foo",
        args: ["--verbose", "--debug"]
    }
}

Forwarding stdout and stderr streams

The stdout and stderr streams of ELF components can be routed to the LogSink service. By default, the ELF runner only forwards these streams if LogSink is available to the component. If your component prints diagnostics messages to either of these streams, you should forward the streams to the LogSink service.

To enable this feature, add the following to your manifest file:

{
    include: [ "syslog/client.shard.cml" ],
}

After including this shard, all writes to stdout are logged as INFO messages, and all writes to stderr are logged as WARN messages. Messages are split by newlines and decoded as UTF-8 strings. Invalid byte sequences are converted to the U+FFFD replacement character, which usually looks like .

Whether or not the syslog shard is included, this feature can be disabled with explicit flags:

    program: {
        runner: "elf",
        binary: "bin/foo",
        forward_stdout_to: "none",
        forward_stderr_to: "none",
    }

Lifecycle

Components have a lifecycle. Components run by the ELF runner can integrate with the lifecycle if you add a lifecycle attribute to your component manifest. Currently stop is the only method in the Lifecycle protocol.

{
    program: {
        runner: "elf",
        binary: "bin/foo",
        lifecycle: { stop_event: "notify" },
    }
}

The program should take the handle to the Lifecycle channel and serve the Lifecycle protocol on that channel. The component should exit after receiving and processing the stop call.

The ELF Runner monitors the process it started for the program binary of the component. If this process exits, the ELF runner will terminate the component's execution context, which includes the component's job and all subprocesses.

Security

There are several privileged fields that are gated by an allowlist. Only components included in this allowlist are able to use these fields. For all fields, the policy applies to the first process in the component. The first process is the one created by ELF runner for the binary declared in program block. All of the fields are booleans that default to false.

Main Process Critical

The main_process_critical field may be used to mark the component's first process as critical to component manager's job, which will cause component manager (and all components) to be terminated if the process exits with a non-zero code. This will force the system to trigger a hard reboot.

Ambient VMO Exec

The ambient_mark_vmo_exec field may be used to allow the component's first process to use zx_vmo_replace_as_executable with a ZX_HANDLE_INVALID as the second argument rather than a valid ZX_RSRC_KIND_SYSTEM with base ZX_RSRC_SYSTEM_VMEX_BASE.

Create Raw Processes

The job_policy_create_raw_processes field may be used to allow a component to create processes by using zx_process_create.

{
    program: {
        runner: "elf",
        binary: "bin/foo",
        job_policy_create_raw_processes: "true"
    }
}

Is Shared Process

The is_shared_process field may be used to pass the ZX_PROCESS_SHARED flag when calling zx_process_create. This flag can only be used if the component also has job_policy_create_raw_processes set to true.

{
    program: {
        runner: "elf",
        binary: "bin/foo",
        job_policy_create_raw_processes: "true",
        is_shared_process: "true"
    }
}

Job with available exception channel

The job_with_available_exception_channel field may be used to make sure the component is created as a direct descendent of a job that will have its exception channel available for taking.

{
    program: {
        runner: "elf",
        binary: "bin/foo",
        job_with_available_exception_channel: "true"
    }
}

Further Reading

For a detailed explanation of how processes are created, please see Zircon program loading and dynamic linking.

Environment Variables

Environment variables can be set for ELF components by using the environ attribute. This field must be a vector of strings where each string contains the variable and value delimited by an equal sign. For example, the following sample code declares variables FAVORITE_ANIMAL and FAVORITE_COLOR to cat and red.

{
    program: {
        runner: "elf",
        binary: "bin/echo",
        environ: [
            "FAVORITE_ANIMAL=cat",
            "FAVORITE_COLOR=red",
        ]
    }
}