[pve-devel] [PATCH cluster v3 1/2] add CFS_IPC_GET_GUEST_CONFIG_PROPERTIES method

Fabian Grünbichler f.gruenbichler at proxmox.com
Fri Apr 8 11:01:47 CEST 2022


On April 8, 2022 10:40 am, Fabian Grünbichler wrote:
> On March 17, 2022 12:44 pm, Dominik Csapak wrote:
>> for getting multiple properties from the in memory config of the
>> guests. I added a new CSF_IPC_ call to maintain backwards compatibility.
>> 
>> It basically behaves the same as
>> CFS_IPC_GET_GUEST_CONFIG_PROPERTY, but takes a list of properties
>> instead.
>> 
>> The old way of getting a single property is now also done by
>> the new function.
>> 
>> Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
> 
> one more small nit, otherwise this LGTM
> 

obviously after hitting send I found another one :-P

>> ---
>> changes since v2:
>> * add 'a-z' check while parsing the properties, this way the later min/max
>>   code works as intended
>> 
>>  data/src/cfs-ipc-ops.h |   2 +
>>  data/src/server.c      |  62 +++++++++++++++
>>  data/src/status.c      | 174 ++++++++++++++++++++++++++++-------------
>>  data/src/status.h      |   3 +
>>  4 files changed, 185 insertions(+), 56 deletions(-)
>> 
>> diff --git a/data/src/cfs-ipc-ops.h b/data/src/cfs-ipc-ops.h
>> index 003e233..249308d 100644
>> --- a/data/src/cfs-ipc-ops.h
>> +++ b/data/src/cfs-ipc-ops.h
>> @@ -43,4 +43,6 @@
>>  
>>  #define CFS_IPC_VERIFY_TOKEN 12
>>  
>> +#define CFS_IPC_GET_GUEST_CONFIG_PROPERTIES 13
>> +
>>  #endif
>> diff --git a/data/src/server.c b/data/src/server.c
>> index 549788a..b9394c8 100644
>> --- a/data/src/server.c
>> +++ b/data/src/server.c
>> @@ -89,6 +89,13 @@ typedef struct {
>>  	char property[];
>>  } cfs_guest_config_propery_get_request_header_t;
>>  
>> +typedef struct {
>> +	struct qb_ipc_request_header req_header;
>> +	uint32_t vmid;
>> +	uint8_t num_props;
>> +	char props[]; /* list of \0 terminated properties */
>> +} cfs_guest_config_properties_get_request_header_t;
>> +
>>  typedef struct {
>>  	struct qb_ipc_request_header req_header;
>>  	char token[];
>> @@ -348,6 +355,61 @@ static int32_t s1_msg_process_fn(
>>  
>>  			result = cfs_create_guest_conf_property_msg(outbuf, memdb, rh->property, rh->vmid);
>>  		}
>> +	} else if (request_id == CFS_IPC_GET_GUEST_CONFIG_PROPERTIES) {
>> +
>> +		cfs_guest_config_properties_get_request_header_t *rh =
>> +			(cfs_guest_config_properties_get_request_header_t *) data;
>> +
>> +		int propslen = request_size - G_STRUCT_OFFSET(cfs_guest_config_properties_get_request_header_t, props);

so request_size is int32_t, and the offset is 32 + 32 (qb header) + 32 + 
8 = 13 bytes, so propslen will always fit in an int and be positive.

>> +
>> +		result = 0;
>> +		if (rh->vmid < 100 && rh->vmid != 0) {
>> +			cfs_debug("vmid out of range %u", rh->vmid);
>> +			result = -EINVAL;
>> +		} else if (rh->vmid >= 100 && !vmlist_vm_exists(rh->vmid)) {
>> +			result = -ENOENT;
>> +		} else if (propslen <= 1) {
>> +			cfs_debug("propslen <= 1, %d", propslen);
>> +			result = -EINVAL;
>> +		} else {
>> +			const char **properties = malloc(sizeof(char*) * rh->num_props);
>> +			char *current = (rh->props);
>> +			int remaining = propslen;

remaining starts positive

>> +			for (uint8_t i = 0; i < rh->num_props; i++) {
>> +			    uint8_t proplen = strnlen(current, remaining);

this ain't no uint8_t ;) so this takes a size_t (positive int is fine 
accordingly) and returns one. a property can be longer than 255 chars 
though, which makes the assignment overflow and gives us a 
wrong/truncated proplen

>> +			    if (proplen == 0) {

could trigger this if the overflow aligns right.

>> +				cfs_debug("property length 0");
>> +				result = -EINVAL;
>> +				break;
>> +			    }
>> +			    if (proplen == remaining) {

can't be triggered by overflow since proplen must always be smaller than 
remaining

>> +				cfs_debug("property not \\0 terminated");
>> +				result = -EINVAL;
>> +				break;
>> +			    }
>> +			    if (current[0] < 'a' || current[0] > 'z') {

this could be triggered depending on how exactly proplen overflows / the 
property gets truncated

>> +				cfs_debug("property does not start with [a-z]");
>> +				result = -EINVAL;
>> +				break;
>> +			    }
>> +			    properties[i] = current;
>> +			    current[proplen] = '\0'; // ensure property is 0 terminated

truncates an overly long property

>> +			    remaining -= (proplen + 1);
>> +			    current += proplen + 1;

and we start the next iteration at the truncated position

>> +			}
>> +
>> +			if (remaining != 0) {

which likely makes us end up here (except if the msg was malformed with 
not-null-terminated properties, in which case they might align again and 
just their boundaries are wrong ;))

given that we assume remaining remains positive, and barring further 
future bugs that invariant should hold (we start off positive, in each 
iteration proplen must be < remaining to reach the subtraction which 
therefore at most reduces remaining to 0), we could switch both 
remaining and proplen to size_t ?

or if the/a limit on property length is actually desired, we should 
explicitly check for that (propslen <= limit * count at the start, and 
then in the loop body still get a size_t from strnlen and check that the 
result is < limit)

> 
>> +			    cfs_debug("leftover data after parsing %ul properties", rh->num_props);
>> +			    result = -EINVAL;
>> +			}
>> +
>> +			if (result == 0) {
>> +			    cfs_debug("cfs_get_guest_config_properties: basic valid checked, do request");
>> +			    result = cfs_create_guest_conf_properties_msg(outbuf, memdb, properties, rh->num_props, rh->vmid);
>> +			}
>> +
>> +			free(properties);
>> +		}
>>  	} else if (request_id == CFS_IPC_VERIFY_TOKEN) {
>>  
>>  		cfs_verify_token_request_header_t *rh = (cfs_verify_token_request_header_t *) data;
> 
> [..]
> 





More information about the pve-devel mailing list