linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3] Introduce support for Systems Management Driver over WMI for Dell Systems
@ 2020-09-17  6:55 Divya Bharathi
  2020-09-17 12:01 ` kernel test robot
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Divya Bharathi @ 2020-09-17  6:55 UTC (permalink / raw)
  To: dvhart
  Cc: LKML, platform-driver-x86, Divya Bharathi, Hans de Goede,
	Andy Shevchenko, mark gross, Mario Limonciello, Prasanth KSR

The Dell WMI Systems Management Driver provides a sysfs
interface for systems management to enable BIOS configuration
capability on certain Dell Systems.

This driver allows user to configure Dell systems with a
uniform common interface. To facilitate this, the patch
introduces a generic way for driver to be able to create
configurable BIOS Attributes available in Setup (F2) screen.

Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Andy Shevchenko <andy.shevchenko@gmail.com>
Cc: mark gross <mgross@linux.intel.com>

Co-developed-by: Mario Limonciello <mario.limonciello@dell.com>
Signed-off-by: Mario Limonciello <mario.limonciello@dell.com>
Co-developed-by: Prasanth KSR <prasanth.ksr@dell.com>
Signed-off-by: Prasanth KSR <prasanth.ksr@dell.com>
Signed-off-by: Divya Bharathi <divya_bharathi@dell.com>
---

Changes from v2 to v3:
 - Fix a possible NULL pointer error in init
 - Add missing newlines to all dev_err/dev_dbg/pr_err/pr_debug statements
 - Correct updating passwords when both Admin and System password are set
 - Correct the WMI driver name
 - Correct some namespace clashing when compiled into the kernel (Reported by Mark Gross)
 - Correct some comment typos
 - Adopt suggestions made by Hans:
   + Use single global mutex
   + Clarify reason for uevents with a comment
   + Remove functions for set and get current password
   + Rename lower_bound to min_value and upper_bound to max_value
   + Rename possible_value to possible_values
   + Remove references to float
   + Build a separate passwords directory again since it behaves differently from the other
     attributes
   + Move more calls from pr_err -> dev_err
 - Documentation cleanups (see v2 patch feedback)
   + Grouping types
   + Syntax of `modifier` output

Changes from v1 to v2:
 - use pr_fmt instead of pr_err(DRIVER_NAME
 - re-order variables reverse xmas tree order
 - correct returns of -1 to error codes
 - correct usage of {} on some split line statements
 - Refine all documentation deficiencies suggested by Hans
 - Merge all attributes to a single directory
 - Overhaul WMI interface interaction as suggested by Hans
   * Move WMI driver registration to start of module
   * Remove usage of lists that only use first entry for WMI interfaces
   * Create a global structure shared across interface source files
   * Make get_current_password function static
   * Remove get_pending changes function, shared across global structure now.
- Overhaul use of mutexes
   * Make kset list mutex shared across source files
   * Remove unneeded dell-wmi-sysman call_mutex
   * Keep remaining call_mutexes in WMI functions
- Move security area calculation into a function
- Use NLS helper for utf8->utf16 conversion

 .../testing/sysfs-platform-dell-wmi-sysman    | 175 ++++++
 MAINTAINERS                                   |   9 +
 drivers/platform/x86/Kconfig                  |  12 +
 drivers/platform/x86/Makefile                 |   8 +
 .../x86/dell-wmi-biosattr-interface.c         | 197 ++++++
 .../platform/x86/dell-wmi-enum-attributes.c   | 208 +++++++
 .../platform/x86/dell-wmi-int-attributes.c    | 189 ++++++
 .../x86/dell-wmi-passobj-attributes.c         | 165 +++++
 .../x86/dell-wmi-passwordattr-interface.c     | 167 +++++
 .../platform/x86/dell-wmi-string-attributes.c | 171 +++++
 .../platform/x86/dell-wmi-sysman-attributes.c | 589 ++++++++++++++++++
 .../platform/x86/dell-wmi-sysman-attributes.h | 137 ++++
 12 files changed, 2027 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-platform-dell-wmi-sysman
 create mode 100644 drivers/platform/x86/dell-wmi-biosattr-interface.c
 create mode 100644 drivers/platform/x86/dell-wmi-enum-attributes.c
 create mode 100644 drivers/platform/x86/dell-wmi-int-attributes.c
 create mode 100644 drivers/platform/x86/dell-wmi-passobj-attributes.c
 create mode 100644 drivers/platform/x86/dell-wmi-passwordattr-interface.c
 create mode 100644 drivers/platform/x86/dell-wmi-string-attributes.c
 create mode 100644 drivers/platform/x86/dell-wmi-sysman-attributes.c
 create mode 100644 drivers/platform/x86/dell-wmi-sysman-attributes.h

diff --git a/Documentation/ABI/testing/sysfs-platform-dell-wmi-sysman b/Documentation/ABI/testing/sysfs-platform-dell-wmi-sysman
new file mode 100644
index 000000000000..03398ac11121
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-dell-wmi-sysman
@@ -0,0 +1,175 @@
+What:		/sys/devices/platform/dell-wmi-sysman/attributes/
+Date:		December 2020
+KernelVersion:	5.10
+Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
+		Mario Limonciello <mario.limonciello@dell.com>,
+		Prasanth KSR <prasanth.ksr@dell.com>
+Description:
+		The Dell WMI Systems Management Driver provides a sysfs interface
+		for systems management software to enable BIOS configuration
+		capability on certain Dell systems. This directory exposes
+		interfaces for interacting with BIOS attributes.
+
+		Attributes can accept a set of pre-defined valid values (enumeration)
+		or a range of numerical values (integer) or a string.
+
+		current_value:	A file that can be read to obtain the current
+		value of the <attr>
+
+		This file can also be written to in order to update
+		the value of a <attr>
+
+		default_value:	A file that can be read to obtain the default
+		value of the <attr>
+
+		display_name:	A file that can be read to obtain a user friendly
+		description of the at <attr>
+
+		display_name_language_code:	A file that can be read to obtain
+		the IETF language tag corresponding to the "display_name" of the <attr>
+
+		modifier:	A file that can be read to obtain attribute-level
+		dependency rule. It says an attribute X will become read-only or
+		suppressed, if/if-not attribute Y is configured.
+
+		modifier rules can be in following format,
+		[ReadOnlyIf:<attribute>=<value>]
+		[ReadOnlyIfNot:<attribute>=<value>]
+		[SuppressIf:<attribute>=<value>]
+		[SuppressIfNot:<attribute>=<value>]
+
+		For example,
+		AutoOnFri/modifier has value,
+			[SuppressIfNot:AutoOn=SelectDays]
+		This means AutoOnFri will be supressed in BIOS setup if AutoOn
+		attribute is not "SelectDays" and its value will not be effective
+		through sysfs until this rule is met.
+
+		"enumeration"-type specific properties:
+
+		possible_values:	A file that can be read to obtain the possible
+		values of the <attr>. Values are separated using semi-colon.
+
+		value_modifier:	A file that can be read to obtain value-level
+		dependency. This file is similar to modifier but here, an attribute's
+		current value will be forcefully changed based dependent attributes
+		value.
+
+		value_modifier rules can be in following format,
+		<value>[ForceIf:<attribute>=<value>]
+		<value>[ForceIfNot:<attribute>=<value>]
+
+		For example,
+		LegacyOrom/value_modifier has value,
+			Disabled[ForceIf:SecureBoot=Enabled]
+		This means LegacyOrom's current value will be forced to "Disabled"
+		in BIOS setup if SecureBoot is Enabled and its value will not be
+		effective through sysfs until this rule is met.
+
+		"integer"-type specific properties:
+
+		min_value:	A file that can be read to obtain the lower
+		bound value of the <attr>
+
+		max_value:	A file that can be read to obtain the upper
+		bound value of the <attr>
+
+		scalar_increment:	A file that can be read to obtain the
+		resolution of the incremental value this attribute accepts.
+
+		"string"-type specific properties:
+
+		max_length:	A file that can be read to obtain the maximum
+		length value of the <attr>
+
+		min_length:	A file that can be read to obtain the minimum
+		length value of the <attr>
+
+What:		/sys/devices/platform/dell-wmi-sysman/passwords/
+Date:		December 2020
+KernelVersion:	5.10
+Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
+		Mario Limonciello <mario.limonciello@dell.com>,
+		Prasanth KSR <prasanth.ksr@dell.com>
+
+		A BIOS Admin password and System Password can be set, reset or
+		cleared using these attributes. An "Admin" password is used for
+		preventing modification to the BIOS settings. A "System" password is
+		required to boot a machine.
+
+		is_password_set:	A file that can be read
+		to obtain flag to see if a password is set on <attr>
+
+		max_password_length:	A file that can be read to obtain the
+		maximum length of the Password
+
+		min_password_length:	A file that can be read to obtain the
+		minimum length of the Password
+
+		current_password: A write only value used for privileged access
+		such as setting attributes when a system or admin password is set
+		or resetting to a new password
+
+		new_password: A write only value that when used in tandem with
+		current_password will reset a system or admin password.
+
+		Note, password management is session specific. If Admin/System
+		password is set, same password must be writen into current_password
+		file (requied for pasword-validation) and must be cleared once the
+		session	is over. For example,
+			echo "password" > current_password
+			echo "disabled" > TouchScreen/current_value
+			echo "" > current_password
+
+
+What:		/sys/devices/platform/dell-wmi-sysman/attributes/reset_bios
+Date:		December 2020
+KernelVersion:	5.10
+Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
+		Mario Limonciello <mario.limonciello@dell.com>,
+		Prasanth KSR <prasanth.ksr@dell.com>
+Description:
+		This attribute can be used to reset the BIOS Configuration.
+		Specifically, it tells which type of reset BIOS configuration is being
+		requested on the host.
+
+		Reading from it returns a list of supported options encoded as:
+
+			'builtinsafe' (Built in safe configuration profile)
+			'lastknowngood' (Last known good saved configuration profile)
+			'factory' (Default factory settings configuration profile)
+			'custom' (Custom saved configuration profile)
+
+		The currently selected option is printed in square brackets as
+		shown below:
+
+		# echo "factory" > sys/devices/platform/dell-wmi-sysman/attributes/reset_bios
+
+		# cat sys/devices/platform/dell-wmi-sysman/attributes/reset_bios
+		# builtinsafe lastknowngood [factory] custom
+
+		Note that any changes to this attribute requires a reboot
+		for changes to take effect.
+
+What:		/sys/devices/platform/dell-wmi-sysman/attributes/pending_reboot
+Date:		December 2020
+KernelVersion:	5.10
+Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
+		Mario Limonciello <mario.limonciello@dell.com>,
+		Prasanth KSR <prasanth.ksr@dell.com>
+Description:
+		A read-only attribute reads 1 if a reboot is necessary to apply
+		pending BIOS attribute changes.
+
+			0:	All BIOS attributes setting are current
+			1:	A reboot is necessary to get pending BIOS attribute changes
+				applied
+
+
+		Note, userspace applications need to follow below steps for efficient
+		BIOS management,
+		1.	Check if admin password is set. If yes, follow session method for
+			password management as briefed under password section above.
+		2.	Before setting any attribute, check if it has any modifiers
+			or value_modifiers. If yes, incorporate them and then modify
+			attribute.
diff --git a/MAINTAINERS b/MAINTAINERS
index d746519253c3..7f46d381d759 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4957,6 +4957,15 @@ M:	Mario Limonciello <mario.limonciello@dell.com>
 S:	Maintained
 F:	drivers/platform/x86/dell-wmi-descriptor.c
 
+DELL WMI SYSMAN DRIVER
+M:	Divya Bharathi <divya.bharathi@dell.com>
+M:	Mario Limonciello <mario.limonciello@dell.com>
+M:	Prasanth Ksr <prasanth.ksr@dell.com>
+L:	platform-driver-x86@vger.kernel.org
+S:	Maintained
+F:	drivers/platform/x86/dell-wmi-*-attributes.*
+F:	drivers/platform/x86/dell-wmi-*-interface.c
+
 DELL WMI NOTIFICATIONS DRIVER
 M:	Matthew Garrett <mjg59@srcf.ucam.org>
 M:	Pali Rohár <pali@kernel.org>
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 40219bba6801..4fd7a3f0a904 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -430,6 +430,18 @@ config DELL_WMI
 	  To compile this driver as a module, choose M here: the module will
 	  be called dell-wmi.
 
+config DELL_WMI_SYSMAN
+	tristate "Dell WMI Systems management WMI driver"
+	depends on ACPI_WMI
+	depends on DMI
+	select NLS
+	help
+	  This driver allows changing BIOS settings on many Dell machines from
+	  2018 and newer without the use of any additional software.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called dell-wmi-sysman.
+
 config DELL_WMI_DESCRIPTOR
 	tristate
 	depends on ACPI_WMI
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 5f823f7eff45..dc2ccb574192 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -47,6 +47,14 @@ obj-$(CONFIG_DELL_WMI)			+= dell-wmi.o
 obj-$(CONFIG_DELL_WMI_DESCRIPTOR)	+= dell-wmi-descriptor.o
 obj-$(CONFIG_DELL_WMI_AIO)		+= dell-wmi-aio.o
 obj-$(CONFIG_DELL_WMI_LED)		+= dell-wmi-led.o
+obj-$(CONFIG_DELL_WMI_SYSMAN)  += dell-wmi-sysman.o
+dell-wmi-sysman-objs := dell-wmi-sysman-attributes.o \
+				 dell-wmi-enum-attributes.o \
+				 dell-wmi-int-attributes.o \
+				 dell-wmi-string-attributes.o \
+				 dell-wmi-passobj-attributes.o \
+				 dell-wmi-passwordattr-interface.o \
+				 dell-wmi-biosattr-interface.o
 
 # Fujitsu
 obj-$(CONFIG_AMILO_RFKILL)	+= amilo-rfkill.o
diff --git a/drivers/platform/x86/dell-wmi-biosattr-interface.c b/drivers/platform/x86/dell-wmi-biosattr-interface.c
new file mode 100644
index 000000000000..6fd79c181ee6
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-biosattr-interface.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Functions corresponding to SET methods under BIOS attributes interface GUID for use
+ * with dell-wmi-sysman
+ *
+ *  Copyright (c) 2020 Dell Inc.
+ */
+
+#include <linux/nls.h>
+#include <linux/wmi.h>
+#include "dell-wmi-sysman-attributes.h"
+
+#define SETDEFAULTVALUES_METHOD_ID					0x02
+#define SETBIOSDEFAULTS_METHOD_ID					0x03
+#define SETATTRIBUTE_METHOD_ID						0x04
+
+static int call_biosattributes_interface(struct wmi_device *wdev, char *in_args, size_t size,
+					int method_id)
+{
+	struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
+	struct acpi_buffer input;
+	union acpi_object *obj;
+	acpi_status status;
+	int ret = -EIO;
+
+	input.length =  (acpi_size) size;
+	input.pointer = in_args;
+	status = wmidev_evaluate_method(wdev, 0, method_id, &input, &output);
+	if (ACPI_FAILURE(status))
+		return -EIO;
+	obj = (union acpi_object *)output.pointer;
+	if (obj->type == ACPI_TYPE_INTEGER)
+		ret = obj->integer.value;
+
+	/* let userland know it may need to check reboot pending again */
+	kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE);
+	kfree(output.pointer);
+	return map_wmi_error(ret);
+}
+
+/**
+ * set_attribute() - Update an attribute value
+ * @a_name: The attribute name
+ * @a_value: The attribute value
+ *
+ * Sets an attribute to new value
+ **/
+int set_attribute(const char *a_name, const char *a_value)
+{
+	size_t security_area_size, string_area_size, buffer_size;
+	char *attribute_name, *attribute_value;
+	u8 *name_len, *value_len;
+	char *buffer = NULL;
+	int ret;
+
+	mutex_lock(&wmi_priv.mutex);
+	if (!wmi_priv.bios_attr_wdev) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* build/calculate buffer */
+	security_area_size = calculate_security_buffer();
+	string_area_size = (strlen(a_name) + strlen(a_value))*2;
+	buffer_size = security_area_size + string_area_size + sizeof(u16) * 2;
+	buffer = kzalloc(buffer_size, GFP_KERNEL);
+	if (!buffer) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/* build security area */
+	if (strlen(wmi_priv.current_admin_password) > 0)
+		populate_security_buffer(buffer, wmi_priv.current_admin_password);
+
+	/* build variables to set */
+	name_len = buffer + security_area_size;
+	attribute_name = name_len + sizeof(u16);
+	*name_len = utf8s_to_utf16s(a_name, strlen(a_name), UTF16_HOST_ENDIAN,
+				    (wchar_t *) attribute_name, MAX_BUFF) * 2;
+	if (*name_len < 0) {
+		ret = -EINVAL;
+		dev_err(&wmi_priv.password_attr_wdev->dev, "UTF16 conversion failed\n");
+		goto out;
+	}
+
+	value_len = (u8 *) attribute_name + *name_len;
+	attribute_value = value_len + sizeof(u16);
+	*value_len = utf8s_to_utf16s(a_value, strlen(a_value), UTF16_HOST_ENDIAN,
+				    (wchar_t *) attribute_value, MAX_BUFF) * 2;
+	if (*value_len < 0) {
+		ret = -EINVAL;
+		dev_err(&wmi_priv.password_attr_wdev->dev, "UTF16 conversion failed\n");
+		goto out;
+	}
+
+	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev,
+					    buffer, buffer_size,
+					    SETATTRIBUTE_METHOD_ID);
+	if (ret == -EOPNOTSUPP)
+		dev_err(&wmi_priv.password_attr_wdev->dev, "admin password must be configured\n");
+	else if (ret == -EACCES)
+		dev_err(&wmi_priv.password_attr_wdev->dev, "invalid password\n");
+
+	wmi_priv.pending_changes = 1;
+out:
+	kfree(buffer);
+	mutex_unlock(&wmi_priv.mutex);
+
+	return ret;
+}
+
+/**
+ * set_bios_defaults() - Resets BIOS defaults
+ * @deftype: the type of BIOS value reset to issue.
+ *
+ * Resets BIOS defaults
+ **/
+int set_bios_defaults(u8 deftype)
+{
+	size_t security_area_size, buffer_size;
+	size_t integer_area_size = sizeof(u8);
+	char *buffer = NULL;
+	u8 *defaultType;
+	int ret;
+
+	mutex_lock(&wmi_priv.mutex);
+	if (!wmi_priv.bios_attr_wdev) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	security_area_size = calculate_security_buffer();
+	buffer_size = security_area_size + integer_area_size;
+	buffer = kzalloc(buffer_size, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	/* build security area */
+	if (strlen(wmi_priv.current_admin_password) > 0)
+		populate_security_buffer(buffer, wmi_priv.current_admin_password);
+
+	defaultType = buffer + security_area_size;
+	*defaultType = deftype;
+
+	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev, buffer, buffer_size,
+					    SETBIOSDEFAULTS_METHOD_ID);
+	if (ret)
+		dev_err(&wmi_priv.bios_attr_wdev->dev, "reset BIOS defaults failed: %d\n", ret);
+	wmi_priv.pending_changes = 1;
+out:
+	kfree(buffer);
+	mutex_unlock(&wmi_priv.mutex);
+
+	return ret;
+}
+
+static int dell_wmi_bios_attr_set_interface_probe(struct wmi_device *wdev, const void *context)
+{
+	mutex_lock(&wmi_priv.mutex);
+	wmi_priv.bios_attr_wdev = wdev;
+	mutex_unlock(&wmi_priv.mutex);
+	return 0;
+}
+
+static int dell_wmi_bios_attr_set_interface_remove(struct wmi_device *wdev)
+{
+	mutex_lock(&wmi_priv.mutex);
+	wmi_priv.bios_attr_wdev = NULL;
+	mutex_unlock(&wmi_priv.mutex);
+	return 0;
+}
+
+static const struct wmi_device_id dell_wmi_bios_attr_set_interface_id_table[] = {
+	{ .guid_string = DELL_WMI_BIOS_ATTRIBUTES_INTERFACE_GUID },
+	{ },
+};
+static struct wmi_driver dell_wmi_bios_attr_set_interface_driver = {
+	.driver = {
+		.name = DRIVER_NAME
+	},
+	.probe = dell_wmi_bios_attr_set_interface_probe,
+	.remove = dell_wmi_bios_attr_set_interface_remove,
+	.id_table = dell_wmi_bios_attr_set_interface_id_table,
+};
+
+int init_dell_wmi_bios_attr_set_interface(void)
+{
+	return wmi_driver_register(&dell_wmi_bios_attr_set_interface_driver);
+}
+
+void exit_dell_wmi_bios_attr_set_interface(void)
+{
+	wmi_driver_unregister(&dell_wmi_bios_attr_set_interface_driver);
+}
+
+MODULE_DEVICE_TABLE(wmi, dell_wmi_bios_attr_set_interface_id_table);
diff --git a/drivers/platform/x86/dell-wmi-enum-attributes.c b/drivers/platform/x86/dell-wmi-enum-attributes.c
new file mode 100644
index 000000000000..4598c4e27310
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-enum-attributes.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Functions corresponding to enumeration type attributes under BIOS Enumeration GUID for use
+ * with dell-wmi-sysman
+ *
+ *  Copyright (c) 2020 Dell Inc.
+ */
+
+#include "dell-wmi-sysman-attributes.h"
+
+/* kept variable names same as in sysfs file name for sysfs_show macro definition */
+struct enumeration_data {
+	char display_name_language_code[MAX_BUFF];
+	char attribute_name[MAX_BUFF];
+	char display_name[MAX_BUFF];
+	char default_value[MAX_BUFF];
+	char current_value[MAX_BUFF];
+	char modifier[MAX_BUFF];
+	int value_modifier_count;
+	char value_modifier[MAX_BUFF];
+	int possible_values_count;
+	char possible_values[MAX_BUFF];
+	char type[MAX_BUFF];
+};
+
+static struct enumeration_data *enumeration_data;
+static int enumeration_instances_count;
+get_instance_id(enumeration);
+
+static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int instance_id;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	instance_id = get_enumeration_instance_id(kobj);
+	if (instance_id >= 0) {
+		union acpi_object *obj;
+
+		/* need to use specific instance_id and guid combination to get right data */
+		obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
+		if (!obj)
+			return -AE_ERROR;
+		strncpy_attr(enumeration_data[instance_id].current_value,
+		       obj->package.elements[CURRENT_VAL].string.pointer);
+		kfree(obj);
+		return sprintf(buf, "%s\n", enumeration_data[instance_id].current_value);
+	}
+	return -EIO;
+}
+
+/**
+ * validate_enumeration_input() - Validate input of current_value against possible values
+ * @instance_id: The instance on which input is validated
+ * @buf: Input value
+ **/
+int validate_enumeration_input(int instance_id, const char *buf)
+{
+	char *options, *tmp, *p;
+	int ret = -EINVAL;
+
+	options = tmp = kstrdup((enumeration_data[instance_id].possible_values), GFP_KERNEL);
+	if (!options)
+		return -ENOMEM;
+
+	while ((p = strsep(&options, ";")) != NULL) {
+		if (!*p)
+			continue;
+		if (!strncasecmp(p, buf, strlen(p))) {
+			ret = 0;
+			break;
+		}
+	}
+
+	kfree(tmp);
+	return ret;
+}
+
+attribute_s_property_show(display_name_language_code, enumeration);
+static struct kobj_attribute displ_langcode =
+		__ATTR_RO(display_name_language_code);
+
+attribute_s_property_show(display_name, enumeration);
+struct kobj_attribute displ_name =
+		__ATTR_RO(display_name);
+
+attribute_s_property_show(default_value, enumeration);
+struct kobj_attribute default_val =
+		__ATTR_RO(default_value);
+
+attribute_property_store(current_value, enumeration);
+struct kobj_attribute current_val =
+		__ATTR_RW(current_value);
+
+attribute_s_property_show(modifier, enumeration);
+struct kobj_attribute modifier =
+		__ATTR_RO(modifier);
+
+attribute_s_property_show(value_modifier, enumeration);
+struct kobj_attribute value_modfr =
+		__ATTR_RO(value_modifier);
+
+attribute_s_property_show(possible_values, enumeration);
+struct kobj_attribute poss_val =
+		__ATTR_RO(possible_values);
+
+attribute_s_property_show(type, enumeration);
+struct kobj_attribute type =
+		__ATTR_RO(type);
+
+static struct attribute *enumeration_attrs[] = {
+	&displ_langcode.attr,
+	&displ_name.attr,
+	&default_val.attr,
+	&current_val.attr,
+	&modifier.attr,
+	&value_modfr.attr,
+	&poss_val.attr,
+	&type.attr,
+	NULL,
+};
+
+static const struct attribute_group enumeration_attr_group = {
+	.attrs = enumeration_attrs,
+};
+
+int alloc_enum_data(void)
+{
+	int ret = 0;
+
+	enumeration_instances_count = get_instance_count(DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
+	enumeration_data = kzalloc((sizeof(struct enumeration_data) * enumeration_instances_count),
+					GFP_KERNEL);
+	if (!enumeration_data)
+		ret = -ENOMEM;
+	return ret;
+}
+
+/**
+ * populate_enum_data() - Populate all properties of an instance under enumeration attribute
+ * @enumeration_obj: ACPI object with enumeration data
+ * @instance_id: The instance to enumerate
+ * @attr_name_kobj: The parent kernel object
+ **/
+int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
+			struct kobject *attr_name_kobj)
+{
+	int retval = sysfs_create_group(attr_name_kobj, &enumeration_attr_group);
+	int i, next_obj;
+
+	if (retval)
+		goto out;
+
+	mutex_lock(&wmi_priv.mutex);
+	strncpy_attr(enumeration_data[instance_id].attribute_name,
+		enumeration_obj[ATTR_NAME].string.pointer);
+	strncpy_attr(enumeration_data[instance_id].display_name_language_code,
+		enumeration_obj[DISPL_NAME_LANG_CODE].string.pointer);
+	strncpy_attr(enumeration_data[instance_id].display_name,
+		enumeration_obj[DISPLAY_NAME].string.pointer);
+	strncpy_attr(enumeration_data[instance_id].default_value,
+		enumeration_obj[DEFAULT_VAL].string.pointer);
+	strncpy_attr(enumeration_data[instance_id].current_value,
+		enumeration_obj[CURRENT_VAL].string.pointer);
+	strncpy_attr(enumeration_data[instance_id].modifier,
+		enumeration_obj[MODIFIER].string.pointer);
+
+	next_obj = MODIFIER + 1;
+
+	enumeration_data[instance_id].value_modifier_count =
+		(uintptr_t)enumeration_obj[next_obj].string.pointer;
+
+	for (i = 0; i < enumeration_data[instance_id].value_modifier_count; i++) {
+		strcat(enumeration_data[instance_id].value_modifier,
+			enumeration_obj[++next_obj].string.pointer);
+		strcat(enumeration_data[instance_id].value_modifier, ";");
+	}
+
+	enumeration_data[instance_id].possible_values_count =
+		(uintptr_t) enumeration_obj[++next_obj].string.pointer;
+
+	for (i = 0; i < enumeration_data[instance_id].possible_values_count; i++) {
+		strcat(enumeration_data[instance_id].possible_values,
+			enumeration_obj[++next_obj].string.pointer);
+		strcat(enumeration_data[instance_id].possible_values, ";");
+	}
+	strncpy_attr(enumeration_data[instance_id].type, "enumeration");
+	mutex_unlock(&wmi_priv.mutex);
+
+out:
+	return retval;
+}
+
+/**
+ * exit_enum_attributes() - Clear all attribute data
+ *
+ * Clears all data allocated for this group of attributes
+ **/
+void exit_enum_attributes(void)
+{
+	struct kobject *pos, *next;
+
+	list_for_each_entry_safe(pos, next, &wmi_priv.main_dir_kset->list, entry) {
+		/* this removes only enumeration atribute group under main_dir_kset */
+		sysfs_remove_group(pos, &enumeration_attr_group);
+	}
+	kfree(enumeration_data);
+}
diff --git a/drivers/platform/x86/dell-wmi-int-attributes.c b/drivers/platform/x86/dell-wmi-int-attributes.c
new file mode 100644
index 000000000000..66947972739c
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-int-attributes.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Functions corresponding to integer type attributes under BIOS Integer GUID for use with
+ * dell-wmi-sysman
+ *
+ *  Copyright (c) 2020 Dell Inc.
+ */
+
+#include "dell-wmi-sysman-attributes.h"
+
+enum int_properties {MIN_VALUE = 6, MAX_VALUE, SCALAR_INCR};
+
+/* kept variable names same as in sysfs file name for sysfs_show macro definition */
+struct integer_data {
+	char display_name_language_code[MAX_BUFF];
+	char attribute_name[MAX_BUFF];
+	char display_name[MAX_BUFF];
+	int default_value;
+	int current_value;
+	char modifier[MAX_BUFF];
+	int min_value;
+	int max_value;
+	int scalar_increment;
+	char type[MAX_BUFF];
+};
+
+static struct integer_data *integer_data;
+static int integer_instances_count;
+get_instance_id(integer);
+
+static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int instance_id;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	instance_id = get_integer_instance_id(kobj);
+	if (instance_id >= 0) {
+		union acpi_object *obj;
+
+		/* need to use specific instance_id and guid combination to get right data */
+		obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
+		if (!obj)
+			return -AE_ERROR;
+		integer_data[instance_id].current_value =
+			(uintptr_t)obj->package.elements[CURRENT_VAL].string.pointer;
+		kfree(obj);
+		return sprintf(buf, "%d\n", integer_data[instance_id].current_value);
+	}
+	return -EIO;
+}
+
+/**
+ * validate_integer_input() - Validate input of current_value against lower and upper bound
+ * @instance_id: The instance on which input is validated
+ * @buf: Input value
+ **/
+int validate_integer_input(int instance_id, const char *buf)
+{
+	int ret = -EINVAL;
+	int in_val;
+
+	if (kstrtoint(buf, 0, &in_val))
+		return ret;
+	if ((in_val >= integer_data[instance_id].min_value) &&
+	(in_val <= integer_data[instance_id].max_value))
+		ret = 0;
+
+	return ret;
+}
+
+attribute_s_property_show(display_name_language_code, integer);
+static struct kobj_attribute integer_displ_langcode =
+	__ATTR_RO(display_name_language_code);
+
+attribute_s_property_show(display_name, integer);
+struct kobj_attribute integer_displ_name =
+	__ATTR_RO(display_name);
+
+attribute_n_property_show(default_value, integer);
+struct kobj_attribute integer_default_val =
+	__ATTR_RO(default_value);
+
+attribute_property_store(current_value, integer);
+struct kobj_attribute integer_current_val =
+	__ATTR_RW(current_value);
+
+attribute_s_property_show(modifier, integer);
+struct kobj_attribute integer_modifier =
+	__ATTR_RO(modifier);
+
+attribute_n_property_show(min_value, integer);
+struct kobj_attribute integer_lower_bound =
+	__ATTR_RO(min_value);
+
+attribute_n_property_show(max_value, integer);
+struct kobj_attribute integer_upper_bound =
+	__ATTR_RO(max_value);
+
+attribute_n_property_show(scalar_increment, integer);
+struct kobj_attribute integer_scalar_increment =
+	__ATTR_RO(scalar_increment);
+
+attribute_s_property_show(type, integer);
+struct kobj_attribute integer_type =
+	__ATTR_RO(type);
+
+static struct attribute *integer_attrs[] = {
+	&integer_displ_langcode.attr,
+	&integer_displ_name.attr,
+	&integer_default_val.attr,
+	&integer_current_val.attr,
+	&integer_modifier.attr,
+	&integer_lower_bound.attr,
+	&integer_upper_bound.attr,
+	&integer_scalar_increment.attr,
+	&integer_type.attr,
+	NULL,
+};
+
+static const struct attribute_group integer_attr_group = {
+	.attrs = integer_attrs,
+};
+
+int alloc_int_data(void)
+{
+	int ret = 0;
+
+	integer_instances_count = get_instance_count(DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
+	integer_data = kzalloc((sizeof(struct integer_data) * integer_instances_count), GFP_KERNEL);
+	if (!integer_data)
+		ret = -ENOMEM;
+	return ret;
+}
+
+/**
+ * populate_int_data() - Populate all properties of an instance under integer attribute
+ * @integer_obj: ACPI object with integer data
+ * @instance_id: The instance to enumerate
+ * @attr_name_kobj: The parent kernel object
+ **/
+int populate_int_data(union acpi_object *integer_obj, int instance_id,
+			struct kobject *attr_name_kobj)
+{
+	int retval = sysfs_create_group(attr_name_kobj, &integer_attr_group);
+
+	if (retval)
+		goto out;
+
+	mutex_lock(&wmi_priv.mutex);
+	strncpy_attr(integer_data[instance_id].attribute_name,
+		integer_obj[ATTR_NAME].string.pointer);
+	strncpy_attr(integer_data[instance_id].display_name_language_code,
+		integer_obj[DISPL_NAME_LANG_CODE].string.pointer);
+	strncpy_attr(integer_data[instance_id].display_name,
+		integer_obj[DISPLAY_NAME].string.pointer);
+	integer_data[instance_id].default_value =
+		(uintptr_t)integer_obj[DEFAULT_VAL].string.pointer;
+	integer_data[instance_id].current_value =
+		(uintptr_t)integer_obj[CURRENT_VAL].string.pointer;
+	strncpy_attr(integer_data[instance_id].modifier, integer_obj[MODIFIER].string.pointer);
+	integer_data[instance_id].min_value =
+		(uintptr_t)integer_obj[MIN_VALUE].string.pointer;
+	integer_data[instance_id].max_value =
+		(uintptr_t)integer_obj[MAX_VALUE].string.pointer;
+	integer_data[instance_id].scalar_increment =
+		(uintptr_t)integer_obj[SCALAR_INCR].string.pointer;
+	strncpy_attr(integer_data[instance_id].type, "integer");
+	mutex_unlock(&wmi_priv.mutex);
+
+out:
+	return retval;
+}
+
+/**
+ * exit_int_attributes() - Clear all attribute data
+ *
+ * Clears all data allocated for this group of attributes
+ **/
+void exit_int_attributes(void)
+{
+	struct kobject *pos, *next;
+
+	list_for_each_entry_safe(pos, next, &wmi_priv.main_dir_kset->list, entry) {
+		/* this removes only integer atribute group under main_dir_kset */
+		sysfs_remove_group(pos, &integer_attr_group);
+	}
+	kfree(integer_data);
+}
diff --git a/drivers/platform/x86/dell-wmi-passobj-attributes.c b/drivers/platform/x86/dell-wmi-passobj-attributes.c
new file mode 100644
index 000000000000..6884e6153dd6
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-passobj-attributes.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Functions corresponding to password object type attributes under BIOS Password Object GUID for
+ * use with dell-wmi-sysman
+ *
+ *  Copyright (c) 2020 Dell Inc.
+ */
+
+#include "dell-wmi-sysman-attributes.h"
+
+enum po_properties {IS_PASS_SET = 1, MIN_PASS_LEN, MAX_PASS_LEN};
+
+/* kept variable names same as in sysfs file name for sysfs_show macro definition */
+struct po_data {
+	char attribute_name[MAX_BUFF];
+	int is_password_set;
+	int min_password_length;
+	int max_password_length;
+	char type[MAX_BUFF];
+};
+
+static struct po_data *po_data;
+static int po_instances_count;
+get_instance_id(po);
+
+static ssize_t is_password_set_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int instance_id = get_po_instance_id(kobj);
+
+	if (instance_id >= 0) {
+		union acpi_object *obj;
+
+		/* need to use specific instance_id and guid combination to get right data */
+		obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
+		if (!obj)
+			return -AE_ERROR;
+		po_data[instance_id].is_password_set =
+			(uintptr_t)obj->package.elements[IS_PASS_SET].string.pointer;
+		kfree(obj);
+		return sprintf(buf, "%d\n", po_data[instance_id].is_password_set);
+	}
+	return -EIO;
+}
+
+struct kobj_attribute po_is_pass_set =
+		__ATTR_RO(is_password_set);
+
+static ssize_t current_password_store(struct kobject *kobj,
+				      struct kobj_attribute *attr,
+				      const char *buf, size_t count)
+{
+	char *p = memchr(buf, '\n', count);
+	int ret;
+
+	if (p != NULL)
+		*p = '\0';
+	if (strlen(buf) > MAX_BUFF)
+		return -EINVAL;
+
+	if (strcmp(kobj->name, "Admin") == 0)
+		strncpy(wmi_priv.current_admin_password, buf, (strlen(buf) + 1));
+	if (strcmp(kobj->name, "System") == 0)
+		strncpy(wmi_priv.current_system_password, buf, (strlen(buf) + 1));
+	return ret ? ret : count;
+}
+
+struct kobj_attribute po_current_password =
+		__ATTR_WO(current_password);
+
+static ssize_t new_password_store(struct kobject *kobj,
+				  struct kobj_attribute *attr,
+				  const char *buf, size_t count)
+{
+	char *p = memchr(buf, '\n', count);
+	int ret;
+
+	if (p != NULL)
+		*p = '\0';
+	if (strlen(buf) > MAX_BUFF)
+		return -EINVAL;
+
+	ret = set_new_password(kobj->name, buf);
+	return ret ? ret : count;
+}
+
+struct kobj_attribute po_new_password =
+		__ATTR_WO(new_password);
+
+attribute_n_property_show(min_password_length, po);
+struct kobj_attribute po_min_pass_length =
+		__ATTR_RO(min_password_length);
+
+attribute_n_property_show(max_password_length, po);
+struct kobj_attribute po_max_pass_length =
+		__ATTR_RO(max_password_length);
+
+attribute_s_property_show(type, po);
+struct kobj_attribute po_type =
+	__ATTR_RO(type);
+
+static struct attribute *po_attrs[] = {
+	&po_is_pass_set.attr,
+	&po_min_pass_length.attr,
+	&po_max_pass_length.attr,
+	&po_current_password.attr,
+	&po_new_password.attr,
+	&po_type.attr,
+	NULL,
+};
+
+static const struct attribute_group po_attr_group = {
+	.attrs = po_attrs,
+};
+
+int alloc_po_data(void)
+{
+	int ret = 0;
+
+	po_instances_count = get_instance_count(DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
+	po_data = kzalloc((sizeof(struct po_data) * po_instances_count), GFP_KERNEL);
+	if (!po_data)
+		ret = -ENOMEM;
+	return ret;
+}
+
+/**
+ * populate_po_data() - Populate all properties of an instance under password object attribute
+ * @po_obj: ACPI object with password object data
+ * @instance_id: The instance to enumerate
+ * @attr_name_kobj: The parent kernel object
+ **/
+int populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject *attr_name_kobj)
+{
+	int retval = sysfs_create_group(attr_name_kobj, &po_attr_group);
+
+	if (retval)
+		goto out;
+
+	mutex_lock(&wmi_priv.mutex);
+	strncpy_attr(po_data[instance_id].attribute_name, po_obj[ATTR_NAME].string.pointer);
+	po_data[instance_id].is_password_set = (uintptr_t)po_obj[IS_PASS_SET].string.pointer;
+	po_data[instance_id].min_password_length = (uintptr_t)po_obj[MIN_PASS_LEN].string.pointer;
+	po_data[instance_id].max_password_length = (uintptr_t) po_obj[MAX_PASS_LEN].string.pointer;
+	strncpy_attr(po_data[instance_id].type, "password_object");
+	mutex_unlock(&wmi_priv.mutex);
+
+out:
+	return retval;
+}
+
+/**
+ * exit_po_attributes() - Clear all attribute data
+ *
+ * Clears all data allocated for this group of attributes
+ **/
+void exit_po_attributes(void)
+{
+	struct kobject *pos, *next;
+
+	list_for_each_entry_safe(pos, next, &wmi_priv.password_dir_kset->list, entry) {
+		/* this removes only enumeration atribute group under main_dir_kset */
+		sysfs_remove_group(pos, &po_attr_group);
+	}
+	kfree(po_data);
+}
diff --git a/drivers/platform/x86/dell-wmi-passwordattr-interface.c b/drivers/platform/x86/dell-wmi-passwordattr-interface.c
new file mode 100644
index 000000000000..bd19d6c15002
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-passwordattr-interface.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Functions corresponding to SET password methods under BIOS attributes interface GUID
+ *
+ *  Copyright (c) 2020 Dell Inc.
+ */
+
+#include <linux/nls.h>
+#include <linux/wmi.h>
+#include "dell-wmi-sysman-attributes.h"
+
+static int call_password_interface(struct wmi_device *wdev, char *in_args, size_t size)
+{
+	struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
+	struct acpi_buffer input;
+	union acpi_object *obj;
+	acpi_status status;
+	int ret = -EIO;
+
+	input.length =  (acpi_size) size;
+	input.pointer = in_args;
+	status = wmidev_evaluate_method(wdev, 0, 1, &input, &output);
+	if (ACPI_FAILURE(status))
+		return -EIO;
+	obj = (union acpi_object *)output.pointer;
+	if (obj->type == ACPI_TYPE_INTEGER)
+		ret = obj->integer.value;
+
+	kfree(output.pointer);
+	/* let userland know it may need to check is_password_set again */
+	kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE);
+	return map_wmi_error(ret);
+}
+
+/**
+ * set_new_password() - Sets a system admin password
+ * @password_type: The type of password to set
+ * @new: The new password
+ *
+ * Sets the password using plaintext interface
+ **/
+int set_new_password(const char *password_type, const char *new)
+{
+	char *current_password, *type_value, *old_value, *new_value;
+	size_t security_area_size, string_area_size, buffer_size;
+	u8 *type_len, *old_len, *new_len;
+	char *buffer = NULL;
+	int ret;
+
+	mutex_lock(&wmi_priv.mutex);
+	if (!wmi_priv.password_attr_wdev) {
+		ret = -ENODEV;
+		goto out;
+	}
+	if (strcmp(password_type, "Admin") == 0) {
+		current_password = wmi_priv.current_admin_password;
+	} else if (strcmp(password_type, "System") == 0) {
+		current_password = wmi_priv.current_system_password;
+	} else {
+		ret = -EINVAL;
+		dev_err(&wmi_priv.password_attr_wdev->dev, "unknown password type %s\n",
+			password_type);
+		goto out;
+	}
+
+	/* build/calculate buffer */
+	security_area_size = calculate_security_buffer();
+	string_area_size = (strlen(password_type) + strlen(current_password) + strlen(new))*2;
+	buffer_size = security_area_size + string_area_size + sizeof(u16) * 3;
+	buffer = kzalloc(buffer_size, GFP_KERNEL);
+	if (!buffer) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/* build security area */
+	if (strlen(wmi_priv.current_admin_password) > 0)
+		populate_security_buffer(buffer, wmi_priv.current_admin_password);
+
+	/* build variables to set */
+	type_len = buffer + security_area_size;
+	type_value = type_len + sizeof(u16);
+	*type_len = utf8s_to_utf16s(password_type, strlen(password_type), UTF16_HOST_ENDIAN,
+				    (wchar_t *) type_value, MAX_BUFF) * 2;
+	if (*type_len < 0) {
+		ret = -EINVAL;
+		dev_err(&wmi_priv.password_attr_wdev->dev, "UTF16 conversion failed\n");
+		goto out;
+	}
+
+	old_len = type_value + *type_len;
+	old_value = old_len + sizeof(u16);
+	*old_len = utf8s_to_utf16s(current_password, strlen(current_password), UTF16_HOST_ENDIAN,
+				   (wchar_t *) old_value, MAX_BUFF) * 2;
+	if (*old_len < 0) {
+		ret = -EINVAL;
+		dev_err(&wmi_priv.password_attr_wdev->dev, "UTF16 conversion failed\n");
+		goto out;
+	}
+
+	new_len = old_value + *old_len;
+	new_value = new_len + sizeof(u16);
+	*new_len = utf8s_to_utf16s(new, strlen(new), UTF16_HOST_ENDIAN,
+				   (wchar_t *) new_value, MAX_BUFF) * 2;
+	if (*new_len < 0) {
+		ret = -EINVAL;
+		dev_err(&wmi_priv.password_attr_wdev->dev, "UTF16 conversion failed\n");
+		goto out;
+	}
+
+	ret = call_password_interface(wmi_priv.password_attr_wdev, buffer, buffer_size);
+	/* clear current_password here and use user input from wmi_priv.current_password */
+	if (!ret)
+		current_password = "";
+	/* explain to user the detailed failure reason */
+	else if (ret == -EOPNOTSUPP)
+		dev_err(&wmi_priv.password_attr_wdev->dev, "admin password must be configured\n");
+	else if (ret == -EACCES)
+		dev_err(&wmi_priv.password_attr_wdev->dev, "invalid password\n");
+
+out:
+	kfree(buffer);
+	mutex_unlock(&wmi_priv.mutex);
+
+	return ret;
+}
+
+static int dell_wmi_bios_attr_pass_interface_probe(struct wmi_device *wdev, const void *context)
+{
+	mutex_lock(&wmi_priv.mutex);
+	wmi_priv.password_attr_wdev = wdev;
+	mutex_unlock(&wmi_priv.mutex);
+	return 0;
+}
+
+static int dell_wmi_bios_attr_pass_interface_remove(struct wmi_device *wdev)
+{
+	mutex_lock(&wmi_priv.mutex);
+	wmi_priv.password_attr_wdev = NULL;
+	mutex_unlock(&wmi_priv.mutex);
+	return 0;
+}
+
+static const struct wmi_device_id dell_wmi_bios_attr_pass_interface_id_table[] = {
+	{ .guid_string = DELL_WMI_BIOS_PASSWORD_INTERFACE_GUID },
+	{ },
+};
+static struct wmi_driver dell_wmi_bios_attr_pass_interface_driver = {
+	.driver = {
+		.name = DRIVER_NAME"-password"
+	},
+	.probe = dell_wmi_bios_attr_pass_interface_probe,
+	.remove = dell_wmi_bios_attr_pass_interface_remove,
+	.id_table = dell_wmi_bios_attr_pass_interface_id_table,
+};
+
+int init_dell_wmi_bios_attr_pass_interface(void)
+{
+	return wmi_driver_register(&dell_wmi_bios_attr_pass_interface_driver);
+}
+
+void exit_dell_wmi_bios_attr_pass_interface(void)
+{
+	wmi_driver_unregister(&dell_wmi_bios_attr_pass_interface_driver);
+}
+
+MODULE_DEVICE_TABLE(wmi, dell_wmi_bios_attr_pass_interface_id_table);
diff --git a/drivers/platform/x86/dell-wmi-string-attributes.c b/drivers/platform/x86/dell-wmi-string-attributes.c
new file mode 100644
index 000000000000..edc6f461e37f
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-string-attributes.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Functions corresponding to string type attributes under BIOS String GUID for use with
+ * dell-wmi-sysman
+ *
+ *  Copyright (c) 2020 Dell Inc.
+ */
+
+#include "dell-wmi-sysman-attributes.h"
+
+enum string_properties {MIN_LEN = 6, MAX_LEN};
+
+/* kept variable names same as in sysfs file name for sysfs_show macro definition */
+struct str_data {
+	char display_name_language_code[MAX_BUFF];
+	char attribute_name[MAX_BUFF];
+	char display_name[MAX_BUFF];
+	char default_value[MAX_BUFF];
+	char current_value[MAX_BUFF];
+	char modifier[MAX_BUFF];
+	int min_length;
+	int max_length;
+	char type[MAX_BUFF];
+};
+
+static struct str_data *str_data;
+static int str_instances_count;
+get_instance_id(str);
+
+static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int instance_id;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	instance_id = get_str_instance_id(kobj);
+	if (instance_id >= 0) {
+		union acpi_object *obj;
+
+		/* need to use specific instance_id and guid combination to get right data */
+		obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
+		if (!obj)
+			return -AE_ERROR;
+		strncpy_attr(str_data[instance_id].current_value,
+			obj->package.elements[CURRENT_VAL].string.pointer);
+		kfree(obj);
+		return sprintf(buf, "%s\n", str_data[instance_id].current_value);
+	}
+	return -EIO;
+}
+
+/**
+ * validate_str_input() - Validate input of current_value against min and max lengths
+ * @instance_id: The instance on which input is validated
+ * @buf: Input value
+ **/
+int validate_str_input(int instance_id, const char *buf)
+{
+	int in_len = strlen(buf);
+
+	if ((in_len >= str_data[instance_id].min_length) &&
+	(in_len <= str_data[instance_id].max_length))
+		return 0;
+
+	return -EINVAL;
+}
+
+attribute_s_property_show(display_name_language_code, str);
+static struct kobj_attribute str_displ_langcode =
+		__ATTR_RO(display_name_language_code);
+
+attribute_s_property_show(display_name, str);
+struct kobj_attribute str_displ_name =
+		__ATTR_RO(display_name);
+
+attribute_s_property_show(default_value, str);
+struct kobj_attribute str_default_val =
+		__ATTR_RO(default_value);
+
+attribute_property_store(current_value, str);
+struct kobj_attribute str_current_val =
+		__ATTR_RW(current_value);
+
+attribute_s_property_show(modifier, str);
+struct kobj_attribute str_modifier =
+		__ATTR_RO(modifier);
+
+attribute_n_property_show(min_length, str);
+struct kobj_attribute str_min_length =
+		__ATTR_RO(min_length);
+
+attribute_n_property_show(max_length, str);
+struct kobj_attribute str_max_length =
+		__ATTR_RO(max_length);
+
+attribute_s_property_show(type, str);
+struct kobj_attribute str_type =
+	__ATTR_RO(type);
+
+static struct attribute *str_attrs[] = {
+	&str_displ_langcode.attr,
+	&str_displ_name.attr,
+	&str_default_val.attr,
+	&str_current_val.attr,
+	&str_modifier.attr,
+	&str_min_length.attr,
+	&str_max_length.attr,
+	&str_type.attr,
+	NULL,
+};
+
+static const struct attribute_group str_attr_group = {
+	.attrs = str_attrs,
+};
+
+int alloc_str_data(void)
+{
+	int ret = 0;
+
+	str_instances_count = get_instance_count(DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
+	str_data = kzalloc((sizeof(struct str_data) * str_instances_count), GFP_KERNEL);
+	if (!str_data)
+		ret = -ENOMEM;
+	return ret;
+}
+
+/**
+ * populate_str_data() - Populate all properties of an instance under string attribute
+ * @str_obj: ACPI object with integer data
+ * @instance_id: The instance to enumerate
+ * @attr_name_kobj: The parent kernel object
+ **/
+int populate_str_data(union acpi_object *str_obj, int instance_id, struct kobject *attr_name_kobj)
+{
+	int retval = sysfs_create_group(attr_name_kobj, &str_attr_group);
+
+	if (retval)
+		goto out;
+
+	mutex_lock(&wmi_priv.mutex);
+	strncpy_attr(str_data[instance_id].attribute_name, str_obj[ATTR_NAME].string.pointer);
+	strncpy_attr(str_data[instance_id].display_name_language_code,
+		str_obj[DISPL_NAME_LANG_CODE].string.pointer);
+	strncpy_attr(str_data[instance_id].display_name, str_obj[DISPLAY_NAME].string.pointer);
+	strncpy_attr(str_data[instance_id].default_value, str_obj[DEFAULT_VAL].string.pointer);
+	strncpy_attr(str_data[instance_id].current_value, str_obj[CURRENT_VAL].string.pointer);
+	strncpy_attr(str_data[instance_id].modifier, str_obj[MODIFIER].string.pointer);
+	str_data[instance_id].min_length = (uintptr_t)str_obj[MIN_LEN].string.pointer;
+	str_data[instance_id].max_length = (uintptr_t) str_obj[MAX_LEN].string.pointer;
+	strncpy_attr(str_data[instance_id].type, "string");
+	mutex_unlock(&wmi_priv.mutex);
+
+out:
+	return retval;
+}
+
+/**
+ * exit_str_attributes() - Clear all attribute data
+ *
+ * Clears all data allocated for this group of attributes
+ **/
+void exit_str_attributes(void)
+{
+	struct kobject *pos, *next;
+
+	list_for_each_entry_safe(pos, next, &wmi_priv.main_dir_kset->list, entry) {
+		/* this removes only string atribute group under main_dir_kset */
+		sysfs_remove_group(pos, &str_attr_group);
+	}
+	kfree(str_data);
+}
diff --git a/drivers/platform/x86/dell-wmi-sysman-attributes.c b/drivers/platform/x86/dell-wmi-sysman-attributes.c
new file mode 100644
index 000000000000..4a44ffff03c7
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-sysman-attributes.c
@@ -0,0 +1,589 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Common methods for use with dell-wmi-sysman
+ *
+ *  Copyright (c) 2020 Dell Inc.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/dmi.h>
+#include <linux/wmi.h>
+#include "dell-wmi-sysman-attributes.h"
+
+#define MAX_TYPES  4
+
+static struct platform_device *platform_device;
+
+static struct platform_driver platform_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+	},
+};
+
+struct dell_wmi_sysman_priv wmi_priv = {
+	.mutex = __MUTEX_INITIALIZER(wmi_priv.mutex),
+};
+
+/* reset bios to defaults */
+static const char * const reset_types[] = {"builtinsafe", "lastknowngood", "factory", "custom"};
+static int reset_option = -1;
+
+/**
+ * calculate_security_buffer() - determines size of security buffer for authentication scheme
+ *
+ * Currently only supported type is Admin password
+ **/
+size_t calculate_security_buffer(void)
+{
+	if (strlen(wmi_priv.current_admin_password) > 0) {
+		return (sizeof(u32) * 2) +
+			strlen(wmi_priv.current_admin_password) +
+			strlen(wmi_priv.current_admin_password) % 2;
+	}
+	return sizeof(u32) * 2;
+}
+
+/**
+ * populate_security_buffer() - builds a security buffer for authentication scheme
+ * @buffer: the buffer to populate
+ * @authentication: the authentication content
+ *
+ * Currently only supported type is PLAIN TEXT
+ **/
+void populate_security_buffer(char *buffer, char *authentication)
+{
+	char *auth = buffer + sizeof(u32)*2;
+	u32 *sectype = (u32 *) buffer;
+	u32 *seclen = sectype + 1;
+	/* plain text */
+	*sectype = 1;
+	*seclen = strlen(authentication);
+	strncpy(auth, authentication, *seclen);
+}
+
+/**
+ * map_wmi_error() - map errors from WMI methods to kernel error codes
+ **/
+int map_wmi_error(int error_code)
+{
+	switch (error_code) {
+	case 0:
+		/* success */
+		return 0;
+	case 1:
+		/* failed */
+		return -EIO;
+	case 2:
+		/* invalid parameter */
+		return -EINVAL;
+	case 3:
+		/* access denied */
+		return -EACCES;
+	case 4:
+		/* not supported */
+		return -EOPNOTSUPP;
+	case 5:
+		/* memory error */
+		return -ENOMEM;
+	case 6:
+		/* protocol error */
+		return -EPROTO;
+	}
+	/* unspecified error */
+	return -EIO;
+}
+
+/**
+ * reset_bios_show() - sysfs implementaton for read reset_bios
+ * @kobj: Kernel object for this attribute
+ * @attr: Kernel object attribute
+ * @buf: The buffer to display to userspace
+ **/
+static ssize_t reset_bios_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	char *start = buf;
+	int i;
+
+	for (i = 0; i < MAX_TYPES; i++) {
+		if (i == reset_option)
+			buf += sprintf(buf, "[%s] ", reset_types[i]);
+		else
+			buf += sprintf(buf, "%s ", reset_types[i]);
+	}
+	buf += sprintf(buf, "\n");
+	return buf-start;
+}
+
+/**
+ * reset_bios_store() - sysfs implementaton for write reset_bios
+ * @kobj: Kernel object for this attribute
+ * @attr: Kernel object attribute
+ * @buf: The buffer from userspace
+ * @count: the size of the buffer from userspace
+ **/
+static ssize_t reset_bios_store(struct kobject *kobj,
+				struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int len, ret, i;
+	int type = -1;
+	char *p;
+
+	p = memchr(buf, '\n', count);
+	if (p != NULL)
+		*p = '\0';
+	len = p ? p - buf : count;
+
+	for (i = 0; i < MAX_TYPES; i++) {
+		if (len == strlen(reset_types[i])
+		    && !strncmp(buf, reset_types[i], len)) {
+			type = i;
+			break;
+		}
+	}
+
+	if (type < 0 || type >= MAX_TYPES) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = set_bios_defaults(type);
+	dev_dbg(&platform_device->dev, "reset all attributes request type %d: %d\n", type, ret);
+	if (ret) {
+		ret = -EINVAL;
+	} else {
+		reset_option = type;
+		ret = count;
+	}
+
+out:
+	return ret;
+}
+
+/**
+ * pending_reboot_show() - sysfs implementaton for read pending_reboot
+ * @kobj: Kernel object for this attribute
+ * @attr: Kernel object attribute
+ * @buf: The buffer to display to userspace
+ *
+ * Stores default value as 0
+ * When current_value is changed this attribute is set to 1 to notify reboot may be required
+ **/
+static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *attr,
+				   char *buf)
+{
+	return sprintf(buf, "%d\n", wmi_priv.pending_changes);
+}
+
+static struct kobj_attribute reset_bios = __ATTR_RW(reset_bios);
+static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
+
+
+/**
+ * create_reset_bios() - Creates reset_bios and pending_reboot attributes
+ **/
+static int create_reset_bios(void)
+{
+	int ret = sysfs_create_file(&wmi_priv.main_dir_kset->kobj, &reset_bios.attr);
+
+	if (ret) {
+		dev_dbg(&platform_device->dev, "could not create reset_bios file\n");
+		return ret;
+	}
+
+	ret = sysfs_create_file(&wmi_priv.main_dir_kset->kobj, &pending_reboot.attr);
+	if (ret) {
+		dev_dbg(&platform_device->dev, "could not create changing_pending_reboot file\n");
+		sysfs_remove_file(&wmi_priv.main_dir_kset->kobj, &reset_bios.attr);
+	}
+	return ret;
+}
+
+static void release_reset_bios_data(void)
+{
+	sysfs_remove_file(&wmi_priv.main_dir_kset->kobj, &reset_bios.attr);
+	sysfs_remove_file(&wmi_priv.main_dir_kset->kobj, &pending_reboot.attr);
+}
+
+static ssize_t wmi_sysman_attr_show(struct kobject *kobj, struct attribute *attr,
+				    char *buf)
+{
+	struct kobj_attribute *kattr;
+	ssize_t ret = -EIO;
+
+	kattr = container_of(attr, struct kobj_attribute, attr);
+	if (kattr->show)
+		ret = kattr->show(kobj, kattr, buf);
+	return ret;
+}
+
+static ssize_t wmi_sysman_attr_store(struct kobject *kobj, struct attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct kobj_attribute *kattr;
+	ssize_t ret = -EIO;
+
+	kattr = container_of(attr, struct kobj_attribute, attr);
+	if (kattr->store)
+		ret = kattr->store(kobj, kattr, buf, count);
+	return ret;
+}
+
+const struct sysfs_ops wmi_sysman_kobj_sysfs_ops = {
+	.show	= wmi_sysman_attr_show,
+	.store	= wmi_sysman_attr_store,
+};
+
+static void attr_name_release(struct kobject *kobj)
+{
+	kfree(kobj);
+}
+
+static struct kobj_type attr_name_ktype = {
+	.release	= attr_name_release,
+	.sysfs_ops	= &wmi_sysman_kobj_sysfs_ops,
+};
+
+/**
+ * strncpy_attr - Copy a length-limited, NULL-terminated string with bound checks
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ **/
+void strncpy_attr(char *dest, char *src)
+{
+	size_t len = strlen(src) + 1;
+
+	if (len > 1 && len < MAX_BUFF)
+		strncpy(dest, src, len);
+}
+
+/**
+ * get_wmiobj_pointer() - Get Content of WMI block for particular instance
+ * @instance_id: WMI instance ID
+ * @guid_string: WMI GUID (in str form)
+ *
+ * Fetches the content for WMI block (instance_id) under GUID (guid_string)
+ * Caller must kfree the return
+ **/
+union acpi_object *get_wmiobj_pointer(int instance_id, const char *guid_string)
+{
+	struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
+	acpi_status status;
+
+	status = wmi_query_block(guid_string, instance_id, &out);
+
+	return ACPI_SUCCESS(status) ? (union acpi_object *)out.pointer : NULL;
+}
+
+/**
+ * get_instance_count() - Compute total number of instances under guid_string
+ * @guid_string: WMI GUID (in string form)
+ **/
+int get_instance_count(const char *guid_string)
+{
+	union acpi_object *wmi_obj = NULL;
+	int i = 0;
+
+	do {
+		kfree(wmi_obj);
+		wmi_obj = get_wmiobj_pointer(i, guid_string);
+		i++;
+	} while (wmi_obj);
+
+	return (i-1);
+}
+
+/**
+ * alloc_attributes_data() - Allocate attributes data for a particular type
+ * @attr_type: Attribute type to allocate
+ **/
+static int alloc_attributes_data(int attr_type)
+{
+	int retval = 0;
+
+	switch (attr_type) {
+	case ENUM:
+		retval = alloc_enum_data();
+		break;
+	case INT:
+		retval = alloc_int_data();
+		break;
+	case STR:
+		retval = alloc_str_data();
+		break;
+	case PO:
+		retval = alloc_po_data();
+		break;
+	default:
+		break;
+	}
+
+	return retval;
+}
+
+/**
+ * destroy_attribute_objs() - Free a kset of kobjects
+ * @kset: The kset to destroy
+ *
+ * Fress kobjects created for each attribute_name under attribute type kset
+ **/
+static void destroy_attribute_objs(struct kset *kset)
+{
+	struct kobject *pos, *next;
+
+	list_for_each_entry_safe(pos, next, &kset->list, entry) {
+		kobject_put(pos);
+	}
+}
+
+/**
+ * release_attributes_data() - Clean-up all sysfs directories and files created
+ **/
+static void release_attributes_data(void)
+{
+	release_reset_bios_data();
+
+	mutex_lock(&wmi_priv.mutex);
+	exit_enum_attributes();
+	exit_int_attributes();
+	exit_str_attributes();
+	exit_po_attributes();
+	destroy_attribute_objs(wmi_priv.main_dir_kset);
+	destroy_attribute_objs(wmi_priv.password_dir_kset);
+	kset_unregister(wmi_priv.main_dir_kset);
+	kset_unregister(wmi_priv.password_dir_kset);
+	mutex_unlock(&wmi_priv.mutex);
+
+}
+
+/**
+ * init_bios_attributes() - Initialize all attributes for a type
+ * @attr_type: The attribute type to initialize
+ * @guid: The WMI GUID associated with this type to initialize
+ *
+ * Initialiaze all 4 types of attributes enumeration, integer, string and password object.
+ * Populates each attrbute typ's respective properties under sysfs files
+ **/
+static int init_bios_attributes(int attr_type, const char *guid)
+{
+	struct kobject *attr_name_kobj; //individual attribute names
+	union acpi_object *obj = NULL;
+	union acpi_object *elements;
+	struct kset *tmp_set;
+	
+	/* instance_id needs to be reset for each type GUID
+	 * also, instance IDs are unique within GUID but not across
+	 */
+	int instance_id = 0;
+	int retval = 0;
+
+	retval = alloc_attributes_data(attr_type);
+	if (retval)
+		return retval;
+	/* need to use specific instance_id and guid combination to get right data */
+	obj = get_wmiobj_pointer(instance_id, guid);
+	if (!obj)
+		return -ENODEV;
+	elements = obj->package.elements;
+
+	while (elements) {
+		/* sanity checking */
+		if (strlen(elements[ATTR_NAME].string.pointer) == 0) {
+			dev_dbg(&platform_device->dev, "empty attribute found\n");
+			goto nextobj;
+		}
+		if (attr_type == PO)
+			tmp_set = wmi_priv.password_dir_kset;
+		else
+			tmp_set = wmi_priv.main_dir_kset;
+
+		if (kset_find_obj(tmp_set, elements[ATTR_NAME].string.pointer)) {
+			dev_dbg(&platform_device->dev, "duplicate attribute name found - %s\n",
+				elements[ATTR_NAME].string.pointer);
+			goto nextobj;
+		}
+
+		/* build attribute */
+		attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL);
+		if (!attr_name_kobj)
+			goto err_attr_init;
+
+		attr_name_kobj->kset = tmp_set;
+
+		retval = kobject_init_and_add(attr_name_kobj, &attr_name_ktype, NULL, "%s",
+						elements[ATTR_NAME].string.pointer);
+		if (retval) {
+			kobject_put(attr_name_kobj);
+			goto err_attr_init;
+		}
+
+		/* enumerate all of this attribute */
+		switch (attr_type) {
+		case ENUM:
+			retval = populate_enum_data(elements, instance_id, attr_name_kobj);
+			break;
+		case INT:
+			retval = populate_int_data(elements, instance_id, attr_name_kobj);
+			break;
+		case STR:
+			retval = populate_str_data(elements, instance_id, attr_name_kobj);
+			break;
+		case PO:
+			retval = populate_po_data(elements, instance_id, attr_name_kobj);
+			break;
+		default:
+			break;
+		}
+
+		if (retval) {
+			dev_dbg(&platform_device->dev, "failed to populate %s\n",
+				elements[ATTR_NAME].string.pointer);
+			goto err_attr_init;
+		}
+
+nextobj:
+		kfree(obj);
+		instance_id++;
+		obj = get_wmiobj_pointer(instance_id, guid);
+		elements = obj ? obj->package.elements : NULL;
+	}
+
+	goto out;
+
+err_attr_init:
+	release_attributes_data();
+	kfree(obj);
+out:
+	return retval;
+}
+
+static int __init init_dell_bios_attrib_wmi(void)
+{
+	int ret = 0;
+
+	if (!dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL) &&
+	    !dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "www.dell.com", NULL)) {
+		pr_err("Unable to run on non-Dell system\n");
+		return -ENODEV;
+	}
+
+	ret = init_dell_wmi_bios_attr_set_interface();
+	if (ret || !wmi_priv.bios_attr_wdev) {
+		pr_debug("failed to initialize set interface\n");
+		goto fail_set_interface;
+	}
+
+	ret = init_dell_wmi_bios_attr_pass_interface();
+	if (ret || !wmi_priv.password_attr_wdev) {
+		pr_debug("failed to initialize pass interface\n");
+		goto fail_pass_interface;
+	}
+
+	ret = platform_driver_register(&platform_driver);
+	if (ret)
+		goto fail_platform_driver;
+
+	platform_device = platform_device_alloc(DRIVER_NAME, -1);
+	if (!platform_device) {
+		ret = -ENOMEM;
+		goto fail_platform_device_alloc;
+	}
+
+	ret = platform_device_add(platform_device);
+	if (ret)
+		goto fail_platform_device_add;
+
+	wmi_priv.main_dir_kset = kset_create_and_add("attributes", NULL,
+											&platform_device->dev.kobj);
+	if (!wmi_priv.main_dir_kset) {
+		ret = -ENOMEM;
+		goto fail_platform_device_add;
+	}
+
+	wmi_priv.password_dir_kset = kset_create_and_add("passwords", NULL,
+												&platform_device->dev.kobj);
+	if (!wmi_priv.password_dir_kset) {
+		ret = -ENOMEM;
+		goto fail_main_kset;
+	}
+
+	ret = create_reset_bios();
+	if (ret) {
+		dev_dbg(&platform_device->dev, "could not create reset BIOS attribute\n");
+		goto fail_password_kset;
+	}
+
+	ret = init_bios_attributes(ENUM, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
+	if (ret) {
+		dev_dbg(&platform_device->dev, "failed to populate enumeration type attributes\n");
+		goto fail_create_group;
+	}
+
+	ret = init_bios_attributes(INT, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
+	if (ret) {
+		dev_dbg(&platform_device->dev, "failed to populate integer type attributes\n");
+		goto fail_create_group;
+	}
+
+	ret = init_bios_attributes(STR, DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
+	if (ret) {
+		dev_dbg(&platform_device->dev, "failed to populate string type attributes\n");
+		goto fail_create_group;
+	}
+
+	ret = init_bios_attributes(PO, DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
+	if (ret) {
+		dev_dbg(&platform_device->dev, "failed to populate pass object type attributes\n");
+		goto fail_create_group;
+	}
+
+	return 0;
+
+fail_create_group:
+	release_attributes_data();
+	platform_device_del(platform_device);
+
+fail_password_kset:
+	kset_unregister(wmi_priv.password_dir_kset);
+
+fail_main_kset:
+	kset_unregister(wmi_priv.main_dir_kset);
+
+fail_platform_device_add:
+	platform_device_put(platform_device);
+
+fail_platform_device_alloc:
+	platform_driver_unregister(&platform_driver);
+
+fail_platform_driver:
+	exit_dell_wmi_bios_attr_pass_interface();
+
+fail_pass_interface:
+	exit_dell_wmi_bios_attr_set_interface();
+
+fail_set_interface:
+	return ret;
+}
+
+static void __exit exit_dell_bios_attrib_wmi(void)
+{
+	release_attributes_data();
+	exit_dell_wmi_bios_attr_set_interface();
+	exit_dell_wmi_bios_attr_pass_interface();
+	if (platform_device) {
+		platform_device_unregister(platform_device);
+		platform_driver_unregister(&platform_driver);
+	}
+}
+
+module_init(init_dell_bios_attrib_wmi);
+module_exit(exit_dell_bios_attrib_wmi);
+
+MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
+MODULE_AUTHOR("Prasanth Ksr <prasanth.ksr@dell.com>");
+MODULE_AUTHOR("Divya Bharathi <divya.bharathi@dell.com>");
+MODULE_DESCRIPTION("Dell platform setting control interface");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/dell-wmi-sysman-attributes.h b/drivers/platform/x86/dell-wmi-sysman-attributes.h
new file mode 100644
index 000000000000..cc66c120de6d
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-sysman-attributes.h
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Definitions for kernel modules using Dell WMI System Management Driver
+ *
+ *  Copyright (c) 2020 Dell Inc.
+ */
+
+#ifndef _DELL_WMI_BIOS_ATTR_H_
+#define _DELL_WMI_BIOS_ATTR_H_
+
+#include <linux/wmi.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/capability.h>
+
+#define DRIVER_NAME					"dell-wmi-sysman"
+#define MAX_BUFF  512
+
+#define DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID	"F1DDEE52-063C-4784-A11E-8A06684B9BF5"
+#define DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID		"F1DDEE52-063C-4784-A11E-8A06684B9BFA"
+#define DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID		"F1DDEE52-063C-4784-A11E-8A06684B9BF9"
+#define DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID		"0894B8D6-44A6-4719-97D7-6AD24108BFD4"
+#define DELL_WMI_BIOS_ATTRIBUTES_INTERFACE_GUID		"F1DDEE52-063C-4784-A11E-8A06684B9BF4"
+#define DELL_WMI_BIOS_PASSWORD_INTERFACE_GUID		"70FE8229-D03B-4214-A1C6-1F884B1A892A"
+
+struct dell_wmi_sysman_priv {
+	char current_admin_password[MAX_BUFF];
+	char current_system_password[MAX_BUFF];
+	struct wmi_device *password_attr_wdev;
+	struct wmi_device *bios_attr_wdev;
+	bool pending_changes;
+	struct mutex mutex;
+	struct kset *main_dir_kset;
+	struct kset *password_dir_kset;
+};
+
+/* global structure used by multiple WMI interfaces */
+extern struct dell_wmi_sysman_priv wmi_priv;
+
+enum { ENUM, INT, STR, PO };
+
+enum {
+	ATTR_NAME,
+	DISPL_NAME_LANG_CODE,
+	DISPLAY_NAME,
+	DEFAULT_VAL,
+	CURRENT_VAL,
+	MODIFIER
+};
+
+#define get_instance_id(type)							\
+int get_##type##_instance_id(struct kobject *kobj)				\
+{										\
+	int i;									\
+	for (i = 0; i <= type##_instances_count; i++) {				\
+		if (!(strcmp(kobj->name, type##_data[i].attribute_name)))	\
+			return i;						\
+	}									\
+	return -EIO;								\
+}
+
+#define attribute_s_property_show(name, type)					\
+static ssize_t name##_show(struct kobject *kobj, struct kobj_attribute *attr,	\
+			   char *buf)						\
+{										\
+	int i = get_##type##_instance_id(kobj);					\
+	if (i >= 0)								\
+		return sprintf(buf, "%s\n", type##_data[i].name);		\
+	return 0;								\
+}
+
+#define attribute_n_property_show(name, type)					\
+static ssize_t name##_show(struct kobject *kobj, struct kobj_attribute *attr,	\
+			   char *buf)						\
+{										\
+	int i = get_##type##_instance_id(kobj);					\
+	if (i >= 0)								\
+		return sprintf(buf, "%d\n", type##_data[i].name);		\
+	return 0;								\
+}
+
+#define attribute_property_store(curr_val, type)				\
+static ssize_t curr_val##_store(struct kobject *kobj,				\
+				struct kobj_attribute *attr,			\
+				const char *buf, size_t count)			\
+{										\
+	char *p = memchr(buf, '\n', count);					\
+	int ret = -EIO;								\
+	int i;									\
+										\
+	if (p != NULL)								\
+		*p = '\0';							\
+	i = get_##type##_instance_id(kobj);					\
+	if (i >= 0)								\
+		ret = validate_##type##_input(i, buf);				\
+	if (!ret)								\
+		ret = set_attribute(kobj->name, buf);				\
+	return ret ? ret : count;						\
+}
+
+union acpi_object *get_wmiobj_pointer(int instance_id, const char *guid_string);
+int get_instance_count(const char *guid_string);
+void strncpy_attr(char *dest, char *src);
+
+int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
+			struct kobject *attr_name_kobj);
+int alloc_enum_data(void);
+void exit_enum_attributes(void);
+
+int populate_int_data(union acpi_object *integer_obj, int instance_id,
+			struct kobject *attr_name_kobj);
+int alloc_int_data(void);
+void exit_int_attributes(void);
+
+int populate_str_data(union acpi_object *str_obj, int instance_id, struct kobject *attr_name_kobj);
+int alloc_str_data(void);
+void exit_str_attributes(void);
+
+int populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject *attr_name_kobj);
+int alloc_po_data(void);
+void exit_po_attributes(void);
+
+int set_attribute(const char *a_name, const char *a_value);
+int set_bios_defaults(u8 defType);
+
+void exit_dell_wmi_bios_attr_set_interface(void);
+int init_dell_wmi_bios_attr_set_interface(void);
+int map_wmi_error(int error_code);
+size_t calculate_security_buffer(void);
+void populate_security_buffer(char *buffer, char *authentication);
+
+int set_new_password(const char *password_type, const char *new);
+int init_dell_wmi_bios_attr_pass_interface(void);
+void exit_dell_wmi_bios_attr_pass_interface(void);
+
+#endif
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v3] Introduce support for Systems Management Driver over WMI for Dell Systems
  2020-09-17  6:55 [PATCH v3] Introduce support for Systems Management Driver over WMI for Dell Systems Divya Bharathi
@ 2020-09-17 12:01 ` kernel test robot
  2020-09-21 10:57 ` Hans de Goede
  2020-09-21 11:38 ` Hans de Goede
  2 siblings, 0 replies; 8+ messages in thread
