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.csa...@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;
> 
> [..]
> 


_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to