freebsd-nq/sys/xen/xenstore/xenstorevar.h
Roger Pau Monné 4e4e43dc9e xen: allow limiting the amount of duplicated pending xenstore watches
Xenstore watches received are queued in a list and processed in a
deferred thread. Such queuing was done without any checking, so a
guest could potentially trigger a resource starvation against the
FreeBSD kernel if such kernel is watching any user-controlled xenstore
path.

Allowing limiting the amount of pending events a watch can accumulate
to prevent a remote guest from triggering this resource starvation
issue.

For the PV device backends and frontends this limitation is only
applied to the other end /state node, which is limited to 1 pending
event, the rest of the watched paths can still have unlimited pending
watches because they are either local or controlled by a privileged
domain.

The xenstore user-space device gets special treatment as it's not
possible for the kernel to know whether the paths being watched by
user-space processes are controlled by a guest domain. For this reason
watches set by the xenstore user-space device are limited to 1000
pending events. Note this can be modified using the
max_pending_watch_events sysctl of the device.

This is XSA-349.

Sponsored by:	Citrix Systems R&D
MFC after:	3 days
2020-12-30 11:18:26 +01:00

380 lines
12 KiB
C

/******************************************************************************
* xenstorevar.h
*
* Method declarations and structures for accessing the XenStore.h
*
* Copyright (C) 2005 Rusty Russell, IBM Corporation
* Copyright (C) 2005 XenSource Ltd.
* Copyright (C) 2009,2010 Spectra Logic Corporation
*
* This file may be distributed separately from the Linux kernel, or
* incorporated into other software packages, subject to the following license:
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this source file (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* $FreeBSD$
*/
#ifndef _XEN_XENSTORE_XENSTOREVAR_H
#define _XEN_XENSTORE_XENSTOREVAR_H
#include <sys/queue.h>
#include <sys/bus.h>
#include <sys/eventhandler.h>
#include <sys/malloc.h>
#include <sys/sbuf.h>
#include <machine/stdarg.h>
#include <xen/xen-os.h>
#include <xen/interface/grant_table.h>
#include <xen/interface/io/xenbus.h>
#include <xen/interface/io/xs_wire.h>
#include "xenbus_if.h"
/* XenStore allocations including XenStore data returned to clients. */
MALLOC_DECLARE(M_XENSTORE);
struct xs_watch;
typedef void (xs_watch_cb_t)(struct xs_watch *, const char **vec,
unsigned int len);
/* Register callback to watch subtree (node) in the XenStore. */
struct xs_watch
{
LIST_ENTRY(xs_watch) list;
/* Path being watched. */
char *node;
/* Callback (executed in a process context with no locks held). */
xs_watch_cb_t *callback;
/* Callback client data untouched by the XenStore watch mechanism. */
uintptr_t callback_data;
/* Maximum number of pending watch events to be delivered. */
unsigned int max_pending;
/*
* Private counter used by xenstore to keep track of the pending
* watches. Protected by xs.watch_events_lock.
*/
unsigned int pending;
};
LIST_HEAD(xs_watch_list, xs_watch);
typedef int (*xs_event_handler_t)(void *);
struct xs_transaction
{
uint32_t id;
};
#define XST_NIL ((struct xs_transaction) { 0 })
/**
* Check if Xenstore is initialized.
*
* \return True if initialized, false otherwise.
*/
bool xs_initialized(void);
/**
* Return xenstore event channel port.
*
* \return event channel port.
*/
evtchn_port_t xs_evtchn(void);
/**
* Return xenstore page physical memory address.
*
* \return xenstore page physical address.
*/
vm_paddr_t xs_address(void);
/**
* Fetch the contents of a directory in the XenStore.
*
* \param t The XenStore transaction covering this request.
* \param dir The dirname of the path to read.
* \param node The basename of the path to read.
* \param num The returned number of directory entries.
* \param result An array of directory entry strings.
*
* \return On success, 0. Otherwise an errno value indicating the
* type of failure.
*
* \note The results buffer is malloced and should be free'd by the
* caller with 'free(*result, M_XENSTORE)'.
*/
int xs_directory(struct xs_transaction t, const char *dir,
const char *node, unsigned int *num, const char ***result);
/**
* Determine if a path exists in the XenStore.
*
* \param t The XenStore transaction covering this request.
* \param dir The dirname of the path to read.
* \param node The basename of the path to read.
*
* \retval 1 The path exists.
* \retval 0 The path does not exist or an error occurred attempting
* to make that determination.
*/
int xs_exists(struct xs_transaction t, const char *dir, const char *node);
/**
* Get the contents of a single "file". Returns the contents in
* *result which should be freed with free(*result, M_XENSTORE) after
* use. The length of the value in bytes is returned in *len.
*
* \param t The XenStore transaction covering this request.
* \param dir The dirname of the file to read.
* \param node The basename of the file to read.
* \param len The amount of data read.
* \param result The returned contents from this file.
*
* \return On success, 0. Otherwise an errno value indicating the
* type of failure.
*
* \note The results buffer is malloced and should be free'd by the
* caller with 'free(*result, M_XENSTORE)'.
*/
int xs_read(struct xs_transaction t, const char *dir,
const char *node, unsigned int *len, void **result);
/**
* Write to a single file.
*
* \param t The XenStore transaction covering this request.
* \param dir The dirname of the file to write.
* \param node The basename of the file to write.
* \param string The NUL terminated string of data to write.
*
* \return On success, 0. Otherwise an errno value indicating the
* type of failure.
*/
int xs_write(struct xs_transaction t, const char *dir,
const char *node, const char *string);
/**
* Create a new directory.
*
* \param t The XenStore transaction covering this request.
* \param dir The dirname of the directory to create.
* \param node The basename of the directory to create.
*
* \return On success, 0. Otherwise an errno value indicating the
* type of failure.
*/
int xs_mkdir(struct xs_transaction t, const char *dir,
const char *node);
/**
* Remove a file or directory (directories must be empty).
*
* \param t The XenStore transaction covering this request.
* \param dir The dirname of the directory to remove.
* \param node The basename of the directory to remove.
*
* \return On success, 0. Otherwise an errno value indicating the
* type of failure.
*/
int xs_rm(struct xs_transaction t, const char *dir, const char *node);
/**
* Destroy a tree of files rooted at dir/node.
*
* \param t The XenStore transaction covering this request.
* \param dir The dirname of the directory to remove.
* \param node The basename of the directory to remove.
*
* \return On success, 0. Otherwise an errno value indicating the
* type of failure.
*/
int xs_rm_tree(struct xs_transaction t, const char *dir,
const char *node);
/**
* Start a transaction.
*
* Changes by others will not be seen during the lifetime of this
* transaction, and changes will not be visible to others until it
* is committed (xs_transaction_end).
*
* \param t The returned transaction.
*
* \return On success, 0. Otherwise an errno value indicating the
* type of failure.
*/
int xs_transaction_start(struct xs_transaction *t);
/**
* End a transaction.
*
* \param t The transaction to end/commit.
* \param abort If non-zero, the transaction is discarded
* instead of committed.
*
* \return On success, 0. Otherwise an errno value indicating the
* type of failure.
*/
int xs_transaction_end(struct xs_transaction t, int abort);
/*
* Single file read and scanf parsing of the result.
*
* \param t The XenStore transaction covering this request.
* \param dir The dirname of the path to read.
* \param node The basename of the path to read.
* \param scancountp The number of input values assigned (i.e. the result
* of scanf).
* \param fmt Scanf format string followed by a variable number of
* scanf input arguments.
*
* \return On success, 0. Otherwise an errno value indicating the
* type of failure.
*/
int xs_scanf(struct xs_transaction t,
const char *dir, const char *node, int *scancountp, const char *fmt, ...)
__attribute__((format(scanf, 5, 6)));
/**
* Printf formatted write to a XenStore file.
*
* \param t The XenStore transaction covering this request.
* \param dir The dirname of the path to read.
* \param node The basename of the path to read.
* \param fmt Printf format string followed by a variable number of
* printf arguments.
*
* \return On success, 0. Otherwise an errno value indicating the
* type of write failure.
*/
int xs_printf(struct xs_transaction t, const char *dir,
const char *node, const char *fmt, ...)
__attribute__((format(printf, 4, 5)));
/**
* va_list version of xenbus_printf().
*
* \param t The XenStore transaction covering this request.
* \param dir The dirname of the path to read.
* \param node The basename of the path to read.
* \param fmt Printf format string.
* \param ap Va_list of printf arguments.
*
* \return On success, 0. Otherwise an errno value indicating the
* type of write failure.
*/
int xs_vprintf(struct xs_transaction t, const char *dir,
const char *node, const char *fmt, va_list ap);
/**
* Multi-file read within a single directory and scanf parsing of
* the results.
*
* \param t The XenStore transaction covering this request.
* \param dir The dirname of the paths to read.
* \param ... A variable number of argument triples specifying
* the file name, scanf-style format string, and
* output variable (pointer to storage of the results).
* The last triple in the call must be terminated
* will a final NULL argument. A NULL format string
* will cause the entire contents of the given file
* to be assigned as a NUL terminated, M_XENSTORE heap
* backed, string to the output parameter of that tuple.
*
* \return On success, 0. Otherwise an errno value indicating the
* type of read failure.
*
* Example:
* char protocol_abi[64];
* uint32_t ring_ref;
* char *dev_type;
* int error;
*
* error = xenbus_gather(XBT_NIL, xenbus_get_node(dev),
* "ring-ref", "%" PRIu32, &ring_ref,
* "protocol", "%63s", protocol_abi,
* "device-type", NULL, &dev_type,
* NULL);
*
* ...
*
* free(dev_type, M_XENSTORE);
*/
int xs_gather(struct xs_transaction t, const char *dir, ...);
/**
* Register a XenStore watch.
*
* XenStore watches allow a client to be notified via a callback (embedded
* within the watch object) of changes to an object in the XenStore.
*
* \param watch An xs_watch struct with it's node and callback fields
* properly initialized.
*
* \return On success, 0. Otherwise an errno value indicating the
* type of write failure. EEXIST errors from the XenStore
* are supressed, allowing multiple, physically different,
* xenbus_watch objects, to watch the same path in the XenStore.
*/
int xs_register_watch(struct xs_watch *watch);
/**
* Unregister a XenStore watch.
*
* \param watch An xs_watch object previously used in a successful call
* to xs_register_watch().
*
* The xs_watch object's node field is not altered by this call.
* It is the caller's responsibility to properly dispose of both the
* watch object and the data pointed to by watch->node.
*/
void xs_unregister_watch(struct xs_watch *watch);
/**
* Allocate and return an sbuf containing the XenStore path string
* <dir>/<name>. If name is the NUL string, the returned sbuf contains
* the path string <dir>.
*
* \param dir The NUL terminated directory prefix for new path.
* \param name The NUL terminated basename for the new path.
*
* \return A buffer containing the joined path.
*/
struct sbuf *xs_join(const char *, const char *);
/**
* Lock the xenstore request mutex.
*/
void xs_lock(void);
/**
* Unlock the xenstore request mutex.
*/
void xs_unlock(void);
#endif /* _XEN_XENSTORE_XENSTOREVAR_H */