From: kernel test robot @ 2020-09-17 12:01 UTC (permalink / raw)
  To: Divya Bharathi, dvhart
  Cc: kbuild-all, LKML, platform-driver-x86, Divya Bharathi,
	Hans de Goede, Andy Shevchenko, mark gross, Mario Limonciello,
	Prasanth KSR

[-- Attachment #1: Type: text/plain, Size: 4561 bytes --]

Hi Divya,

I love your patch! Perhaps something to improve:

[auto build test WARNING on linux/master]
[also build test WARNING on linus/master v5.9-rc5 next-20200916]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Divya-Bharathi/Introduce-support-for-Systems-Management-Driver-over-WMI-for-Dell-Systems/20200917-145838
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git bcf876870b95592b52519ed4aafcf9d95999bc9c
config: x86_64-allyesconfig (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0
reproduce (this is a W=1 build):
        # save the attached .config to linux build tree
        make W=1 ARCH=x86_64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from drivers/platform/x86/dell-wmi-enum-attributes.c:9:
>> drivers/platform/x86/dell-wmi-sysman-attributes.h:53:5: warning: no previous prototype for 'get_enumeration_instance_id' [-Wmissing-prototypes]
      53 | int get_##type##_instance_id(struct kobject *kobj)    \
         |     ^~~~
   drivers/platform/x86/dell-wmi-enum-attributes.c:28:1: note: in expansion of macro 'get_instance_id'
      28 | get_instance_id(enumeration);
         | ^~~~~~~~~~~~~~~
>> drivers/platform/x86/dell-wmi-enum-attributes.c:57:5: warning: no previous prototype for 'validate_enumeration_input' [-Wmissing-prototypes]
      57 | int validate_enumeration_input(int instance_id, const char *buf)
         |     ^~~~~~~~~~~~~~~~~~~~~~~~~~
--
   In file included from drivers/platform/x86/dell-wmi-int-attributes.c:9:
>> drivers/platform/x86/dell-wmi-sysman-attributes.h:53:5: warning: no previous prototype for 'get_integer_instance_id' [-Wmissing-prototypes]
      53 | int get_##type##_instance_id(struct kobject *kobj)    \
         |     ^~~~
   drivers/platform/x86/dell-wmi-int-attributes.c:29:1: note: in expansion of macro 'get_instance_id'
      29 | get_instance_id(integer);
         | ^~~~~~~~~~~~~~~
>> drivers/platform/x86/dell-wmi-int-attributes.c:58:5: warning: no previous prototype for 'validate_integer_input' [-Wmissing-prototypes]
      58 | int validate_integer_input(int instance_id, const char *buf)
         |     ^~~~~~~~~~~~~~~~~~~~~~
--
   In file included from drivers/platform/x86/dell-wmi-string-attributes.c:9:
>> drivers/platform/x86/dell-wmi-sysman-attributes.h:53:5: warning: no previous prototype for 'get_str_instance_id' [-Wmissing-prototypes]
      53 | int get_##type##_instance_id(struct kobject *kobj)    \
         |     ^~~~
   drivers/platform/x86/dell-wmi-string-attributes.c:28:1: note: in expansion of macro 'get_instance_id'
      28 | get_instance_id(str);
         | ^~~~~~~~~~~~~~~
>> drivers/platform/x86/dell-wmi-string-attributes.c:57:5: warning: no previous prototype for 'validate_str_input' [-Wmissing-prototypes]
      57 | int validate_str_input(int instance_id, const char *buf)
         |     ^~~~~~~~~~~~~~~~~~
--
   In file included from drivers/platform/x86/dell-wmi-passobj-attributes.c:9:
>> drivers/platform/x86/dell-wmi-sysman-attributes.h:53:5: warning: no previous prototype for 'get_po_instance_id' [-Wmissing-prototypes]
      53 | int get_##type##_instance_id(struct kobject *kobj)    \
         |     ^~~~
   drivers/platform/x86/dell-wmi-passobj-attributes.c:24:1: note: in expansion of macro 'get_instance_id'
      24 | get_instance_id(po);
         | ^~~~~~~~~~~~~~~

# https://github.com/0day-ci/linux/commit/4809f4528720c1aa027b717b66960848bdae7b58
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Divya-Bharathi/Introduce-support-for-Systems-Management-Driver-over-WMI-for-Dell-Systems/20200917-145838
git checkout 4809f4528720c1aa027b717b66960848bdae7b58
vim +/get_enumeration_instance_id +53 drivers/platform/x86/dell-wmi-sysman-attributes.h

    51	
    52	#define get_instance_id(type)							\
  > 53	int get_##type##_instance_id(struct kobject *kobj)				\
    54	{										\
    55		int i;									\
    56		for (i = 0; i <= type##_instances_count; i++) {				\
    57			if (!(strcmp(kobj->name, type##_data[i].attribute_name)))	\
    58				return i;						\
    59		}									\
    60		return -EIO;								\
    61	}
    62	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 75082 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v3] Introduce support for Systems Management Driver over WMI for Dell Systems
  2020-09-17  6:55 [PATCH v3] Introduce support for Systems Management Driver over WMI for Dell Systems Divya Bharathi
  2020-09-17 12:01 ` kernel test robot
@ 2020-09-21 10:57 ` Hans de Goede
  2020-09-21 18:23   ` Limonciello, Mario
  2020-09-21 11:38 ` Hans de Goede
  2 siblings, 1 reply; 8+ messages in thread
From: Hans de Goede @ 2020-09-21 10:57 UTC (permalink / raw)
  To: Divya Bharathi, dvhart
  Cc: LKML, platform-driver-x86, Divya Bharathi, Andy Shevchenko,
	mark gross, Mario Limonciello, Prasanth KSR

Hi,

As usual, first a review of the userspace API.

Note the biggest pending issue with the userspace API is if
we are going to keep this under /sys/devices/platform/dell-wmi-sysman/
or if we are going to have it under:

/sys/class/firmware-attributes/dell-wmi-sysman/

That is still being discussed in the v1 thread.

On 9/17/20 8:55 AM, Divya Bharathi wrote:
> The Dell WMI Systems Management Driver provides a sysfs
> interface for systems management to enable BIOS configuration
> capability on certain Dell Systems.
> 
> This driver allows user to configure Dell systems with a
> uniform common interface. To facilitate this, the patch
> introduces a generic way for driver to be able to create
> configurable BIOS Attributes available in Setup (F2) screen.
> 
> Cc: Hans de Goede <hdegoede@redhat.com>
> Cc: Andy Shevchenko <andy.shevchenko@gmail.com>
> Cc: mark gross <mgross@linux.intel.com>
> 
> Co-developed-by: Mario Limonciello <mario.limonciello@dell.com>
> Signed-off-by: Mario Limonciello <mario.limonciello@dell.com>
> Co-developed-by: Prasanth KSR <prasanth.ksr@dell.com>
> Signed-off-by: Prasanth KSR <prasanth.ksr@dell.com>
> Signed-off-by: Divya Bharathi <divya_bharathi@dell.com>
> ---
> 
> Changes from v2 to v3:
>   - Fix a possible NULL pointer error in init
>   - Add missing newlines to all dev_err/dev_dbg/pr_err/pr_debug statements
>   - Correct updating passwords when both Admin and System password are set
>   - Correct the WMI driver name
>   - Correct some namespace clashing when compiled into the kernel (Reported by Mark Gross)
>   - Correct some comment typos
>   - Adopt suggestions made by Hans:
>     + Use single global mutex
>     + Clarify reason for uevents with a comment
>     + Remove functions for set and get current password
>     + Rename lower_bound to min_value and upper_bound to max_value
>     + Rename possible_value to possible_values
>     + Remove references to float
>     + Build a separate passwords directory again since it behaves differently from the other
>       attributes
>     + Move more calls from pr_err -> dev_err
>   - Documentation cleanups (see v2 patch feedback)
>     + Grouping types
>     + Syntax of `modifier` output
> 
> Changes from v1 to v2:
>   - use pr_fmt instead of pr_err(DRIVER_NAME
>   - re-order variables reverse xmas tree order
>   - correct returns of -1 to error codes
>   - correct usage of {} on some split line statements
>   - Refine all documentation deficiencies suggested by Hans
>   - Merge all attributes to a single directory
>   - Overhaul WMI interface interaction as suggested by Hans
>     * Move WMI driver registration to start of module
>     * Remove usage of lists that only use first entry for WMI interfaces
>     * Create a global structure shared across interface source files
>     * Make get_current_password function static
>     * Remove get_pending changes function, shared across global structure now.
> - Overhaul use of mutexes
>     * Make kset list mutex shared across source files
>     * Remove unneeded dell-wmi-sysman call_mutex
>     * Keep remaining call_mutexes in WMI functions
> - Move security area calculation into a function
> - Use NLS helper for utf8->utf16 conversion
> 
>   .../testing/sysfs-platform-dell-wmi-sysman    | 175 ++++++
>   MAINTAINERS                                   |   9 +
>   drivers/platform/x86/Kconfig                  |  12 +
>   drivers/platform/x86/Makefile                 |   8 +
>   .../x86/dell-wmi-biosattr-interface.c         | 197 ++++++
>   .../platform/x86/dell-wmi-enum-attributes.c   | 208 +++++++
>   .../platform/x86/dell-wmi-int-attributes.c    | 189 ++++++
>   .../x86/dell-wmi-passobj-attributes.c         | 165 +++++
>   .../x86/dell-wmi-passwordattr-interface.c     | 167 +++++
>   .../platform/x86/dell-wmi-string-attributes.c | 171 +++++
>   .../platform/x86/dell-wmi-sysman-attributes.c | 589 ++++++++++++++++++
>   .../platform/x86/dell-wmi-sysman-attributes.h | 137 ++++
>   12 files changed, 2027 insertions(+)
>   create mode 100644 Documentation/ABI/testing/sysfs-platform-dell-wmi-sysman
>   create mode 100644 drivers/platform/x86/dell-wmi-biosattr-interface.c
>   create mode 100644 drivers/platform/x86/dell-wmi-enum-attributes.c
>   create mode 100644 drivers/platform/x86/dell-wmi-int-attributes.c
>   create mode 100644 drivers/platform/x86/dell-wmi-passobj-attributes.c
>   create mode 100644 drivers/platform/x86/dell-wmi-passwordattr-interface.c
>   create mode 100644 drivers/platform/x86/dell-wmi-string-attributes.c
>   create mode 100644 drivers/platform/x86/dell-wmi-sysman-attributes.c
>   create mode 100644 drivers/platform/x86/dell-wmi-sysman-attributes.h
> 
> diff --git a/Documentation/ABI/testing/sysfs-platform-dell-wmi-sysman b/Documentation/ABI/testing/sysfs-platform-dell-wmi-sysman
> new file mode 100644
> index 000000000000..03398ac11121
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-platform-dell-wmi-sysman
> @@ -0,0 +1,175 @@
> +What:		/sys/devices/platform/dell-wmi-sysman/attributes/
> +Date:		December 2020
> +KernelVersion:	5.10
> +Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
> +		Mario Limonciello <mario.limonciello@dell.com>,
> +		Prasanth KSR <prasanth.ksr@dell.com>
> +Description:
> +		The Dell WMI Systems Management Driver provides a sysfs interface
> +		for systems management software to enable BIOS configuration
> +		capability on certain Dell systems. This directory exposes
> +		interfaces for interacting with BIOS attributes.
> +
> +		Attributes can accept a set of pre-defined valid values (enumeration)
> +		or a range of numerical values (integer) or a string.
> +
> +		current_value:	A file that can be read to obtain the current
> +		value of the <attr>
> +
> +		This file can also be written to in order to update
> +		the value of a <attr>
> +
> +		default_value:	A file that can be read to obtain the default
> +		value of the <attr>
> +
> +		display_name:	A file that can be read to obtain a user friendly
> +		description of the at <attr>
> +
> +		display_name_language_code:	A file that can be read to obtain
> +		the IETF language tag corresponding to the "display_name" of the <attr>
> +
> +		modifier:	A file that can be read to obtain attribute-level
> +		dependency rule. It says an attribute X will become read-only or
> +		suppressed, if/if-not attribute Y is configured.
> +
> +		modifier rules can be in following format,
> +		[ReadOnlyIf:<attribute>=<value>]
> +		[ReadOnlyIfNot:<attribute>=<value>]
> +		[SuppressIf:<attribute>=<value>]
> +		[SuppressIfNot:<attribute>=<value>]
> +
> +		For example,
> +		AutoOnFri/modifier has value,
> +			[SuppressIfNot:AutoOn=SelectDays]
> +		This means AutoOnFri will be supressed in BIOS setup if AutoOn
> +		attribute is not "SelectDays" and its value will not be effective
> +		through sysfs until this rule is met.

As discussed in the v1 thread, this is somewhat Dell specific and we make the
sysfs interface generic and move this to /sys/class/firmware-attributes/dell-wmi-sysman/
then this should probably be prefixed with dell- (and moved to a separate section
of this file for vendor extensions to the generic part)

> +
> +		"enumeration"-type specific properties:
> +
> +		possible_values:	A file that can be read to obtain the possible
> +		values of the <attr>. Values are separated using semi-colon.
> +
> +		value_modifier:	A file that can be read to obtain value-level
> +		dependency. This file is similar to modifier but here, an attribute's
> +		current value will be forcefully changed based dependent attributes
> +		value.
> +
> +		value_modifier rules can be in following format,
> +		<value>[ForceIf:<attribute>=<value>]
> +		<value>[ForceIfNot:<attribute>=<value>]
> +
> +		For example,
> +		LegacyOrom/value_modifier has value,
> +			Disabled[ForceIf:SecureBoot=Enabled]
> +		This means LegacyOrom's current value will be forced to "Disabled"
> +		in BIOS setup if SecureBoot is Enabled and its value will not be
> +		effective through sysfs until this rule is met.

Are value_modifiers only valid for enums? If not this should be moved to
the generic properties (or to the vendor extensions part)

> +
> +		"integer"-type specific properties:
> +
> +		min_value:	A file that can be read to obtain the lower
> +		bound value of the <attr>
> +
> +		max_value:	A file that can be read to obtain the upper
> +		bound value of the <attr>
> +
> +		scalar_increment:	A file that can be read to obtain the
> +		resolution of the incremental value this attribute accepts.
> +
> +		"string"-type specific properties:
> +
> +		max_length:	A file that can be read to obtain the maximum
> +		length value of the <attr>
> +
> +		min_length:	A file that can be read to obtain the minimum
> +		length value of the <attr>
> +
> +What:		/sys/devices/platform/dell-wmi-sysman/passwords/
> +Date:		December 2020
> +KernelVersion:	5.10
> +Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
> +		Mario Limonciello <mario.limonciello@dell.com>,
> +		Prasanth KSR <prasanth.ksr@dell.com>
> +
> +		A BIOS Admin password and System Password can be set, reset or
> +		cleared using these attributes. An "Admin" password is used for
> +		preventing modification to the BIOS settings. A "System" password is
> +		required to boot a machine.
> +
> +		is_password_set:	A file that can be read
> +		to obtain flag to see if a password is set on <attr>
> +
> +		max_password_length:	A file that can be read to obtain the
> +		maximum length of the Password
> +
> +		min_password_length:	A file that can be read to obtain the
> +		minimum length of the Password
> +
> +		current_password: A write only value used for privileged access
> +		such as setting attributes when a system or admin password is set
> +		or resetting to a new password
> +
> +		new_password: A write only value that when used in tandem with
> +		current_password will reset a system or admin password.
> +
> +		Note, password management is session specific. If Admin/System
> +		password is set, same password must be writen into current_password
> +		file (requied for pasword-validation) and must be cleared once the
> +		session	is over. For example,
> +			echo "password" > current_password
> +			echo "disabled" > TouchScreen/current_value
> +			echo "" > current_password

So I know this was mentioned before already but one concern I have here
is that there is a race where other users with write access to say TouchScreen/current_value
may change it between the setting and the clearing of the current_password even if
they don't have the password.

This is esp. relevant with containers. I'm not aware about all the intrinsics of
sysfs and containers, at a minimum we need to check if it is possible to disallow
all writes to the attributes when sysfs is mounted inside a container (so outside of the
main filesystem namespace).

If someone is reading along who happen to knows this, please enlighten me :)

> +
> +
> +What:		/sys/devices/platform/dell-wmi-sysman/attributes/reset_bios
> +Date:		December 2020
> +KernelVersion:	5.10
> +Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
> +		Mario Limonciello <mario.limonciello@dell.com>,
> +		Prasanth KSR <prasanth.ksr@dell.com>
> +Description:
> +		This attribute can be used to reset the BIOS Configuration.
> +		Specifically, it tells which type of reset BIOS configuration is being
> +		requested on the host.
> +
> +		Reading from it returns a list of supported options encoded as:
> +
> +			'builtinsafe' (Built in safe configuration profile)
> +			'lastknowngood' (Last known good saved configuration profile)
> +			'factory' (Default factory settings configuration profile)
> +			'custom' (Custom saved configuration profile)
> +
> +		The currently selected option is printed in square brackets as
> +		shown below:
> +
> +		# echo "factory" > sys/devices/platform/dell-wmi-sysman/attributes/reset_bios
> +
> +		# cat sys/devices/platform/dell-wmi-sysman/attributes/reset_bios
> +		# builtinsafe lastknowngood [factory] custom
> +
> +		Note that any changes to this attribute requires a reboot
> +		for changes to take effect.
> +
> +What:		/sys/devices/platform/dell-wmi-sysman/attributes/pending_reboot
> +Date:		December 2020
> +KernelVersion:	5.10
> +Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
> +		Mario Limonciello <mario.limonciello@dell.com>,
> +		Prasanth KSR <prasanth.ksr@dell.com>
> +Description:
> +		A read-only attribute reads 1 if a reboot is necessary to apply
> +		pending BIOS attribute changes.
> +
> +			0:	All BIOS attributes setting are current
> +			1:	A reboot is necessary to get pending BIOS attribute changes
> +				applied
> +
> +
> +		Note, userspace applications need to follow below steps for efficient
> +		BIOS management,
> +		1.	Check if admin password is set. If yes, follow session method for
> +			password management as briefed under password section above.
> +		2.	Before setting any attribute, check if it has any modifiers
> +			or value_modifiers. If yes, incorporate them and then modify
> +			attribute.

OK, so as also mentioned in the v1 thread, I would like to see the uevent disappear
since it is somewhat of a heavy mechanism and not necessary when userspace specifically
cares about a single sysfs attribute changing.

Instead we can allow userspace to use poll() for POLL_PRI on this file to be notified
when it goes from 0 -> 1. See the v1 thread for some example code how to wake the
poll() in this case.

Regards,

Hans


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v3] Introduce support for Systems Management Driver over WMI for Dell Systems
  2020-09-17  6:55 [PATCH v3] Introduce support for Systems Management Driver over WMI for Dell Systems Divya Bharathi
  2020-09-17 12:01 ` kernel test robot
  2020-09-21 10:57 ` Hans de Goede
@ 2020-09-21 11:38 ` Hans de Goede
  2020-09-21 12:08   ` Andy Shevchenko
  2 siblings, 1 reply; 8+ messages in thread
From: Hans de Goede @ 2020-09-21 11:38 UTC (permalink / raw)
  To: Divya Bharathi, dvhart
  Cc: LKML, platform-driver-x86, Divya Bharathi, Andy Shevchenko,
	mark gross, Mario Limonciello, Prasanth KSR

Hi,

Ok code review this time. Still mainly focussing on the overal
structure and not so much individual functions.

Note the code is starting to look good to me.

One general remark, now that we are keeping the 1 file per
type (int/enum/string) layout, there are quite a few files
in this driver. I think it would be good to create a
drivers/platform/x86/dell-wmi-sysman dir and put all the
files there, so that it is easier to e.g. grep for something
in all the files belonging to this driver.

On 9/17/20 8:55 AM, Divya Bharathi wrote:
> The Dell WMI Systems Management Driver provides a sysfs
> interface for systems management to enable BIOS configuration
> capability on certain Dell Systems.
> 
> This driver allows user to configure Dell systems with a
> uniform common interface. To facilitate this, the patch
> introduces a generic way for driver to be able to create
> configurable BIOS Attributes available in Setup (F2) screen.
> 
> Cc: Hans de Goede <hdegoede@redhat.com>
> Cc: Andy Shevchenko <andy.shevchenko@gmail.com>
> Cc: mark gross <mgross@linux.intel.com>
> 
> Co-developed-by: Mario Limonciello <mario.limonciello@dell.com>
> Signed-off-by: Mario Limonciello <mario.limonciello@dell.com>
> Co-developed-by: Prasanth KSR <prasanth.ksr@dell.com>
> Signed-off-by: Prasanth KSR <prasanth.ksr@dell.com>
> Signed-off-by: Divya Bharathi <divya_bharathi@dell.com>
> ---
> 
> Changes from v2 to v3:
>   - Fix a possible NULL pointer error in init
>   - Add missing newlines to all dev_err/dev_dbg/pr_err/pr_debug statements
>   - Correct updating passwords when both Admin and System password are set
>   - Correct the WMI driver name
>   - Correct some namespace clashing when compiled into the kernel (Reported by Mark Gross)
>   - Correct some comment typos
>   - Adopt suggestions made by Hans:
>     + Use single global mutex
>     + Clarify reason for uevents with a comment
>     + Remove functions for set and get current password
>     + Rename lower_bound to min_value and upper_bound to max_value
>     + Rename possible_value to possible_values
>     + Remove references to float
>     + Build a separate passwords directory again since it behaves differently from the other
>       attributes
>     + Move more calls from pr_err -> dev_err
>   - Documentation cleanups (see v2 patch feedback)
>     + Grouping types
>     + Syntax of `modifier` output
> 
> Changes from v1 to v2:
>   - use pr_fmt instead of pr_err(DRIVER_NAME
>   - re-order variables reverse xmas tree order
>   - correct returns of -1 to error codes
>   - correct usage of {} on some split line statements
>   - Refine all documentation deficiencies suggested by Hans
>   - Merge all attributes to a single directory
>   - Overhaul WMI interface interaction as suggested by Hans
>     * Move WMI driver registration to start of module
>     * Remove usage of lists that only use first entry for WMI interfaces
>     * Create a global structure shared across interface source files
>     * Make get_current_password function static
>     * Remove get_pending changes function, shared across global structure now.
> - Overhaul use of mutexes
>     * Make kset list mutex shared across source files
>     * Remove unneeded dell-wmi-sysman call_mutex
>     * Keep remaining call_mutexes in WMI functions
> - Move security area calculation into a function
> - Use NLS helper for utf8->utf16 conversion
> 
>   .../testing/sysfs-platform-dell-wmi-sysman    | 175 ++++++
>   MAINTAINERS                                   |   9 +
>   drivers/platform/x86/Kconfig                  |  12 +
>   drivers/platform/x86/Makefile                 |   8 +
>   .../x86/dell-wmi-biosattr-interface.c         | 197 ++++++
>   .../platform/x86/dell-wmi-enum-attributes.c   | 208 +++++++
>   .../platform/x86/dell-wmi-int-attributes.c    | 189 ++++++
>   .../x86/dell-wmi-passobj-attributes.c         | 165 +++++
>   .../x86/dell-wmi-passwordattr-interface.c     | 167 +++++
>   .../platform/x86/dell-wmi-string-attributes.c | 171 +++++
>   .../platform/x86/dell-wmi-sysman-attributes.c | 589 ++++++++++++++++++
>   .../platform/x86/dell-wmi-sysman-attributes.h | 137 ++++
>   12 files changed, 2027 insertions(+)
>   create mode 100644 Documentation/ABI/testing/sysfs-platform-dell-wmi-sysman
>   create mode 100644 drivers/platform/x86/dell-wmi-biosattr-interface.c
>   create mode 100644 drivers/platform/x86/dell-wmi-enum-attributes.c
>   create mode 100644 drivers/platform/x86/dell-wmi-int-attributes.c
>   create mode 100644 drivers/platform/x86/dell-wmi-passobj-attributes.c
>   create mode 100644 drivers/platform/x86/dell-wmi-passwordattr-interface.c
>   create mode 100644 drivers/platform/x86/dell-wmi-string-attributes.c
>   create mode 100644 drivers/platform/x86/dell-wmi-sysman-attributes.c
>   create mode 100644 drivers/platform/x86/dell-wmi-sysman-attributes.h

<snip>

> diff --git a/drivers/platform/x86/dell-wmi-enum-attributes.c b/drivers/platform/x86/dell-wmi-enum-attributes.c
> new file mode 100644
> index 000000000000..4598c4e27310
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-enum-attributes.c
> @@ -0,0 +1,208 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Functions corresponding to enumeration type attributes under BIOS Enumeration GUID for use
> + * with dell-wmi-sysman
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#include "dell-wmi-sysman-attributes.h"
> +
> +/* kept variable names same as in sysfs file name for sysfs_show macro definition */
> +struct enumeration_data {
> +	char display_name_language_code[MAX_BUFF];
> +	char attribute_name[MAX_BUFF];
> +	char display_name[MAX_BUFF];
> +	char default_value[MAX_BUFF];
> +	char current_value[MAX_BUFF];
> +	char modifier[MAX_BUFF];
> +	int value_modifier_count;
> +	char value_modifier[MAX_BUFF];
> +	int possible_values_count;
> +	char possible_values[MAX_BUFF];
> +	char type[MAX_BUFF];
> +};
> +
> +static struct enumeration_data *enumeration_data;
> +static int enumeration_instances_count;

Can we put these 2 static globals inside the wmi_priv
data structure?  It does not matter much but I find it a bit
cleaner to have all global state together in a single place.

> +get_instance_id(enumeration);

This macro will need to be adjusted a bit then, but I don't
see any problem there, just put wmi_priv. in front of the
type##_instances_count and type##_data[i].attribute_name.

> +
> +static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
> +{
> +	int instance_id;
> +
> +	if (!capable(CAP_SYS_ADMIN))
> +		return -EPERM;
> +	instance_id = get_enumeration_instance_id(kobj);
> +	if (instance_id >= 0) {
> +		union acpi_object *obj;
> +
> +		/* need to use specific instance_id and guid combination to get right data */
> +		obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
> +		if (!obj)
> +			return -AE_ERROR;
> +		strncpy_attr(enumeration_data[instance_id].current_value,
> +		       obj->package.elements[CURRENT_VAL].string.pointer);
> +		kfree(obj);
> +		return sprintf(buf, "%s\n", enumeration_data[instance_id].current_value);
> +	}
> +	return -EIO;
> +}
> +
> +/**
> + * validate_enumeration_input() - Validate input of current_value against possible values
> + * @instance_id: The instance on which input is validated
> + * @buf: Input value
> + **/
> +int validate_enumeration_input(int instance_id, const char *buf)
> +{
> +	char *options, *tmp, *p;
> +	int ret = -EINVAL;
> +
> +	options = tmp = kstrdup((enumeration_data[instance_id].possible_values), GFP_KERNEL);
> +	if (!options)
> +		return -ENOMEM;
> +
> +	while ((p = strsep(&options, ";")) != NULL) {
> +		if (!*p)
> +			continue;
> +		if (!strncasecmp(p, buf, strlen(p))) {
> +			ret = 0;
> +			break;
> +		}
> +	}
> +
> +	kfree(tmp);
> +	return ret;
> +}
> +
> +attribute_s_property_show(display_name_language_code, enumeration);
> +static struct kobj_attribute displ_langcode =
> +		__ATTR_RO(display_name_language_code);
> +
> +attribute_s_property_show(display_name, enumeration);
> +struct kobj_attribute displ_name =
> +		__ATTR_RO(display_name);
> +
> +attribute_s_property_show(default_value, enumeration);
> +struct kobj_attribute default_val =
> +		__ATTR_RO(default_value);
> +
> +attribute_property_store(current_value, enumeration);
> +struct kobj_attribute current_val =
> +		__ATTR_RW(current_value);
> +
> +attribute_s_property_show(modifier, enumeration);
> +struct kobj_attribute modifier =
> +		__ATTR_RO(modifier);
> +
> +attribute_s_property_show(value_modifier, enumeration);
> +struct kobj_attribute value_modfr =
> +		__ATTR_RO(value_modifier);
> +
> +attribute_s_property_show(possible_values, enumeration);
> +struct kobj_attribute poss_val =
> +		__ATTR_RO(possible_values);
> +
> +attribute_s_property_show(type, enumeration);
> +struct kobj_attribute type =
> +		__ATTR_RO(type);
> +
> +static struct attribute *enumeration_attrs[] = {
> +	&displ_langcode.attr,
> +	&displ_name.attr,
> +	&default_val.attr,
> +	&current_val.attr,
> +	&modifier.attr,
> +	&value_modfr.attr,
> +	&poss_val.attr,
> +	&type.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group enumeration_attr_group = {
> +	.attrs = enumeration_attrs,
> +};
> +
> +int alloc_enum_data(void)
> +{
> +	int ret = 0;
> +
> +	enumeration_instances_count = get_instance_count(DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
> +	enumeration_data = kzalloc((sizeof(struct enumeration_data) * enumeration_instances_count),
> +					GFP_KERNEL);

Please use kcalloc here, that will check that the
(sizeof(struct enumeration_data) * enumeration_instances_count multiplication does not
overflow. The same for all the other alloc_foo_data functions.

> +	if (!enumeration_data)
> +		ret = -ENOMEM;
> +	return ret;
> +}
> +
> +/**
> + * populate_enum_data() - Populate all properties of an instance under enumeration attribute
> + * @enumeration_obj: ACPI object with enumeration data
> + * @instance_id: The instance to enumerate
> + * @attr_name_kobj: The parent kernel object
> + **/
> +int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
> +			struct kobject *attr_name_kobj)
> +{
> +	int retval = sysfs_create_group(attr_name_kobj, &enumeration_attr_group);

This needs to be moved to the end of this function, as soon as you
call this, e.g. current_value_show() could be called, before the
enumeration_data[instance_id].current_value buffer has been filled.

The same goes for the other populate_foo() functions.

> +	int i, next_obj;
> +
> +	if (retval)
> +		goto out;
> +
> +	mutex_lock(&wmi_priv.mutex);

It would be better to push this lock (and the unlock) up into init_dell_bios_attrib_wmi()
this way we can ensure that none of the functions which take the lock can run
before we are completely done with initializing and registering all
the various sysfs attributes.

This lock/unlock can then also be removed from the other populate_foo()
functions.


> +	strncpy_attr(enumeration_data[instance_id].attribute_name,
> +		enumeration_obj[ATTR_NAME].string.pointer);
> +	strncpy_attr(enumeration_data[instance_id].display_name_language_code,
> +		enumeration_obj[DISPL_NAME_LANG_CODE].string.pointer);
> +	strncpy_attr(enumeration_data[instance_id].display_name,
> +		enumeration_obj[DISPLAY_NAME].string.pointer);
> +	strncpy_attr(enumeration_data[instance_id].default_value,
> +		enumeration_obj[DEFAULT_VAL].string.pointer);
> +	strncpy_attr(enumeration_data[instance_id].current_value,
> +		enumeration_obj[CURRENT_VAL].string.pointer);
> +	strncpy_attr(enumeration_data[instance_id].modifier,
> +		enumeration_obj[MODIFIER].string.pointer);
> +
> +	next_obj = MODIFIER + 1;
> +
> +	enumeration_data[instance_id].value_modifier_count =
> +		(uintptr_t)enumeration_obj[next_obj].string.pointer;
> +
> +	for (i = 0; i < enumeration_data[instance_id].value_modifier_count; i++) {
> +		strcat(enumeration_data[instance_id].value_modifier,
> +			enumeration_obj[++next_obj].string.pointer);
> +		strcat(enumeration_data[instance_id].value_modifier, ";");
> +	}
> +
> +	enumeration_data[instance_id].possible_values_count =
> +		(uintptr_t) enumeration_obj[++next_obj].string.pointer;
> +
> +	for (i = 0; i < enumeration_data[instance_id].possible_values_count; i++) {
> +		strcat(enumeration_data[instance_id].possible_values,
> +			enumeration_obj[++next_obj].string.pointer);
> +		strcat(enumeration_data[instance_id].possible_values, ";");
> +	}
> +	strncpy_attr(enumeration_data[instance_id].type, "enumeration");
> +	mutex_unlock(&wmi_priv.mutex);
> +
> +out:
> +	return retval;
> +}
> +
> +/**
> + * exit_enum_attributes() - Clear all attribute data
> + *
> + * Clears all data allocated for this group of attributes
> + **/
> +void exit_enum_attributes(void)
> +{
> +	struct kobject *pos, *next;
> +
> +	list_for_each_entry_safe(pos, next, &wmi_priv.main_dir_kset->list, entry) {
> +		/* this removes only enumeration atribute group under main_dir_kset */
> +		sysfs_remove_group(pos, &enumeration_attr_group);
> +	}
> +	kfree(enumeration_data);
> +}

As mentioned in the v2 thread I would prefer for this to be done differently
(for all exit_foo_attributes functions).

<snip>

> diff --git a/drivers/platform/x86/dell-wmi-passobj-attributes.c b/drivers/platform/x86/dell-wmi-passobj-attributes.c
> new file mode 100644
> index 000000000000..6884e6153dd6
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-passobj-attributes.c
> @@ -0,0 +1,165 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Functions corresponding to password object type attributes under BIOS Password Object GUID for
> + * use with dell-wmi-sysman
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#include "dell-wmi-sysman-attributes.h"
> +
> +enum po_properties {IS_PASS_SET = 1, MIN_PASS_LEN, MAX_PASS_LEN};
> +
> +/* kept variable names same as in sysfs file name for sysfs_show macro definition */
> +struct po_data {
> +	char attribute_name[MAX_BUFF];
> +	int is_password_set;
> +	int min_password_length;
> +	int max_password_length;
> +	char type[MAX_BUFF];
> +};
> +
> +static struct po_data *po_data;
> +static int po_instances_count;
> +get_instance_id(po);
> +
> +static ssize_t is_password_set_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
> +{
> +	int instance_id = get_po_instance_id(kobj);
> +
> +	if (instance_id >= 0) {
> +		union acpi_object *obj;
> +
> +		/* need to use specific instance_id and guid combination to get right data */
> +		obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
> +		if (!obj)
> +			return -AE_ERROR;
> +		po_data[instance_id].is_password_set =
> +			(uintptr_t)obj->package.elements[IS_PASS_SET].string.pointer;
> +		kfree(obj);
> +		return sprintf(buf, "%d\n", po_data[instance_id].is_password_set);
> +	}
> +	return -EIO;
> +}
> +
> +struct kobj_attribute po_is_pass_set =
> +		__ATTR_RO(is_password_set);
> +
> +static ssize_t current_password_store(struct kobject *kobj,
> +				      struct kobj_attribute *attr,
> +				      const char *buf, size_t count)
> +{
> +	char *p = memchr(buf, '\n', count);
> +	int ret;
> +
> +	if (p != NULL)
> +		*p = '\0';
> +	if (strlen(buf) > MAX_BUFF)
> +		return -EINVAL;

This check fails to take strlen(buf) == MAX_BUFF into account, in that
case the strncpy below:

> +
> +	if (strcmp(kobj->name, "Admin") == 0)
> +		strncpy(wmi_priv.current_admin_password, buf, (strlen(buf) + 1));

Will write MAX_BUFF + 1 bytes to wmi_priv.current_admin_password !

Looking at the string handling in this driver in general,
I am not really happy with it.

It seems that strncpy is used everywhere and strncpy is a horrible
function, which sreally should never be used. The reason for this
is that the source string having a length greater then the passed
in buffer-length will result in the destination buffer not being
0 terminated. Now sometimes that is a feature, but in that case
you should probably use memcpy to make it clear that you expect
the string to not be 0 terminated.

In other cases using strlcpy is better since it guarantees 0
termination (truncating the input to fit in the destination-buffer).

Now I see that you try to correctly deal with strncpy-s nastiness
everywhere, but please just don't use it all.
Not using strncpy at all is much better.

A lot of the strncpy usage is hidden in:

strncpy_attr(char *dest, char *src)
{
         size_t len = strlen(src) + 1;

         if (len > 1 && len < MAX_BUFF)
                 strncpy(dest, src, len);
}

Why is there no warning printed when the source string
is too long ? Now we just quietly throw away the
data, which seems undesirable.

Also wouldn't truncating the data to fit in MAX_BUFF be better?
(honest question, I do not know which option is better)


> +	if (strcmp(kobj->name, "System") == 0)
> +		strncpy(wmi_priv.current_system_password, buf, (strlen(buf) + 1));
> +	return ret ? ret : count;
> +}
> +
> +struct kobj_attribute po_current_password =
> +		__ATTR_WO(current_password);
> +
> +static ssize_t new_password_store(struct kobject *kobj,
> +				  struct kobj_attribute *attr,
> +				  const char *buf, size_t count)
> +{
> +	char *p = memchr(buf, '\n', count);
> +	int ret;
> +
> +	if (p != NULL)
> +		*p = '\0';
> +	if (strlen(buf) > MAX_BUFF)
> +		return -EINVAL;

Same issue with the length check.

> +
> +	ret = set_new_password(kobj->name, buf);
> +	return ret ? ret : count;
> +}
> +
> +struct kobj_attribute po_new_password =
> +		__ATTR_WO(new_password);
> +
> +attribute_n_property_show(min_password_length, po);
> +struct kobj_attribute po_min_pass_length =
> +		__ATTR_RO(min_password_length);
> +
> +attribute_n_property_show(max_password_length, po);
> +struct kobj_attribute po_max_pass_length =
> +		__ATTR_RO(max_password_length);
> +
> +attribute_s_property_show(type, po);
> +struct kobj_attribute po_type =
> +	__ATTR_RO(type);
> +
> +static struct attribute *po_attrs[] = {
> +	&po_is_pass_set.attr,
> +	&po_min_pass_length.attr,
> +	&po_max_pass_length.attr,
> +	&po_current_password.attr,
> +	&po_new_password.attr,
> +	&po_type.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group po_attr_group = {
> +	.attrs = po_attrs,
> +};
> +
> +int alloc_po_data(void)
> +{
> +	int ret = 0;
> +
> +	po_instances_count = get_instance_count(DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
> +	po_data = kzalloc((sizeof(struct po_data) * po_instances_count), GFP_KERNEL);
> +	if (!po_data)
> +		ret = -ENOMEM;
> +	return ret;
> +}
> +
> +/**
> + * populate_po_data() - Populate all properties of an instance under password object attribute
> + * @po_obj: ACPI object with password object data
> + * @instance_id: The instance to enumerate
> + * @attr_name_kobj: The parent kernel object
> + **/
> +int populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject *attr_name_kobj)
> +{
> +	int retval = sysfs_create_group(attr_name_kobj, &po_attr_group);
> +
> +	if (retval)
> +		goto out;
> +
> +	mutex_lock(&wmi_priv.mutex);
> +	strncpy_attr(po_data[instance_id].attribute_name, po_obj[ATTR_NAME].string.pointer);
> +	po_data[instance_id].is_password_set = (uintptr_t)po_obj[IS_PASS_SET].string.pointer;
> +	po_data[instance_id].min_password_length = (uintptr_t)po_obj[MIN_PASS_LEN].string.pointer;
> +	po_data[instance_id].max_password_length = (uintptr_t) po_obj[MAX_PASS_LEN].string.pointer;
> +	strncpy_attr(po_data[instance_id].type, "password_object");
> +	mutex_unlock(&wmi_priv.mutex);
> +
> +out:
> +	return retval;
> +}
> +
> +/**
> + * exit_po_attributes() - Clear all attribute data
> + *
> + * Clears all data allocated for this group of attributes
> + **/
> +void exit_po_attributes(void)
> +{
> +	struct kobject *pos, *next;
> +
> +	list_for_each_entry_safe(pos, next, &wmi_priv.password_dir_kset->list, entry) {
> +		/* this removes only enumeration atribute group under main_dir_kset */
> +		sysfs_remove_group(pos, &po_attr_group);
> +	}
> +	kfree(po_data);
> +}
> diff --git a/drivers/platform/x86/dell-wmi-passwordattr-interface.c b/drivers/platform/x86/dell-wmi-passwordattr-interface.c
> new file mode 100644
> index 000000000000..bd19d6c15002
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-passwordattr-interface.c
> @@ -0,0 +1,167 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Functions corresponding to SET password methods under BIOS attributes interface GUID
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#include <linux/nls.h>
> +#include <linux/wmi.h>
> +#include "dell-wmi-sysman-attributes.h"
> +
> +static int call_password_interface(struct wmi_device *wdev, char *in_args, size_t size)
> +{
> +	struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
> +	struct acpi_buffer input;
> +	union acpi_object *obj;
> +	acpi_status status;
> +	int ret = -EIO;
> +
> +	input.length =  (acpi_size) size;
> +	input.pointer = in_args;
> +	status = wmidev_evaluate_method(wdev, 0, 1, &input, &output);
> +	if (ACPI_FAILURE(status))
> +		return -EIO;
> +	obj = (union acpi_object *)output.pointer;
> +	if (obj->type == ACPI_TYPE_INTEGER)
> +		ret = obj->integer.value;
> +
> +	kfree(output.pointer);
> +	/* let userland know it may need to check is_password_set again */
> +	kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE);

Hmm, I see so there is more then one boolean for user-space to monitor.

I guess that in that case udev change events might make sense.  That would
also be easier to describe in the sysfs API, we can just say that if anything
changes a udev change event is send.

Note you should still make sure to only do the other kobject_uevent() call
on the first change of pending_changes from 0 -> 1, after that it does not
change, so there is no need to spam userspace with more uevents.

Regards,

Hans


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v3] Introduce support for Systems Management Driver over WMI for Dell Systems
  2020-09-21 11:38 ` Hans de Goede
@ 2020-09-21 12:08   ` Andy Shevchenko
  2020-09-21 12:08     ` Andy Shevchenko
  0 siblings, 1 reply; 8+ messages in thread
From: Andy Shevchenko @ 2020-09-21 12:08 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Divya Bharathi, Darren Hart, LKML, Platform Driver,
	Divya Bharathi, mark gross, Mario Limonciello, Prasanth KSR

On Mon, Sep 21, 2020 at 2:38 PM Hans de Goede <hdegoede@redhat.com> wrote:
> On 9/17/20 8:55 AM, Divya Bharathi wrote:

...

> Now I see that you try to correctly deal with strncpy-s nastiness
> everywhere, but please just don't use it all.
> Not using strncpy at all is much better.
>
> A lot of the strncpy usage is hidden in:
>
> strncpy_attr(char *dest, char *src)
> {
>          size_t len = strlen(src) + 1;
>
>          if (len > 1 && len < MAX_BUFF)
>                  strncpy(dest, src, len);
> }
>
> Why is there no warning printed when the source string
> is too long ? Now we just quietly throw away the
> data, which seems undesirable.
>
> Also wouldn't truncating the data to fit in MAX_BUFF be better?
> (honest question, I do not know which option is better)

And don't forget new compiler warning if it can prove that string will
be NUL-terminated.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v3] Introduce support for Systems Management Driver over WMI for Dell Systems
  2020-09-21 12:08   ` Andy Shevchenko
@ 2020-09-21 12:08     ` Andy Shevchenko
  0 siblings, 0 replies; 8+ messages in thread
From: Andy Shevchenko @ 2020-09-21 12:08 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Divya Bharathi, Darren Hart, LKML, Platform Driver,
	Divya Bharathi, mark gross, Mario Limonciello, Prasanth KSR

On Mon, Sep 21, 2020 at 3:08 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> On Mon, Sep 21, 2020 at 2:38 PM Hans de Goede <hdegoede@redhat.com> wrote:
> > On 9/17/20 8:55 AM, Divya Bharathi wrote:
>
> ...
>
> > Now I see that you try to correctly deal with strncpy-s nastiness
> > everywhere, but please just don't use it all.
> > Not using strncpy at all is much better.
> >
> > A lot of the strncpy usage is hidden in:
> >
> > strncpy_attr(char *dest, char *src)
> > {
> >          size_t len = strlen(src) + 1;
> >
> >          if (len > 1 && len < MAX_BUFF)
> >                  strncpy(dest, src, len);
> > }
> >
> > Why is there no warning printed when the source string
> > is too long ? Now we just quietly throw away the
> > data, which seems undesirable.
> >
> > Also wouldn't truncating the data to fit in MAX_BUFF be better?
> > (honest question, I do not know which option is better)
>
> And don't forget new compiler warning if it can prove that string will
> be NUL-terminated.

can -> can't


-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: [PATCH v3] Introduce support for Systems Management Driver over WMI for Dell Systems
  2020-09-21 10:57 ` Hans de Goede
@ 2020-09-21 18:23   ` Limonciello, Mario
  2020-09-23 10:19     ` Hans de Goede
  0 siblings, 1 reply; 8+ messages in thread
From: Limonciello, Mario @ 2020-09-21 18:23 UTC (permalink / raw)
  To: Hans de Goede, Divya Bharathi, dvhart
  Cc: LKML, platform-driver-x86, Bharathi, Divya, Andy Shevchenko,
	mark gross, Ksr, Prasanth

> 
> > +
> > +		"integer"-type specific properties:
> > +
> > +		min_value:	A file that can be read to obtain the lower
> > +		bound value of the <attr>
> > +
> > +		max_value:	A file that can be read to obtain the upper
> > +		bound value of the <attr>
> > +
> > +		scalar_increment:	A file that can be read to obtain the
> > +		resolution of the incremental value this attribute accepts.
> > +
> > +		"string"-type specific properties:
> > +
> > +		max_length:	A file that can be read to obtain the maximum
> > +		length value of the <attr>
> > +
> > +		min_length:	A file that can be read to obtain the minimum
> > +		length value of the <attr>
> > +
> > +What:		/sys/devices/platform/dell-wmi-sysman/passwords/
> > +Date:		December 2020
> > +KernelVersion:	5.10
> > +Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
> > +		Mario Limonciello <mario.limonciello@dell.com>,
> > +		Prasanth KSR <prasanth.ksr@dell.com>
> > +
> > +		A BIOS Admin password and System Password can be set, reset or
> > +		cleared using these attributes. An "Admin" password is used for
> > +		preventing modification to the BIOS settings. A "System" password
> is
> > +		required to boot a machine.
> > +
> > +		is_password_set:	A file that can be read
> > +		to obtain flag to see if a password is set on <attr>
> > +
> > +		max_password_length:	A file that can be read to obtain the
> > +		maximum length of the Password
> > +
> > +		min_password_length:	A file that can be read to obtain the
> > +		minimum length of the Password
> > +
> > +		current_password: A write only value used for privileged access
> > +		such as setting attributes when a system or admin password is set
> > +		or resetting to a new password
> > +
> > +		new_password: A write only value that when used in tandem with
> > +		current_password will reset a system or admin password.
> > +
> > +		Note, password management is session specific. If Admin/System
> > +		password is set, same password must be writen into current_password
> > +		file (requied for pasword-validation) and must be cleared once the
> > +		session	is over. For example,
> > +			echo "password" > current_password
> > +			echo "disabled" > TouchScreen/current_value
> > +			echo "" > current_password
> 
> So I know this was mentioned before already but one concern I have here
> is that there is a race where other users with write access to say
> TouchScreen/current_value
> may change it between the setting and the clearing of the current_password
> even if
> they don't have the password.

I don't think there is much that can be done here other than move to something atomic
like sending the password as part of the request.

echo "foobar123|enabled" | sudo tee /sys/devices/platform/dell-wmi-sysman/

That isn't really pretty - and worse you can no longer have a process fetching
authentication from escrow that is different from your "setter" process.

> 
> This is esp. relevant with containers. I'm not aware about all the intrinsics
> of
> sysfs and containers, at a minimum we need to check if it is possible to
> disallow
> all writes to the attributes when sysfs is mounted inside a container (so
> outside of the
> main filesystem namespace).

Containers by default mount sysfs as read only unless you use the '--privileged'
flag.

https://www.redhat.com/sysadmin/privileged-flag-container-engines

> 
> If someone is reading along who happen to knows this, please enlighten me :)
> 
> > +
> > +
> > +What:		/sys/devices/platform/dell-wmi-sysman/attributes/reset_bios
> > +Date:		December 2020
> > +KernelVersion:	5.10
> > +Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
> > +		Mario Limonciello <mario.limonciello@dell.com>,
> > +		Prasanth KSR <prasanth.ksr@dell.com>
> > +Description:
> > +		This attribute can be used to reset the BIOS Configuration.
> > +		Specifically, it tells which type of reset BIOS configuration is
> being
> > +		requested on the host.
> > +
> > +		Reading from it returns a list of supported options encoded as:
> > +
> > +			'builtinsafe' (Built in safe configuration profile)
> > +			'lastknowngood' (Last known good saved configuration profile)
> > +			'factory' (Default factory settings configuration profile)
> > +			'custom' (Custom saved configuration profile)
> > +
> > +		The currently selected option is printed in square brackets as
> > +		shown below:
> > +
> > +		# echo "factory" > sys/devices/platform/dell-wmi-
> sysman/attributes/reset_bios
> > +
> > +		# cat sys/devices/platform/dell-wmi-sysman/attributes/reset_bios
> > +		# builtinsafe lastknowngood [factory] custom
> > +
> > +		Note that any changes to this attribute requires a reboot
> > +		for changes to take effect.
> > +
> > +What:		/sys/devices/platform/dell-wmi-
> sysman/attributes/pending_reboot
> > +Date:		December 2020
> > +KernelVersion:	5.10
> > +Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
> > +		Mario Limonciello <mario.limonciello@dell.com>,
> > +		Prasanth KSR <prasanth.ksr@dell.com>
> > +Description:
> > +		A read-only attribute reads 1 if a reboot is necessary to apply
> > +		pending BIOS attribute changes.
> > +
> > +			0:	All BIOS attributes setting are current
> > +			1:	A reboot is necessary to get pending BIOS attribute
> changes
> > +				applied
> > +
> > +
> > +		Note, userspace applications need to follow below steps for
> efficient
> > +		BIOS management,
> > +		1.	Check if admin password is set. If yes, follow session method
> for
> > +			password management as briefed under password section above.
> > +		2.	Before setting any attribute, check if it has any modifiers
> > +			or value_modifiers. If yes, incorporate them and then modify
> > +			attribute.
> 
> OK, so as also mentioned in the v1 thread, I would like to see the uevent
> disappear
> since it is somewhat of a heavy mechanism and not necessary when userspace
> specifically
> cares about a single sysfs attribute changing.
> 
> Instead we can allow userspace to use poll() for POLL_PRI on this file to be
> notified
> when it goes from 0 -> 1. See the v1 thread for some example code how to wake
> the
> poll() in this case.
> 
> Regards,
> 
> Hans


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v3] Introduce support for Systems Management Driver over WMI for Dell Systems
  2020-09-21 18:23   ` Limonciello, Mario
@ 2020-09-23 10:19     ` Hans de Goede
  0 siblings, 0 replies; 8+ messages in thread
From: Hans de Goede @ 2020-09-23 10:19 UTC (permalink / raw)
  To: Limonciello, Mario, Divya Bharathi, dvhart
  Cc: LKML, platform-driver-x86, Bharathi, Divya, Andy Shevchenko,
	mark gross, Ksr, Prasanth

Hi,

On 9/21/20 8:23 PM, Limonciello, Mario wrote:
>>
>>> +
>>> +		"integer"-type specific properties:
>>> +
>>> +		min_value:	A file that can be read to obtain the lower
>>> +		bound value of the <attr>
>>> +
>>> +		max_value:	A file that can be read to obtain the upper
>>> +		bound value of the <attr>
>>> +
>>> +		scalar_increment:	A file that can be read to obtain the
>>> +		resolution of the incremental value this attribute accepts.
>>> +
>>> +		"string"-type specific properties:
>>> +
>>> +		max_length:	A file that can be read to obtain the maximum
>>> +		length value of the <attr>
>>> +
>>> +		min_length:	A file that can be read to obtain the minimum
>>> +		length value of the <attr>
>>> +
>>> +What:		/sys/devices/platform/dell-wmi-sysman/passwords/
>>> +Date:		December 2020
>>> +KernelVersion:	5.10
>>> +Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
>>> +		Mario Limonciello <mario.limonciello@dell.com>,
>>> +		Prasanth KSR <prasanth.ksr@dell.com>
>>> +
>>> +		A BIOS Admin password and System Password can be set, reset or
>>> +		cleared using these attributes. An "Admin" password is used for
>>> +		preventing modification to the BIOS settings. A "System" password
>> is
>>> +		required to boot a machine.
>>> +
>>> +		is_password_set:	A file that can be read
>>> +		to obtain flag to see if a password is set on <attr>
>>> +
>>> +		max_password_length:	A file that can be read to obtain the
>>> +		maximum length of the Password
>>> +
>>> +		min_password_length:	A file that can be read to obtain the
>>> +		minimum length of the Password
>>> +
>>> +		current_password: A write only value used for privileged access
>>> +		such as setting attributes when a system or admin password is set
>>> +		or resetting to a new password
>>> +
>>> +		new_password: A write only value that when used in tandem with
>>> +		current_password will reset a system or admin password.
>>> +
>>> +		Note, password management is session specific. If Admin/System
>>> +		password is set, same password must be writen into current_password
>>> +		file (requied for pasword-validation) and must be cleared once the
>>> +		session	is over. For example,
>>> +			echo "password" > current_password
>>> +			echo "disabled" > TouchScreen/current_value
>>> +			echo "" > current_password
>>
>> So I know this was mentioned before already but one concern I have here
>> is that there is a race where other users with write access to say
>> TouchScreen/current_value
>> may change it between the setting and the clearing of the current_password
>> even if
>> they don't have the password.
> 
> I don't think there is much that can be done here other than move to something atomic
> like sending the password as part of the request.

Right, I'm not saying this scheme is bad per se I just wanted to make
sure that this was brought up and discussed.

> echo "foobar123|enabled" | sudo tee /sys/devices/platform/dell-wmi-sysman/
> 
> That isn't really pretty - and worse you can no longer have a process fetching
> authentication from escrow that is different from your "setter" process.

Note you will likely need some form of IPC, say dbus to your escrow process
anyways to ask it to unlock. So you could just change the "unlock" request
to a "set Camera=Enabled" request and have the process which has access
to the authentication token make the changes itself.

>> This is esp. relevant with containers. I'm not aware about all the intrinsics
>> of
>> sysfs and containers, at a minimum we need to check if it is possible to
>> disallow
>> all writes to the attributes when sysfs is mounted inside a container (so
>> outside of the
>> main filesystem namespace).
> 
> Containers by default mount sysfs as read only unless you use the '--privileged'
> flag.
> 
> https://www.redhat.com/sysadmin/privileged-flag-container-engines

Thanks that is good to know and does address most of my concerns. What I was
wondering about is if we can enforce this in the kernel even for --privileged
containers.  I guess another question would be if we can do that, should we?

Regards,

Hans


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2020-09-23 10:19 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-17  6:55 [PATCH v3] Introduce support for Systems Management Driver over WMI for Dell Systems Divya Bharathi
2020-09-17 12:01 ` kernel test robot
2020-09-21 10:57 ` Hans de Goede
2020-09-21 18:23   ` Limonciello, Mario
2020-09-23 10:19     ` Hans de Goede
2020-09-21 11:38 ` Hans de Goede
2020-09-21 12:08   ` Andy Shevchenko
2020-09-21 12:08     ` Andy Shevchenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).