API: add VIR_TYPED_PARAM_STRING

This allows strings to be transported between client and server
in the context of name-type-value virTypedParameter functions.
For compatibility,

    o new clients will not send strings to old servers, based on
      a feature check
    o new servers will not send strings to old clients without the
      flag VIR_TYPED_PARAM_STRING_OKAY; this will be enforced at
      the RPC layer in the next patch, so that drivers need not
      worry about it in general.  The one exception is that
      virDomainGetSchedulerParameters lacks a flags argument, so
      it must not return a string; drivers that forward that
      function on to virDomainGetSchedulerParametersFlags will
      have to pay attention to the flag.
    o the flag VIR_TYPED_PARAM_STRING_OKAY is set automatically,
      based on a feature check (so far, no driver implements it),
      so clients do not have to worry about it

Future patches can then enable the feature on a per-driver basis.

This patch also ensures that drivers can blindly strdup() field
names (previously, a malicious client could stuff 80 non-NUL bytes
into field and cause a read overrun).

* src/libvirt_internal.h (VIR_DRV_FEATURE_TYPED_PARAM_STRING): New
driver feature.
* src/libvirt.c (virTypedParameterValidateSet)
(virTypedParameterSanitizeGet): New helper functions.
(virDomainSetMemoryParameters, virDomainSetBlkioParameters)
(virDomainSetSchedulerParameters)
(virDomainSetSchedulerParametersFlags)
(virDomainGetMemoryParameters, virDomainGetBlkioParameters)
(virDomainGetSchedulerParameters)
(virDomainGetSchedulerParametersFlags, virDomainBlockStatsFlags):
Use them.
* src/util/util.h (virTypedParameterArrayClear): New helper
function.
* src/util/util.c (virTypedParameterArrayClear): Implement it.
* src/libvirt_private.syms (util.h): Export it.
Based on an initial patch by Hu Tao, with feedback from
Daniel P. Berrange.

Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
Eric Blake 2011-10-12 17:26:34 +08:00
parent 329b2b2819
commit a218c81da2
6 changed files with 136 additions and 18 deletions

View File

@ -200,11 +200,14 @@ typedef virDomainControlInfo *virDomainControlInfoPtr;
* current domain state. VIR_DOMAIN_AFFECT_LIVE requires a running
* domain, and VIR_DOMAIN_AFFECT_CONFIG requires a persistent domain
* (whether or not it is running).
*
* These enums should not conflict with those of virTypedParameterFlags.
*/
typedef enum {
VIR_DOMAIN_AFFECT_CURRENT = 0, /* Affect current domain state. */
VIR_DOMAIN_AFFECT_LIVE = 1 << 0, /* Affect running domain state. */
VIR_DOMAIN_AFFECT_CONFIG = 1 << 1, /* Affect persistent domain state. */
/* 1 << 2 is reserved for virTypedParameterFlags */
} virDomainModificationImpact;
/**
@ -489,9 +492,35 @@ typedef enum {
VIR_TYPED_PARAM_LLONG = 3, /* long long case */
VIR_TYPED_PARAM_ULLONG = 4, /* unsigned long long case */
VIR_TYPED_PARAM_DOUBLE = 5, /* double case */
VIR_TYPED_PARAM_BOOLEAN = 6 /* boolean(character) case */
VIR_TYPED_PARAM_BOOLEAN = 6, /* boolean(character) case */
VIR_TYPED_PARAM_STRING = 7, /* string case */
} virTypedParameterType;
/**
* virTypedParameterFlags:
*
* Flags related to libvirt APIs that use virTypedParameter.
*
* These enums should not conflict with those of virDomainModificationImpact.
*/
typedef enum {
/* 1 << 0 is reserved for virDomainModificationImpact */
/* 1 << 1 is reserved for virDomainModificationImpact */
/* Older servers lacked the ability to handle string typed
* parameters. Attempts to set a string parameter with an older
* server will fail at the client, but attempts to retrieve
* parameters must not return strings from a new server to an
* older client, so this flag exists to identify newer clients to
* newer servers. This flag is automatically set when needed, so
* the user does not have to worry about it; however, manually
* setting the flag can be used to reject servers that cannot
* return typed strings, even if no strings would be returned.
*/
VIR_TYPED_PARAM_STRING_OKAY = 1 << 2,
} virTypedParameterFlags;
/**
* VIR_TYPED_PARAM_FIELD_LENGTH:
*
@ -520,6 +549,7 @@ struct _virTypedParameter {
unsigned long long int ul; /* type is ULLONG */
double d; /* type is DOUBLE */
char b; /* type is BOOLEAN */
char *s; /* type is STRING, may not be NULL */
} value; /* parameter value */
};

