From: Vibhav Pant vibhavp@gmail.com
--- dlls/cfgmgr32/main.c | 170 ++++++++++++++++++++++++++++++++- dlls/cfgmgr32/tests/cfgmgr32.c | 50 +++++----- 2 files changed, 193 insertions(+), 27 deletions(-)
diff --git a/dlls/cfgmgr32/main.c b/dlls/cfgmgr32/main.c index 053a657d381..9563419465d 100644 --- a/dlls/cfgmgr32/main.c +++ b/dlls/cfgmgr32/main.c @@ -20,6 +20,7 @@ #include "wine/debug.h" #include "wine/rbtree.h" #include "winreg.h" +#include "winternl.h" #include "cfgmgr32.h" #include "winuser.h" #include "dbt.h" @@ -317,6 +318,169 @@ static BOOL dev_properties_append( DEVPROPERTY **properties, ULONG *props_len, c return TRUE; }
+static HRESULT stack_push( DEVPROP_OPERATOR **stack, ULONG *len, DEVPROP_OPERATOR op ) +{ + DEVPROP_OPERATOR *tmp; + + if (!(tmp = realloc( *stack, (*len + 1) * sizeof( op ) ))) + return E_OUTOFMEMORY; + *stack = tmp; + tmp[*len] = op; + *len += 1; + return S_OK; +} + +static DEVPROP_OPERATOR stack_pop( DEVPROP_OPERATOR **stack, ULONG *len ) +{ + DEVPROP_OPERATOR op = DEVPROP_OPERATOR_NONE; + + if (*len) + { + op = (*stack)[*len - 1]; + *len -= 1; + } + return op; +} + +static BOOL devprop_type_validate( DEVPROPTYPE type, ULONG buf_size ) +{ + static const DWORD type_size[] = { + 0, 0, + sizeof( BYTE ),sizeof( BYTE ), + sizeof( INT16 ), sizeof( INT16 ), + sizeof( INT32 ), sizeof( INT32 ), + sizeof( INT64 ), sizeof( INT64 ), + sizeof( FLOAT ), sizeof( DOUBLE ), sizeof( DECIMAL ), + sizeof( GUID ), + sizeof( CURRENCY ), + sizeof( DATE ), + sizeof( FILETIME ), + sizeof( DEVPROP_BOOLEAN ), + [DEVPROP_TYPE_DEVPROPKEY] = sizeof( DEVPROPKEY ), + [DEVPROP_TYPE_DEVPROPTYPE] = sizeof( DEVPROPTYPE ), + [DEVPROP_TYPE_ERROR] = sizeof( ULONG ), + [DEVPROP_TYPE_NTSTATUS] = sizeof( NTSTATUS ) + }; + DWORD mod = type & DEVPROP_MASK_TYPEMOD, size; + + if (mod && mod != DEVPROP_TYPEMOD_ARRAY && mod != DEVPROP_TYPEMOD_LIST) + return FALSE; + + switch (type & DEVPROP_MASK_TYPE) + { + case DEVPROP_TYPE_EMPTY: + case DEVPROP_TYPE_NULL: + return !mod; + case DEVPROP_TYPE_SECURITY_DESCRIPTOR: + case DEVPROP_TYPE_STRING_INDIRECT: + return !mod && !!buf_size; + + case DEVPROP_TYPE_STRING: + case DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING: + return mod != DEVPROP_TYPEMOD_ARRAY && !!buf_size; + default: + /* The only valid modifier for the remaining types is DEVPROP_TYPEMOD_ARRAY */ + if (mod && mod != DEVPROP_TYPEMOD_ARRAY) + return FALSE; + if ((type & DEVPROP_MASK_TYPE) > DEVPROP_TYPE_NTSTATUS) + return FALSE; + size = type_size[type & DEVPROP_MASK_TYPE]; + } + + return mod == DEVPROP_TYPEMOD_ARRAY ? buf_size >= size : buf_size == size; +} + +static HRESULT devprop_filters_validate( ULONG filters_len, const DEVPROP_FILTER_EXPRESSION *filters ) +{ + DEVPROP_OPERATOR *stack = NULL; + ULONG i, logical_open = 0, stack_top = 0; + HRESULT hr = S_OK; + + for (i = 0; i < filters_len; i++) + { + const DEVPROP_FILTER_EXPRESSION *filter = &filters[i]; + const DEVPROPERTY *prop = &filter->Property; + DEVPROP_OPERATOR op = filter->Operator; + DWORD compare = op & DEVPROP_OPERATOR_MASK_EVAL; + DWORD list = op & DEVPROP_OPERATOR_MASK_LIST; + DWORD modifier = op & DEVPROP_OPERATOR_MASK_MODIFIER; + DWORD logical = op & DEVPROP_OPERATOR_MASK_LOGICAL; + DWORD array = op & DEVPROP_OPERATOR_MASK_ARRAY; + + if ((compare && compare > DEVPROP_OPERATOR_CONTAINS) + || (logical && (op & DEVPROP_OPERATOR_MASK_NOT_LOGICAL)) + || (array && (op != DEVPROP_OPERATOR_ARRAY_CONTAINS)) + || !!prop->Buffer != !!prop->BufferSize) + { + hr = E_INVALIDARG; + break; + } + if (!op) continue; + if (compare && compare != DEVPROP_OPERATOR_EXISTS + && !devprop_type_validate( prop->Type, prop->BufferSize )) + { + hr = E_INVALIDARG; + break; + } + + switch (modifier) + { + case DEVPROP_OPERATOR_NONE: + case DEVPROP_OPERATOR_MODIFIER_NOT: + case DEVPROP_OPERATOR_MODIFIER_IGNORE_CASE: + break; + default: + hr = E_INVALIDARG; + break; + } + + switch (list) + { + case DEVPROP_OPERATOR_NONE: + case DEVPROP_OPERATOR_LIST_CONTAINS: + case DEVPROP_OPERATOR_LIST_ELEMENT_BEGINS_WITH: + case DEVPROP_OPERATOR_LIST_ELEMENT_ENDS_WITH: + case DEVPROP_OPERATOR_LIST_ELEMENT_CONTAINS: + break; + default: + hr = E_INVALIDARG; + break; + } + + switch (logical) + { + case DEVPROP_OPERATOR_NONE: + break; + case DEVPROP_OPERATOR_AND_OPEN: + case DEVPROP_OPERATOR_OR_OPEN: + case DEVPROP_OPERATOR_NOT_OPEN: + hr = stack_push( &stack, &stack_top, logical ); + logical_open = i; + break; + case DEVPROP_OPERATOR_AND_CLOSE: + case DEVPROP_OPERATOR_OR_CLOSE: + case DEVPROP_OPERATOR_NOT_CLOSE: + { + DEVPROP_OPERATOR top = stack_pop( &stack, &stack_top ); + /* The operator should be correct paired, and shouldn't be empty. */ + if (logical - top != (DEVPROP_OPERATOR_AND_CLOSE - DEVPROP_OPERATOR_AND_OPEN) || logical_open == i - 1) + hr = E_INVALIDARG; + break; + } + default: + hr = E_INVALIDARG; + break; + } + + if (FAILED( hr )) break; + } + + if (stack_top) + hr = E_INVALIDARG; + free( stack ); + return hr; +} + static HRESULT dev_object_iface_get_props( DEV_OBJECT *obj, HDEVINFO set, SP_DEVICE_INTERFACE_DATA *iface_data, ULONG props_len, const DEVPROPCOMPKEY *props, BOOL all_props ) { @@ -533,7 +697,8 @@ HRESULT WINAPI DevGetObjectsEx( DEV_OBJECT_TYPE type, ULONG flags, ULONG props_l params_len, params, objs_len, objs );
if (!!props_len != !!props || !!filters_len != !!filters || !!params_len != !!params || (flags & ~valid_flags) - || (props_len && (flags & DevQueryFlagAllProperties))) + || (props_len && (flags & DevQueryFlagAllProperties)) + || FAILED( devprop_filters_validate( filters_len, filters ) )) return E_INVALIDARG; if (filters) FIXME( "Query filters are not supported!\n" ); @@ -985,7 +1150,8 @@ HRESULT WINAPI DevCreateObjectQueryEx( DEV_OBJECT_TYPE type, ULONG flags, ULONG filters, params_len, params, callback, user_data, devquery );
if (!!props_len != !!props || !!filters_len != !!filters || !!params_len != !!params || (flags & ~valid_flags) || !callback - || (props_len && (flags & DevQueryFlagAllProperties))) + || (props_len && (flags & DevQueryFlagAllProperties)) + || FAILED( devprop_filters_validate( filters_len, filters ) )) return E_INVALIDARG; if (filters) FIXME( "Query filters are not supported!\n" ); diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index 5426fa3f536..0af12233a38 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -921,10 +921,10 @@ static void test_DevGetObjects( void ) len = 0xdeadbeef; objects = (DEV_OBJECT *)0xdeadbeef; hr = pDevGetObjects( DevObjectTypeDeviceInterface, DevQueryFlagAllProperties, 0, NULL, 1, &filters[0], &len, &objects ); - todo_wine ok( hr == E_INVALIDARG, "got hr %#lx\n", hr ); + ok( hr == E_INVALIDARG, "got hr %#lx\n", hr ); /* Filters are validated before len and objects are modified. */ - todo_wine ok( len == 0xdeadbeef, "got len %lu\n", len ); - todo_wine ok( objects == (DEV_OBJECT *)0xdeadbeef, "got objects %p\n", objects ); + ok( len == 0xdeadbeef, "got len %lu\n", len ); + ok( objects == (DEV_OBJECT *)0xdeadbeef, "got objects %p\n", objects );
/* Mismatching BufferSize */ len = 0xdeadbeef; @@ -933,9 +933,9 @@ static void test_DevGetObjects( void ) filters[0].Property.BufferSize = 0; hr = pDevGetObjects( DevObjectTypeDeviceInterface, DevQueryFlagAllProperties, 0, NULL, 1, &filters[0], &len, &objects ); /* BufferSize is not validated in Windows 10 and before, but no objects are returned. */ - todo_wine ok( hr == E_INVALIDARG || broken( hr == S_OK ), "got hr %#lx\n", hr ); - todo_wine ok( len == 0xdeadbeef || broken( !len ), "got len %lu\n", len ); - todo_wine ok( objects == (DEV_OBJECT *)0xdeadbeef || broken( !objects ), "got objects %p\n", objects ); + ok( hr == E_INVALIDARG || broken( hr == S_OK ), "got hr %#lx\n", hr ); + ok( len == 0xdeadbeef || broken( !len ), "got len %lu\n", len ); + ok( objects == (DEV_OBJECT *)0xdeadbeef || broken( !objects ), "got objects %p\n", objects );
len = 0xdeadbeef; objects = (DEV_OBJECT *)0xdeadbeef; @@ -943,9 +943,9 @@ static void test_DevGetObjects( void ) filters[0].Property.BufferSize = sizeof( bool_val_extra ); hr = pDevGetObjects( DevObjectTypeDeviceInterface, DevQueryFlagAllProperties, 0, NULL, 1, &filters[0], &len, &objects ); /* The extra bytes are ignored in Windows 10 and before. */ - todo_wine ok( hr == E_INVALIDARG || broken( hr == S_OK ), "got hr %#lx\n", hr ); - todo_wine ok( len == 0xdeadbeef || broken( len ), "got len %lu\n", len ); - todo_wine ok( objects == (DEV_OBJECT *)0xdeadbeef || broken( !!objects ), "got objects %p\n", objects ); + ok( hr == E_INVALIDARG || broken( hr == S_OK ), "got hr %#lx\n", hr ); + ok( len == 0xdeadbeef || broken( len ), "got len %lu\n", len ); + ok( objects == (DEV_OBJECT *)0xdeadbeef || broken( !!objects ), "got objects %p\n", objects ); if (SUCCEEDED( hr )) pDevFreeObjects( len, objects );
for (i = 0; i < ARRAY_SIZE( invalid_ops ); i++) @@ -954,10 +954,10 @@ static void test_DevGetObjects( void ) filters[0].Operator = invalid_ops[i];
hr = pDevGetObjects( DevObjectTypeDeviceInterface, DevQueryFlagAllProperties, 0, NULL, 1, filters, &len, &objects ); - todo_wine ok( hr == E_INVALIDARG, "got hr %#lx\n", hr ); + ok( hr == E_INVALIDARG, "got hr %#lx\n", hr );
hr = pDevGetObjects( DevObjectTypeDeviceInterface, DevQueryFlagAllProperties, 0, NULL, 2, filters, &len, &objects ); - todo_wine ok( hr == E_INVALIDARG, "got hr %#lx\n", hr ); + ok( hr == E_INVALIDARG, "got hr %#lx\n", hr );
winetest_pop_context(); } @@ -986,9 +986,9 @@ static void test_DevGetObjects( void ) len = 0xdeadbeef; objects = (DEV_OBJECT *)0xdeadbeef; hr = pDevGetObjects( DevObjectTypeDeviceInterface, DevQueryFlagAllProperties, 0, NULL, 2, filters, &len, &objects ); - todo_wine ok( hr == E_INVALIDARG, "got hr %#lx\n", hr ); - todo_wine ok( len == 0xdeadbeef, "got len %lu\n", len ); - todo_wine ok( objects == (DEV_OBJECT *)0xdeadbeef, "got objects %p\n", objects ); + ok( hr == E_INVALIDARG, "got hr %#lx\n", hr ); + ok( len == 0xdeadbeef, "got len %lu\n", len ); + ok( objects == (DEV_OBJECT *)0xdeadbeef, "got objects %p\n", objects );
filters[0] = valid_filter; /* DEVPROP_OPERATOR_EXISTS ignores the property type. */ @@ -1056,8 +1056,8 @@ static void test_DevGetObjects( void ) objects = (DEV_OBJECT *)0xdeadbeef; hr = pDevGetObjects( DevObjectTypeDeviceInterface, DevQueryFlagNone, 0, NULL, 1, &filters[0], &len, &objects ); ok( hr == S_OK, "got hr %#lx\n", hr ); - todo_wine ok( len == 0, "got len %lu\n", len ); - todo_wine ok( !objects, "got objects %p\n", objects ); + ok( len == 0, "got len %lu\n", len ); + ok( !objects, "got objects %p\n", objects );
/* Empty expressions */ memset( filters, 0, sizeof( filters ) ); @@ -1072,9 +1072,9 @@ static void test_DevGetObjects( void ) len = 0xdeadbeef; objects = (DEV_OBJECT *)0xdeadbeef; hr = pDevGetObjects( DevObjectTypeDeviceInterface, DevQueryFlagNone, 0, NULL, 2, filters, &len, &objects ); - todo_wine ok( hr == E_INVALIDARG, "got hr %#lx\n", hr ); - todo_wine ok( len == 0xdeadbeef, "got len %lu\n", len ); - todo_wine ok( objects == (DEV_OBJECT *)0xdeadbeef, "got objects %p\n", objects ); + ok( hr == E_INVALIDARG, "got hr %#lx\n", hr ); + ok( len == 0xdeadbeef, "got len %lu\n", len ); + ok( objects == (DEV_OBJECT *)0xdeadbeef, "got objects %p\n", objects );
/* Empty nested expressions */ filters[0].Operator = filters[1].Operator = open; @@ -1082,9 +1082,9 @@ static void test_DevGetObjects( void ) len = 0xdeadbeef; objects = (DEV_OBJECT *)0xdeadbeef; hr = pDevGetObjects( DevObjectTypeDeviceInterface, DevQueryFlagNone, 0, NULL, 4, filters, &len, &objects ); - todo_wine ok( hr == E_INVALIDARG, "got hr %#lx\n", hr ); - todo_wine ok( len == 0xdeadbeef, "got len %lu\n", len ); - todo_wine ok( objects == (DEV_OBJECT *)0xdeadbeef, "got objects %p\n", objects ); + ok( hr == E_INVALIDARG, "got hr %#lx\n", hr ); + ok( len == 0xdeadbeef, "got len %lu\n", len ); + ok( objects == (DEV_OBJECT *)0xdeadbeef, "got objects %p\n", objects );
winetest_pop_context(); } @@ -1108,9 +1108,9 @@ static void test_DevGetObjects( void ) len = 0xdeadbeef; objects = (DEV_OBJECT *)0xdeadbeef; hr = pDevGetObjects( DevObjectTypeDeviceInterface, DevQueryFlagNone, 0, NULL, 3, filters, &len, &objects ); - todo_wine ok( hr == E_INVALIDARG, "got hr %#lx\n", hr ); - todo_wine ok( len == 0xdeadbeef, "got len %lu\n", len ); - todo_wine ok( objects == (DEV_OBJECT *)0xdeadbeef, "got objects %p\n", objects ); + ok( hr == E_INVALIDARG, "got hr %#lx\n", hr ); + ok( len == 0xdeadbeef, "got len %lu\n", len ); + ok( objects == (DEV_OBJECT *)0xdeadbeef, "got objects %p\n", objects );
winetest_pop_context(); }