capsule

capsule

Synopsis

struct              capsule;
typedef             capsule_addr;
void                capsule_close                       (capsule cap);
void *              capsule_external_dlopen             (const char *file,
                                                         int flag);
void *              capsule_external_dlsym              (void *handle,
                                                         const char *symbol);
char *              capsule_get_prefix                  (const char *dflt,
                                                         const char *soname);
capsule             capsule_init                        (const char *soname);
struct              capsule_item;
struct              capsule_metadata;
return              capsule_shim_dlopen                 (cap Param1,
                                                         filename Param2,
                                                         flag Param3);
void                capsule_shim_free                   (const capsule cap,
                                                         void *ptr);
return              capsule_shim_realloc                (cap Param1,
                                                         ptr Param2,
                                                         size Param3);

Description

Details

struct capsule

struct capsule {
    void  *dl_handle;
    struct { ptr_list *all; ptr_list *some; } seen;
    capsule_metadata *meta;
    capsule_namespace *ns;
    capsule_item internal_wrappers[7];
};

A handle returned by capsule_init: A required parameter for all other capsule calls.


capsule_addr

typedef ElfW(Addr) capsule_addr;

Identical to an ElfW(Addr) from libelf. You may treat this as equivalent to a void * when assigning to it.


capsule_close ()

void                capsule_close                       (capsule cap);

This function should be called from a capsule proxy library’s destructor: Its job is to clean up capsule-specific allocated memory and metadata when a capsule proxy is discarded via dlclose(), and ensure that libproxy itself won’t try to access any related invalidated memory afterwards.

cap :

a capsule handle as returned by capsule_init()

capsule_external_dlopen ()

void *              capsule_external_dlopen             (const char *file,
                                                         int flag);

An implementation of `dlopen`, used when it is called by the executable or by a library outside the capsule.

This wrapper is meant to be replace normal calls to dlopen() made by the main program or a non-capsule library - it is necessary because en ELF object loaded by dlopen() may need us to trigger the _capsule_relocate() operation in order to make sure its GOT entries are correctly updated.

This wrapper carries out a normal dlopen() and then re-triggers the initial _capsule_relocate() call immediately, before returning the same value that dlopen() would have, given the same file and flag arguments.

file :

A soname, filename or path as passed to dlopen()

flag :

The dl flags, as per dlopen()

Returns :

The handle returned by `dlopen`

capsule_external_dlsym ()

void *              capsule_external_dlsym              (void *handle,
                                                         const char *symbol);

An implementation of `dlsym`, used when it is called by the executable or by a library outside the capsule.

Some libraries have a use pattern in which their caller/user uses dlsym() to obtain symbols rather than using those symbols directly in its own code (libGL is an example of this).

Since the target library may have a different symbol set than the one the libcapsule proxy shim was generated from we can’t rely on dlsym() finding those symbols in the shim’s symbol table.

Instead we must intercept dlsym() calls made outside the capsule and attempt to look for the required symbol in the namespace defined by the active capsules first - If the required symbol is found there AND is from one of the DSO names present in the exported list then that symbol is returned. If either of those conditions is not met then a normal dlsym call with the passed handle is made.

This function provides the functionality described above, and is normally used automatically by libcapsule. It is exposed as API in case a libcapsule proxy library needs to provide its own specialised symbol lookup mechanism.

handle :

A dl handle, as passed to dlsym()

symbol :

A symbol name, as passed to dlsym()

Returns :

The address associated with symbol (as if for `dlsym`), or NULL

capsule_get_prefix ()

char *              capsule_get_prefix                  (const char *dflt,
                                                         const char *soname);

dflt :

A default capsule prefix path

soname :

The soname of the library we are encapsulating

Returns :

A newly allocated char * pointing to the prefix path libcapsule provides a proxy to a library, potentially from a foreign filesystem tree (found at, for example, ‘/host’). Since it is useful for this location to be overrideable at startup on a per-target-library basis this function standardises the prefix selection algorithm as follows: - An environment variable based on soname: libGL.so.1 would map to CAPSULE_LIBGL_SO_1_PREFIX - If that is unset, the CAPSULE_PREFIX environment variable - Next: The default to the value passed in dflt - And if all that failed, NULL (which is internally equivalent to "/") The environment variables are ignored if the process is privileged (setuid, setgid, given special capabilities, or marked as privileged by a LSM), or if libcapsule was compiled against a glibc version older than 2.17. Although the value is newly allocated it will typically be cached in a structure that needs to survive the entire lifespan of the running program, so freeing it is unlikely to be a concern.

capsule_init ()

capsule             capsule_init                        (const char *soname);

soname :

the soname of the target library

Returns :

a capsule handle. Does any initialisation necessary to use libcapsule’s functions. Initialises internal accounting structures within the capsule and triggers the metadata setup if this caspsule has been acquired via dlopen(), and finishes registering the capsule proxy with libcapsule itself.

struct capsule_item

struct capsule_item {
    const char *name;
    capsule_addr real;
    capsule_addr shim;
};

real and shim may typically be left empty by the shim library.

Both slots will typically hold the correct values after a successful capsule… call. While this is sometimes important internally it is not usually of interest to the caller (except maybe for debugging)

const char *name;

The name of the symbol to be relocated

capsule_addr real;

address of the ‘real’ symbol in the target library

capsule_addr shim;

address of the ‘fake’ symbol in the proxy library

struct capsule_metadata

struct capsule_metadata {
    const int     capsule_abi;
    const char   *soname;
    const char   *default_prefix;
    const char  **exclude;
    const char  **export;
    capsule_item *items;
    void *(*int_dlopen) (const char *filename, int flag);
    void  (*int_free) (void *ptr);
    void *(*int_realloc) (void *ptr, size_t size);
};

This struct allows libcapsule proxy libraries to statically declare metadata about themselves that libcapsule needs at link time in order to function properly.

The capsule_item entries in items need only specify the symbol name: The shim and real fields will be populated automatically if they are not pre-filled (this is the normal use case, as it would be unusual to know these value in advance).

const int capsule_abi;

Version of the libcapsule ABI implmented by this struct

const char *soname;

The soname of the encapsulated library

const char *default_prefix;

The default root location of the filesystem from which the encapsulated library should be loaded

const char **exclude;

an array of char *, each specifying a DSO not to load, terminated by a NULL entry. [array zero-terminated=1]

const char **export;

an array of char *, each specifying a DSO whose symbols should be exported from this capsule. [array zero-terminated=1]

capsule_item *items;

Array of capsule_item specifying which symbols to export, terminated by a capsule_item whose name is NULL. [array zero-terminated=1]

int_dlopen ()

Implementation of the same API as `dlopen`

int_free ()

int_realloc ()


capsule_shim_dlopen ()

return              capsule_shim_dlopen                 (cap Param1,
                                                         filename Param2,
                                                         flag Param3);

capsule_shim_free ()

void                capsule_shim_free                   (const capsule cap,
                                                         void *ptr);

Tries to safely route an allocated pointer to the correct free() implementation.

cap :

The capsule from which `free` was called

ptr :

The pointer to be freed

capsule_shim_realloc ()

return              capsule_shim_realloc                (cap Param1,
                                                         ptr Param2,
                                                         size Param3);