On Tue, May 9, 2023 at 8:15 AM Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx> wrote: > > On Fri, 5 May 2023, Jorge Lopez wrote: > > > HP BIOS Configuration driver purpose is to provide a driver supporting > > the latest sysfs class firmware attributes framework allowing the user > > to change BIOS settings and security solutions on HP Inc.’s commercial > > notebooks. > > > > Many features of HP Commercial notebooks can be managed using Windows > > Management Instrumentation (WMI). WMI is an implementation of Web-Based > > Enterprise Management (WBEM) that provides a standards-based interface > > for changing and monitoring system settings. HP BIOSCFG driver provides > > a native Linux solution and the exposed features facilitates the > > migration to Linux environments. > > > > The Linux security features to be provided in hp-bioscfg driver enables > > managing the BIOS settings and security solutions via sysfs, a virtual > > filesystem that can be used by user-mode applications. The new > > documentation cover HP-specific firmware sysfs attributes such Secure > > Platform Management and Sure Start. Each section provides security > > feature description and identifies sysfs directories and files exposed > > by the driver. > > > > Many HP Commercial notebooks include a feature called Secure Platform > > Management (SPM), which replaces older password-based BIOS settings > > management with public key cryptography. PC secure product management > > begins when a target system is provisioned with cryptographic keys > > that are used to ensure the integrity of communications between system > > management utilities and the BIOS. > > > > HP Commercial notebooks have several BIOS settings that control its > > behaviour and capabilities, many of which are related to security. > > To prevent unauthorized changes to these settings, the system can > > be configured to use a cryptographic signature-based authorization > > string that the BIOS will use to verify authorization to modify the > > setting. > > > > Linux Security components are under development and not published yet. > > The only linux component is the driver (hp bioscfg) at this time. > > Other published security components are under Windows. > > > > Signed-off-by: Jorge Lopez <jorge.lopez2@xxxxxx> > > > > --- > > Based on the latest platform-drivers-x86.git/for-next > > --- > > .../x86/hp/hp-bioscfg/ordered-attributes.c | 443 ++++++++++++++++++ > > 1 file changed, 443 insertions(+) > > create mode 100644 drivers/platform/x86/hp/hp-bioscfg/ordered-attributes.c > > > > diff --git a/drivers/platform/x86/hp/hp-bioscfg/ordered-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/ordered-attributes.c > > new file mode 100644 <snip> > > + strscpy(ordered_list_data->common.display_name_language_code, > > + LANG_CODE_STR, > > + sizeof(ordered_list_data->common.display_name_language_code)); > > + > > + for (elem = 1, eloc = 1; elem < order_obj_count; elem++, eloc++) { > > + /* ONLY look at the first ORDERED_ELEM_CNT elements */ > > + if (eloc == ORD_ELEM_CNT) > > + goto exit_list_package; > > + > > + switch (order_obj[elem].type) { > > + case ACPI_TYPE_STRING: > > + > > Extra newline. Done! > > > + if (elem != PREREQUISITES && elem != ORD_LIST_ELEMENTS) { > > + ret = convert_hexstr_to_str(order_obj[elem].string.pointer, > > + order_obj[elem].string.length, > > + &str_value, &value_len); > > + if (ret) > > + continue; > > + } > > + break; > > + case ACPI_TYPE_INTEGER: > > + int_value = (u32)order_obj[elem].integer.value; > > + break; > > + default: > > + pr_warn("Unsupported object type [%d]\n", order_obj[elem].type); > > + continue; > > + } > > + > > + /* Check that both expected and read object type match */ > > + if (expected_order_types[eloc] != order_obj[elem].type) { > > + pr_err("Error expected type %d for elem %d, but got type %d instead\n", > > Extra space before %d. Done! > > > + expected_order_types[eloc], elem, order_obj[elem].type); > > + return -EIO; > > + } > > + <snip> > > + kfree(tmpstr); > > + break; > > + default: > > + pr_warn("Invalid element: %d found in Ordered_List attribute or data may be malformed\n", elem); > > + break; > > + } > > + kfree(tmpstr); > > + kfree(str_value); > > + } > > + > > +exit_list_package: > > + kfree(tmpstr); > > + kfree(str_value); > > + return 0; > > +} > > Looks double and triple frees in this function. Done! > > After reading the about same things once again, I started to wonder if > some of that switch content could be moved into a common helper (which > takes e.g. the xx->common pointer as parameter and perhaps some other > carefully selected pointers). There's a lots of duplication. > I will look into how the common data can be implemented with a helper. > > +/** > > + * populate_ordered_list_buffer_data() - Populate all properties of an > > + * instance under ordered list attribute > > + * > > + * @buffer_ptr: Buffer pointer > > + * @buffer_size: Buffer size > > + * @instance_id: The instance to enumerate > > + * @attr_name_kobj: The parent kernel object > > + */ > > +int populate_ordered_list_buffer_data(u8 *buffer_ptr, u32 *buffer_size, int instance_id, > > + struct kobject *attr_name_kobj) > > +{ > > + struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id]; > > + > > + ordered_list_data->attr_name_kobj = attr_name_kobj; > > + > > + /* Populate ordered list elements */ > > + populate_ordered_list_elements_from_buffer(buffer_ptr, buffer_size, > > + instance_id); > > + update_attribute_permissions(ordered_list_data->common.is_readonly, > > + &ordered_list_current_val); > > + friendly_user_name_update(ordered_list_data->common.path, > > + attr_name_kobj->name, > > + ordered_list_data->common.display_name, > > + sizeof(ordered_list_data->common.display_name)); > > + > > + return sysfs_create_group(attr_name_kobj, &ordered_list_attr_group); > > +} > > + > > +int populate_ordered_list_elements_from_buffer(u8 *buffer_ptr, u32 *buffer_size, > > + int instance_id) > > +{ > > + int reqs; > > + int values; > > + struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id]; > > + > > + strscpy(ordered_list_data->common.display_name_language_code, > > + LANG_CODE_STR, > > + sizeof(ordered_list_data->common.display_name_language_code)); > > + > > + // VALUE: > > + get_string_from_buffer(&buffer_ptr, buffer_size, ordered_list_data->current_value, > > + sizeof(ordered_list_data->current_value)); > > + > > + // PATH: > > + get_string_from_buffer(&buffer_ptr, buffer_size, ordered_list_data->common.path, > > + sizeof(ordered_list_data->common.path)); > > + > > + // IS_READONLY: > > + get_integer_from_buffer(&buffer_ptr, buffer_size, > > + &ordered_list_data->common.is_readonly); > > + > > + //DISPLAY_IN_UI: > > + get_integer_from_buffer(&buffer_ptr, buffer_size, > > + &ordered_list_data->common.display_in_ui); > > + > > + // REQUIRES_PHYSICAL_PRESENCE: > > + get_integer_from_buffer(&buffer_ptr, buffer_size, > > + &ordered_list_data->common.requires_physical_presence); > > + > > + // SEQUENCE: > > + get_integer_from_buffer(&buffer_ptr, buffer_size, > > + &ordered_list_data->common.sequence); > > + > > + // PREREQUISITES_SIZE: > > + get_integer_from_buffer(&buffer_ptr, buffer_size, > > + &ordered_list_data->common.prerequisites_size); > > + > > + if (ordered_list_data->common.prerequisites_size > MAX_PREREQUISITES_SIZE) { > > + /* Report a message and limit prerequisite size to maximum value */ > > + pr_warn("String Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n"); > > + ordered_list_data->common.prerequisites_size = MAX_PREREQUISITES_SIZE; > > + } > > + > > + // PREREQUISITES: > > + for (reqs = 0; > > + reqs < ordered_list_data->common.prerequisites_size && reqs < MAX_PREREQUISITES_SIZE; > > + reqs++) > > + get_string_from_buffer(&buffer_ptr, buffer_size, > > + ordered_list_data->common.prerequisites[reqs], > > + sizeof(ordered_list_data->common.prerequisites[reqs])); > > + > > + // SECURITY_LEVEL: > > + get_integer_from_buffer(&buffer_ptr, buffer_size, > > + &ordered_list_data->common.security_level); > > + > > + // ORD_LIST_SIZE: > > + get_integer_from_buffer(&buffer_ptr, buffer_size, > > + &ordered_list_data->elements_size); > > + > > + if (ordered_list_data->elements_size > MAX_ELEMENTS_SIZE) { > > + /* Report a message and limit elements size to maximum value */ > > + pr_warn("Ordered List size value exceeded the maximum number of elements supported or data may be malformed\n"); > > + ordered_list_data->elements_size = MAX_ELEMENTS_SIZE; > > + } > > + > > + // ORD_LIST_ELEMENTS: > > + for (values = 0; values < ordered_list_data->elements_size && values < MAX_ELEMENTS_SIZE; > > + values++) > > + get_string_from_buffer(&buffer_ptr, buffer_size, > > + ordered_list_data->elements[values], > > + sizeof(ordered_list_data->elements[values])); > > + > > + return 0; > > +} > > Same here. Pass buffer, buffer_size and common into a helper? Maybe some > other parameters too to cover many/all of the cases? I will investigate how I can use more helpers to minimize the duplication > > > + > > +/** > > + * exit_ordered_list_attributes() - Clear all attribute data > > + * > > + * Clears all data allocated for this group of attributes > > + */ > > +void exit_ordered_list_attributes(void) > > +{ > > + int instance_id; > > + > > + for (instance_id = 0; instance_id < bioscfg_drv.ordered_list_instances_count; > > + instance_id++) { > > + struct kobject *attr_name_kobj = > > + bioscfg_drv.ordered_list_data[instance_id].attr_name_kobj; > > + > > + if (attr_name_kobj) > > + sysfs_remove_group(attr_name_kobj, > > + &ordered_list_attr_group); > > + } > > + bioscfg_drv.ordered_list_instances_count = 0; > > + > > + kfree(bioscfg_drv.ordered_list_data); > > + bioscfg_drv.ordered_list_data = NULL; > > +} > > > > -- > i.