View File

@ -3583,6 +3583,50 @@ error:
return -1;
}
/* Helper function called to validate incoming client array on any
* interface that sets typed parameters in the hypervisor. */
static int
virTypedParameterValidateSet(virDomainPtr domain,
virTypedParameterPtr params,
int nparams)
{
bool string_okay;
int i;
string_okay = VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver,
domain->conn,
VIR_DRV_FEATURE_TYPED_PARAM_STRING);
for (i = 0; i < nparams; i++) {
if (strnlen(params[i].field, VIR_TYPED_PARAM_FIELD_LENGTH) ==
VIR_TYPED_PARAM_FIELD_LENGTH) {
virLibDomainError(VIR_ERR_INVALID_ARG,
_("string parameter name '%.*s' too long"),
VIR_TYPED_PARAM_FIELD_LENGTH,
params[i].field);
virDispatchError(NULL);
return -1;
}
if (params[i].type == VIR_TYPED_PARAM_STRING) {
if (string_okay) {
if (!params[i].value.s) {
virLibDomainError(VIR_ERR_INVALID_ARG,
_("NULL string parameter '%s'"),
params[i].field);
virDispatchError(NULL);
return -1;
}
} else {
virLibDomainError(VIR_ERR_INVALID_ARG,
_("string parameter '%s' unsupported"),
params[i].field);
virDispatchError(NULL);
return -1;
}
}
}
return 0;
}
/**
* virDomainSetMemoryParameters:
* @domain: pointer to domain object
@ -3621,6 +3665,9 @@ virDomainSetMemoryParameters(virDomainPtr domain,
virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
goto error;
}
if (virTypedParameterValidateSet(domain, params, nparams) < 0)
return -1;
conn = domain->conn;
if (conn->driver->domainSetMemoryParameters) {
@ -3644,7 +3691,7 @@ error:
* @params: pointer to memory parameter object
* (return value, allocated by the caller)
* @nparams: pointer to number of memory parameters; input and output
* @flags: one of virDomainModificationImpact
* @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags
*
* Get all memory parameters. On input, @nparams gives the size of the
* @params array; on output, @nparams gives how many slots were filled
@ -3695,6 +3742,9 @@ virDomainGetMemoryParameters(virDomainPtr domain,
virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
goto error;
}
if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
VIR_DRV_FEATURE_TYPED_PARAM_STRING))
flags |= VIR_TYPED_PARAM_STRING_OKAY;
conn = domain->conn;
if (conn->driver->domainGetMemoryParameters) {
@ -3717,7 +3767,7 @@ error:
* @params: pointer to blkio parameter objects
* @nparams: number of blkio parameters (this value can be the same or
* less than the number of parameters supported)
* @flags: an OR'ed set of virDomainModificationImpact
* @flags: bitwise-OR of virDomainModificationImpact
*
* Change all or a subset of the blkio tunables.
* This function may require privileged access to the hypervisor.
@ -3749,6 +3799,9 @@ virDomainSetBlkioParameters(virDomainPtr domain,
virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
goto error;
}
if (virTypedParameterValidateSet(domain, params, nparams) < 0)
return -1;
conn = domain->conn;
if (conn->driver->domainSetBlkioParameters) {
@ -3772,7 +3825,7 @@ error:
* @params: pointer to blkio parameter object
* (return value, allocated by the caller)
* @nparams: pointer to number of blkio parameters; input and output
* @flags: an OR'ed set of virDomainModificationImpact
* @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags
*
* Get all blkio parameters. On input, @nparams gives the size of the
* @params array; on output, @nparams gives how many slots were filled
@ -3814,6 +3867,9 @@ virDomainGetBlkioParameters(virDomainPtr domain,
virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
goto error;
}
if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
VIR_DRV_FEATURE_TYPED_PARAM_STRING))
flags |= VIR_TYPED_PARAM_STRING_OKAY;
conn = domain->conn;
if (conn->driver->domainGetBlkioParameters) {
@ -6410,7 +6466,7 @@ error:
* @nparams: pointer to number of scheduler parameter
* (this value should be same than the returned value
* nparams of virDomainGetSchedulerType()); input and output
* @flags: one of virDomainModificationImpact
* @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags
*
* Get all scheduler parameters. On input, @nparams gives the size of the
* @params array; on output, @nparams gives how many slots were filled
@ -6456,6 +6512,9 @@ virDomainGetSchedulerParametersFlags(virDomainPtr domain,
goto error;
}
if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
VIR_DRV_FEATURE_TYPED_PARAM_STRING))
flags |= VIR_TYPED_PARAM_STRING_OKAY;
conn = domain->conn;
if (conn->driver->domainGetSchedulerParametersFlags) {
@ -6505,15 +6564,17 @@ virDomainSetSchedulerParameters(virDomainPtr domain,
return -1;
}
if (params == NULL || nparams < 0) {
virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
goto error;
}
if (domain->conn->flags & VIR_CONNECT_RO) {
virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__);
goto error;
}
if (params == NULL || nparams < 0) {
virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
goto error;
}
if (virTypedParameterValidateSet(domain, params, nparams) < 0)
return -1;
conn = domain->conn;
if (conn->driver->domainSetSchedulerParameters) {
@ -6568,15 +6629,17 @@ virDomainSetSchedulerParametersFlags(virDomainPtr domain,
return -1;
}
if (params == NULL || nparams < 0) {
virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
goto error;
}
if (domain->conn->flags & VIR_CONNECT_RO) {
virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__);
goto error;
}
if (params == NULL || nparams < 0) {
virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
goto error;
}
if (virTypedParameterValidateSet(domain, params, nparams) < 0)
return -1;
conn = domain->conn;
if (conn->driver->domainSetSchedulerParametersFlags) {
@ -6665,7 +6728,7 @@ error:
* @params: pointer to block stats parameter object
* (return value)
* @nparams: pointer to number of block stats; input and output
* @flags: unused, always pass 0
* @flags: bitwise-OR of virTypedParameterFlags
*
* This function is to get block stats parameters for block
* devices attached to the domain.
@ -6715,6 +6778,9 @@ int virDomainBlockStatsFlags(virDomainPtr dom,
virLibConnError(VIR_ERR_INVALID_ARG, __FUNCTION__);
goto error;
}
if (VIR_DRV_SUPPORTS_FEATURE(dom->conn->driver, dom->conn,
VIR_DRV_FEATURE_TYPED_PARAM_STRING))
flags |= VIR_TYPED_PARAM_STRING_OKAY;
conn = dom->conn;
if (conn->driver->domainBlockStatsFlags) {

View File

@ -1,7 +1,7 @@
/*
* libvirt.h: publically exported APIs, not for public use
*
* Copyright (C) 2006-2008 Red Hat, Inc.
* Copyright (C) 2006-2008, 2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -83,7 +83,12 @@ enum {
/*
* Support for file descriptor passing
*/
VIR_DRV_FEATURE_FD_PASSING = 8
VIR_DRV_FEATURE_FD_PASSING = 8,
/*
* Support for VIR_TYPED_PARAM_STRING
*/
VIR_DRV_FEATURE_TYPED_PARAM_STRING = 9,
};

View File

@ -1162,6 +1162,7 @@ virStrncpy;
virTimeMs;
virTimestamp;
virTrimSpaces;
virTypedParameterArrayClear;
virVasprintf;

View File

@ -2607,3 +2607,17 @@ or other application using the libvirt API.\n\
return 0;
}
void
virTypedParameterArrayClear(virTypedParameterPtr params, int nparams)
{
int i;
if (!params)
return;
for (i = 0; i < nparams; i++) {
if (params[i].type == VIR_TYPED_PARAM_STRING)
VIR_FREE(params[i].value.s);
}
}

View File

@ -258,4 +258,6 @@ bool virIsDevMapperDevice(const char *dev_name) ATTRIBUTE_NONNULL(1);
int virEmitXMLWarning(int fd,
const char *name,
const char *cmd) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
void virTypedParameterArrayClear(virTypedParameterPtr params, int nparams);
#endif /* __VIR_UTIL_H__ */