Backend API

Header: zbc_backend.h

Backends provide the actual implementation of semihosting operations (file I/O, console, time). The host library dispatches requests to a backend vtable.

Backend Vtable

type zbc_backend_t

Backend vtable defining semihosting operations.

Implement the functions you need, set unused operations to NULL. The host library returns an error to the guest for any NULL operation.

Return value conventions: - open: file descriptor (>=0) on success, -1 on error - close, seek, remove, rename: 0 on success, -1 on error - read, write: bytes NOT transferred (0 = complete), -1 on error - flen: file length on success, -1 on error - clock: centiseconds since start, -1 on error - time: seconds since epoch, -1 on error - tmpnam: 0 on success (fills buf), -1 on error

Return Value Conventions

Operation

Success

Error

open

file descriptor (>=0)

-1

close, seek, remove, rename

0

-1

read, write

bytes NOT transferred (0 = complete)

-1

flen

file length

-1

clock

centiseconds since start

-1

time

seconds since epoch

-1

tmpnam

0 (fills buf)

-1

Set unused operations to NULL. The host library returns an error to the guest for any NULL operation.

Built-in Backends

Secure ANSI Backend

const zbc_backend_t *zbc_backend_ansi(void)

Get the secure (sandboxed) ANSI backend.

The secure backend restricts file access to a sandbox directory. Guest code cannot escape the sandbox or access arbitrary host files. Use with zbc_ansi_state_t from zbc_backend_ansi.h.

zbc_ansi_init

Returns:

Pointer to backend vtable

State initialization (from zbc_backend_ansi.h):

#include "zbc_backend_ansi.h"

static zbc_ansi_state_t state;

zbc_ansi_init(&state, "/path/to/sandbox/");

Configuration:

/* Add additional allowed paths */
zbc_ansi_add_path(&state, "/usr/share/data/", 0);  /* read-only */
zbc_ansi_add_path(&state, "/tmp/output/", 1);      /* read-write */

/* Set flags */
state.flags |= ZBC_ANSI_FLAG_ALLOW_SYSTEM;  /* enable system() */
state.flags |= ZBC_ANSI_FLAG_READ_ONLY;     /* block all writes */

/* Set callbacks for violations, exit, and timer config */
zbc_ansi_set_callbacks(&state, violation_handler, exit_handler,
                       timer_handler, ctx);

Cleanup:

zbc_ansi_cleanup(&state);

Insecure ANSI Backend

const zbc_backend_t *zbc_backend_ansi_insecure(void)

Get the insecure (unrestricted) ANSI backend.

The insecure backend provides unrestricted access to the host filesystem. Guest code can read, write, and delete any file the host process can access. Use only for trusted code. Use with zbc_ansi_insecure_state_t from zbc_backend_ansi.h.

zbc_ansi_insecure_init

Returns:

Pointer to backend vtable

Use only for trusted code (e.g., your own test programs).

State initialization (from zbc_backend_ansi.h):

#include "zbc_backend_ansi.h"

static zbc_ansi_insecure_state_t state;

zbc_ansi_insecure_init(&state);

Cleanup:

zbc_ansi_insecure_cleanup(&state);

Dummy Backend

const zbc_backend_t *zbc_backend_dummy(void)

Get the dummy (no-op) backend.

All operations succeed with no side effects. Useful for testing the host processing logic without actual I/O. No state required – pass NULL as backend_ctx.

Returns:

Pointer to backend vtable

Implementing Custom Backends

To implement a custom backend:

  1. Define your context structure (if needed)

  2. Implement the vtable functions you need

  3. Create a static zbc_backend_t with your function pointers

  4. Use NULL for operations you don’t support

Example:

typedef struct {
    int console_fd;
    /* ... */
} my_backend_ctx_t;

static int my_open(void *ctx, const char *path, size_t len, int mode)
{
    my_backend_ctx_t *my = ctx;
    /* Implementation */
    return fd;
}

static void my_writec(void *ctx, char c)
{
    my_backend_ctx_t *my = ctx;
    write(my->console_fd, &c, 1);
}

static const zbc_backend_t my_backend = {
    .open = my_open,
    .writec = my_writec,
    /* Other operations NULL - returns error to guest */
};

/* Usage */
my_backend_ctx_t my_ctx = { .console_fd = STDOUT_FILENO };
zbc_host_init(&host, &mem_ops, NULL, &my_backend, &my_ctx,
              work_buf, sizeof(work_buf));

ANSI Backend Types

Header: zbc_backend_ansi.h

Secure Backend State

type zbc_ansi_state_t

Secure ANSI backend state (caller-allocated).

Initialize with zbc_ansi_init() before use.

void zbc_ansi_init(zbc_ansi_state_t *state, const char *sandbox_dir)

Initialize secure ANSI backend.

The sandbox_dir is copied into state, so the original can be freed.

Parameters:
  • state – Caller-allocated state structure

  • sandbox_dir – Directory to sandbox file operations to (required). All file paths must start with this prefix. Should end with ‘/’ (will be added if missing).

int zbc_ansi_add_path(zbc_ansi_state_t *state, const char *prefix, int allow_write)

Add an additional allowed path.

The prefix string must remain valid for the lifetime of state.

Parameters:
  • state – Initialized state

  • prefix – Path prefix to allow (e.g., “/usr/lib/”)

  • allow_write – 0 for read-only, 1 for read-write

Returns:

0 on success, -1 if path_rules array is full

void zbc_ansi_set_policy(zbc_ansi_state_t *state, const zbc_ansi_policy_t *policy, void *ctx)

Set custom security policy.

Parameters:
  • state – Initialized state

  • policy – Policy vtable (NULL to use built-in)

  • ctx – Context passed to policy callbacks

void zbc_ansi_set_callbacks(zbc_ansi_state_t *state, void (*on_violation)(void*, int, const char*), void (*on_exit)(void*, unsigned int, unsigned int), void (*on_timer_config)(void*, unsigned int), void *ctx)

Set callbacks for security events.

Parameters:
  • state – Initialized state

  • on_violation – Called when operation is blocked (may be NULL)

  • on_exit – Called when exit() is intercepted (may be NULL)

  • on_timer_config – Called when timer is configured (may be NULL)

  • ctx – Context passed to callbacks

void zbc_ansi_cleanup(zbc_ansi_state_t *state)

Clean up secure ANSI backend state.

Closes all open files. State can be reused after calling zbc_ansi_init().

Parameters:
  • state – Initialized state

Insecure Backend State

type zbc_ansi_insecure_state_t

Insecure ANSI backend state (caller-allocated).

Initialize with zbc_ansi_insecure_init() before use.

void zbc_ansi_insecure_init(zbc_ansi_insecure_state_t *state)

Initialize insecure ANSI backend.

This provides unrestricted filesystem access! Guest code can read/write/delete any file the host process can access. Only use for trusted guest code or debugging.

Parameters:
  • state – Caller-allocated state structure

void zbc_ansi_insecure_cleanup(zbc_ansi_insecure_state_t *state)

Clean up insecure ANSI backend state.

Closes all open files. State can be reused after calling zbc_ansi_insecure_init().

Parameters:
  • state – Initialized state

Policy Vtable

type zbc_ansi_policy_t

Custom policy vtable (optional, for OS-specific sandboxing).