blob: 3edafa22dda041c31f68a950ad2990252b668ac2 [file] [edit]
/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
*
* This file is part of PRoot.
*
* Copyright (C) 2014 STMicroelectronics
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
#ifndef EXTENSION_H
#define EXTENSION_H
#include <sys/queue.h> /* LIST_, */
#include <stdint.h> /* intptr_t, */
#include <stdbool.h> /* bool, */
#include "tracee/tracee.h"
#include "syscall/seccomp.h"
/* List of possible events. */
typedef enum {
/* A guest path passed as an argument of the current syscall
* is about to be translated: "(char *) data1" is the base for
* "(char *) data2" -- the guest path -- if this latter is
* relative. If the extension returns > 0, then PRoot skips
* its own handling. If the extension returns < 0, then PRoot
* reports this errno as-is. */
GUEST_PATH,
/* A canonicalized host path is being accessed during the
* translation of a guest path: "(char *) data1" is the
* canonicalized host path and "(bool) data2" is true if it is
* the final path. Note that several host paths are accessed
* for a given guest path since PRoot has to walk along all
* parent directories and symlinks in order to translate it.
* If the extension returns < 0, then PRoot reports this errno
* as-is. */
HOST_PATH,
/* The tracee enters a syscall, and PRoot hasn't do anything
* yet. If the extension returns > 0, then PRoot skips its
* own handling. If the extension returns < 0, then PRoot
* cancels the syscall and reports this errno to the
* tracee. */
SYSCALL_ENTER_START,
/* The tracee enters a syscall, and PRoot has already handled
* it: "(int) data1" is the current status, it is < 0 when
* something went wrong. If the extension returns < 0, then
* PRoot cancels the syscall and reports this errno to the
* tracee. */
SYSCALL_ENTER_END,
/* The tracee exits a syscall, and PRoot hasn't do anything
* yet. If the extension returns > 0, then PRoot skips its
* own handling. If the extension returns < 0, then PRoot
* reports this errno to the tracee. */
SYSCALL_EXIT_START,
/* The tracee exits a syscall, and PRoot has already handled
* it. If the extension returns < 0, then PRoot reports this
* errno to the tracee. */
SYSCALL_EXIT_END,
/* The tracee is stopped either because of a syscall or a
* signal: "(int) data1" is its new status as reported by
* waitpid(2). If the extension returns != 0, then PRoot
* skips its own handling. */
NEW_STATUS,
/* Ask how this extension is inheritable: "(Tracee *) data1"
* is the child tracee and "(bool) data2" is the clone(2)
* flags (CLONE_RECONF for sub-reconfiguration). The meaning
* of the returned value is:
*
* < 0 : not inheritable
* == 0 : inheritable + shared configuration.
* > 0 : inheritable + call INHERIT_CHILD. */
INHERIT_PARENT,
/* Control the inheritance: "(Extension *) data1" is the
* extension of the parent and "(word_t) data2" is the clone(2)
* flags (CLONE_RECONF for sub-reconfiguration). For instance
* the extension for the child could use a configuration
* different from the parent's configuration. */
INHERIT_CHILD,
/* The tracee enters a "chained" syscall, that is, an
* unrequested syscall inserted by PRoot after an actual
* syscall. If the extension returns < 0, then PRoot cancels
* the syscall and reports this errno to the tracee. */
SYSCALL_CHAINED_ENTER,
/* The tracee exists a "chained" syscall, that is, an
* unrequested syscall inserted by PRoot after an actual
* syscall. */
SYSCALL_CHAINED_EXIT,
/* Initialize the extension: "(const char *) data1" is its
* argument that was passed to the command-line interface. If
* the extension returns < 0, then PRoot removed it. */
INITIALIZATION,
/* The extension is not attached to its tracee anymore
* (destructor). */
REMOVED,
/* Print the current configuration of the extension. See
* print_config() as an example. */
PRINT_CONFIG,
/* Print the usage of the extension: "(bool) data1" is true
* for a detailed usage. See print_usage() as an example. */
PRINT_USAGE,
} ExtensionEvent;
#define CLONE_RECONF ((word_t) -1)
struct extension;
typedef int (*extension_callback_t)(struct extension *extension, ExtensionEvent event,
intptr_t data1, intptr_t data2);
typedef struct extension {
/* Function to be called when any event occured. */
extension_callback_t callback;
/* A chunk of memory allocated by any talloc functions.
* Mainly useful to store a configuration. */
TALLOC_CTX *config;
/* List of sysnum handled by this extension. */
const FilteredSysnum *filtered_sysnums;
/* Link to the next and previous extensions. Note the order
* is *never* garantee. */
LIST_ENTRY(extension) link;
} Extension;
typedef LIST_HEAD(extensions, extension) Extensions;
extern int initialize_extension(Tracee *tracee, extension_callback_t callback, const char *cli);
extern void inherit_extensions(Tracee *child, Tracee *parent, word_t clone_flags);
/**
* Notify all extensions of @tracee that the given @event occured.
* See ExtensionEvent for the meaning of @data1 and @data2.
*/
static inline int notify_extensions(Tracee *tracee, ExtensionEvent event,
intptr_t data1, intptr_t data2)
{
Extension *extension;
if (tracee->extensions == NULL)
return 0;
LIST_FOREACH(extension, tracee->extensions, link) {
int status = extension->callback(extension, event, data1, data2);
if (status != 0)
return status;
}
return 0;
}
/* Built-in extensions. */
extern int kompat_callback(Extension *extension, ExtensionEvent event, intptr_t d1, intptr_t d2);
extern int fake_id0_callback(Extension *extension, ExtensionEvent event, intptr_t d1, intptr_t d2);
extern int care_callback(Extension *extension, ExtensionEvent event, intptr_t d1, intptr_t d2);
#endif /* EXTENSION_H */